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

675 lines
20 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#ifndef __PLATFORM_IOS__
#include <malloc.h>
#endif
#include "gpu/gpu_renderer.h"
#include "core/renderer_environment_interface.h"
#include "core/light.h"
#include "core/camera.h"
#include "core/object.h"
#include "core/shader.h"
#include "container/narray.h"
#include "platform_config.h"
#include "platform.h"
#include "log/file_log.h"
#include "log/log.h"
using namespace GS;
using namespace GS::GPU;
//------------------------------------------------------------------------------
void Shader::SetVertexStreamInputs(DisplayList &dls)
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryVertexStream].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryVertexStream][n];
switch (input->semantic)
{
case Core::ShaderInput::Position:
Set(*input->location, 3, Types::ValueHalfFloat, false, dls.stride, (const void *)dls.vertex_offset);
break;
case Core::ShaderInput::Normal:
Set(*input->location, 3, Types::ValueByte, true, dls.stride, (const void *)dls.normal_offset);
break;
case Core::ShaderInput::VertexColor:
Set(*input->location, 4, Types::ValueUByte, true, dls.stride, (const void *)dls.rgb_offset);
break;
case Core::ShaderInput::Tangent:
Set(*input->location, 3, Types::ValueByte, true, dls.stride, (const void *)dls.tangent_offset);
break;
case Core::ShaderInput::Bitangent:
Set(*input->location, 3, Types::ValueByte, true, dls.stride, (const void *)(dls.tangent_offset + 4 * sizeof(char)));
break;
case Core::ShaderInput::BoneIndex:
Set(*input->location, 4, Types::ValueUByte, false, dls.stride, (const void *)dls.skinning_offset);
break;
case Core::ShaderInput::BoneWeight:
Set(*input->location, 4, Types::ValueUByte, true, dls.stride, (const void *)(dls.skinning_offset + 4 * sizeof(char)));
break;
case Core::ShaderInput::UV0:
case Core::ShaderInput::UV1:
case Core::ShaderInput::UV2:
{
int uv_index = (int)input->semantic - (int)Core::ShaderInput::UV0;
Set(*input->location, 2, Types::ValueHalfFloat, false, dls.stride, (const void *)dls.uv_offset[uv_index]);
}
break;
}
}
}
void Shader::SetSkinInputs(DisplayList &dls, Core::Skin &skin)
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategorySkin].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategorySkin][n];
switch (input->semantic)
{
case Core::ShaderInput::BoneMatrix:
if (float *m = (float *)alloca(4 * 4 * sizeof(float) * dls.bone.GetCount()))
{
float *p_m = m;
for (uint n = 0; n < dls.bone.GetCount(); ++n)
{
Memory::Copy(p_m, skin.bones_mtx[dls.bone[n]].m, 4 * 4 * sizeof(float));
p_m += 4 * 4;
}
Set(*input->location, (Matrix4 *)m, dls.bone.GetCount());
}
break;
case Core::ShaderInput::PreviousBoneMatrix:
if (float *m = (float *)alloca(4 * 4 * sizeof(float) * dls.bone.GetCount()))
{
float *p_m = m;
for (uint n = 0; n < dls.bone.GetCount(); ++n)
{
Memory::Copy(p_m, skin.previous_bones_mtx[dls.bone[n]].m, 4 * 4 * sizeof(float));
p_m += 4 * 4;
}
Set(*input->location, (Matrix4 *)m, dls.bone.GetCount());
}
break;
}
}
}
void Shader::SetConstantInputs()
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryConstant].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryConstant][n];
switch (input->semantic)
{
case Core::ShaderInput::Constant:
switch (input->data_type)
{
default:
case Core::ShaderInput::Matrix3:
case Core::ShaderInput::Matrix4:
break;
case Core::ShaderInput::DataTexture2D:
case Core::ShaderInput::DataTexture3D:
case Core::ShaderInput::DataTextureCube:
Set(*input->location, *input->parm_t, input->index);
break;
case Core::ShaderInput::Int:
Set(*input->location, (int *)&input->parm_v.x);
break;
case Core::ShaderInput::Float:
Set(*input->location, &input->parm_v.x);
break;
case Core::ShaderInput::Vector2:
Set(*input->location, &input->parm_v.x, 2);
break;
case Core::ShaderInput::Vector3:
Set(*input->location, &input->parm_v.x, 3);
break;
case Core::ShaderInput::Vector4:
Set(*input->location, &input->parm_v.x, 4);
break;
}
break;
}
}
}
void Shader::SetTextureInputs()
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryTexture].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryTexture][n];
switch (input->semantic)
{
case Core::ShaderInput::Texture2D:
case Core::ShaderInput::Texture3D:
case Core::ShaderInput::TextureCube:
if (input->parm_t)
Set(*input->location, *input->parm_t, input->index);
break;
}
}
}
void Shader::SetRendererInputs(Renderer &r, Material *m)
{
Color fog_color;
float fog_near = 0, fog_far = 0;
bool fog_enabled = r.environment_interface ? r.environment_interface->GetFogConfiguration(fog_color, fog_near, fog_far) : false;
if (r.performance_tools.disable_fog)
fog_enabled = false;
if (m && (m->blendop == Core::Material::Blend_Add))
fog_enabled = false;
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryRenderer].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryRenderer][n];
switch (input->semantic)
{
case Core::ShaderInput::Clock:
Set(*input->location, r.frame_clock);
break;
case Core::ShaderInput::TimeOfDay:
Set(*input->location, r.environment_interface->GetTimeOfDay());
break;
case Core::ShaderInput::ViewVector:
{
Vector4 tmp = r.GetCamera()->GetMatrix().GetRow(2);
Set(*input->location, &tmp.x, 3);
}
break;
case Core::ShaderInput::ViewPosition:
{
Vector4 tmp = r.GetCamera()->GetMatrix().GetRow(3);
Set(*input->location, &tmp.x, 4);
}
break;
case Core::ShaderInput::Viewport:
{
const fRect viewport = r.GetViewport();
float v[4] = { viewport.sx, viewport.sy, viewport.GetWidth(), viewport.GetHeight() };
Set(*input->location, v, 4);
}
break;
case Core::ShaderInput::ZNear:
Set(*input->location, r.GetCamera()->GetNearClippingPlane());
break;
case Core::ShaderInput::ZFar:
Set(*input->location, r.GetCamera()->GetFarClippingPlane());
break;
case Core::ShaderInput::ZoomFactor:
Set(*input->location, r.GetCamera()->zoom_factor);
break;
case Core::ShaderInput::DisplayBufferRatio:
{
float v[] = { r.GetOutputAspectRatio(), 1.f };
Set(*input->location, v, 2);
}
break;
case Core::ShaderInput::ViewportRatio:
{
float v[] = { r.GetViewport().GetHeight() / r.GetViewport().GetWidth(), 1.f };
Set(*input->location, v, 2);
}
break;
case Core::ShaderInput::FxScale:
Set(*input->location, float(r.fx_scale));
break;
case Core::ShaderInput::InverseBufferSize:
{
tVector2 <uint> d = r.GetOutputDimensions();
float v[] = { 1.f / d.x, 1.f / d.y };
Set(*input->location, v, 2);
}
break;
case Core::ShaderInput::InverseViewportSize:
{
float v[] = { 1.f / r.GetViewport().GetWidth(), 1.f / r.GetViewport().GetHeight() };
Set(*input->location, v, 2);
}
break;
case Core::ShaderInput::ViewDepthOffset:
{
float k = 0.f;
Set(*input->location, &k);
}
break;
case Core::ShaderInput::AmbientColor:
{
Color ambient = r.environment_interface->GetAmbientColor();
Set(*input->location, &ambient.x, 3);
}
break;
case Core::ShaderInput::FogColor:
Set(*input->location, &fog_color.x, 3);
break;
case Core::ShaderInput::FogNear:
Set(*input->location, fog_near);
break;
case Core::ShaderInput::FogFar:
Set(*input->location, fog_far);
break;
case Core::ShaderInput::FogInverseRange:
{
bool use_fog = fog_enabled && (fog_far > 0.0);
if (m && (m->renderword & Core::Material::Render_NoFog))
use_fog = false;
Set(*input->location, use_fog ? 1.f / (fog_far - fog_near) : -1.f);
}
break;
case Core::ShaderInput::DepthBuffer:
if (r.render_technique == Renderer::TechniqueDeferred)
Set(*input->location, *r.t_gbuffer[0], input->index);
else Set(*input->location, *r.t_depth, input->index);
break;
case Core::ShaderInput::FrameBuffer:
if (r.t_fx[0].IsValid())
Set(*input->location, *r.t_fx[0], input->index);
break;
case Core::ShaderInput::GBuffer0:
case Core::ShaderInput::GBuffer1:
case Core::ShaderInput::GBuffer2:
case Core::ShaderInput::GBuffer3:
Set(*input->location, *r.t_gbuffer[input->semantic - Core::ShaderInput::GBuffer0], input->index);
break;
case Core::ShaderInput::NoiseMap:
if (r.t_noise.IsValid())
Set(*input->location, *r.t_noise, input->index);
break;
}
}
}
void Shader::SetTransformInputs(const Matrix4 &v_pm, const Matrix4 &v_m, const Matrix4 &v_im, const Matrix4 *i_m, const Matrix4 *i_im, uint count)
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryTransform].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryTransform][n];
switch (input->semantic)
{
case Core::ShaderInput::NormalMatrix:
if (Matrix3 *n_m = (Matrix3 *)alloca(sizeof(Matrix3) * count))
{
for (uint n = 0; n < count; ++n)
n_m[n] = Matrix3::FromMatrix4(i_m[n]).Normalized();
Set(*input->location, n_m, count);
}
break;
case Core::ShaderInput::NormalViewMatrix:
if (Matrix3 *nv_m = (Matrix3 *)alloca(sizeof(Matrix3) * count))
{
Matrix3 vn_m = Matrix3::FromMatrix4(v_m).Normalized().Transposed();
for (uint n = 0; n < count; ++n)
nv_m[n] = vn_m * Matrix3::FromMatrix4(i_m[n]).Normalized();
Set(*input->location, nv_m, count);
}
break;
case Core::ShaderInput::ModelMatrix:
Set(*input->location, i_m, count);
break;
case Core::ShaderInput::ViewMatrix:
Set(*input->location, v_im);
break;
case Core::ShaderInput::ProjectionMatrix:
Set(*input->location, v_pm);
break;
case Core::ShaderInput::ModelViewMatrix:
if (Matrix4 *mv_m = (Matrix4 *)alloca(sizeof(Matrix4) * count))
{
for (uint n = 0; n < count; ++n)
mv_m[n] = v_im * i_m[n];
Set(*input->location, mv_m, count);
}
break;
case Core::ShaderInput::ModelViewProjectionMatrix:
if (Matrix4 *mvp_m = (Matrix4 *)alloca(sizeof(Matrix4) * count))
{
for (uint n = 0; n < count; ++n)
mvp_m[n] = v_pm * (v_im * i_m[n]);
Set(*input->location, mvp_m, count);
}
break;
case Core::ShaderInput::InverseViewProjectionMatrix:
{
Matrix4 vpm = v_pm * v_im, ivpm;
vpm.Inverse(ivpm);
Set(*input->location, ivpm);
}
break;
case Core::ShaderInput::InverseViewProjectionMatrixAtOrigin:
{
Matrix4 v_im_o = v_im;
v_im_o.SetRow(3, Vector4(0, 0, 0, 1));
Matrix4 vpm = v_pm * v_im_o, ivpm;
vpm.Inverse(ivpm);
Set(*input->location, ivpm);
}
break;
}
}
}
void Shader::SetPreviousTransformInputs(const Matrix4 &v_pm, const Matrix4 &v_im, const Matrix4 *i_m, uint count)
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryPreviousTransform].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryPreviousTransform][n];
switch (input->semantic)
{
case Core::ShaderInput::PreviousModelViewMatrix:
if (Matrix4 *mv_m = (Matrix4 *)alloca(sizeof(Matrix4) * count))
{
for (uint n = 0; n < count; ++n)
mv_m[n] = v_im * i_m[n];
Set(*input->location, mv_m, count);
}
break;
case Core::ShaderInput::PreviousModelViewProjectionMatrix:
if (Matrix4 *mvp_m = (Matrix4 *)alloca(sizeof(Matrix4) * count))
{
for (uint n = 0; n < count; ++n)
mvp_m[n] = v_pm * (v_im * i_m[n]);
Set(*input->location, mvp_m, count);
}
break;
}
}
}
void Shader::SetMaterialOpacityInputs(Material &m, float opacity)
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryMaterialOpacity].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryMaterialOpacity][n];
switch (input->semantic)
{
case Core::ShaderInput::MaterialOpacity:
Set(*input->location, m.opacity * opacity);
break;
}
}
}
void Shader::SetMaterialInputs(Material &m)
{
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryMaterial].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryMaterial][n];
switch (input->semantic)
{
case Core::ShaderInput::MaterialDiffuse:
Set(*input->location, &m.diffuse.x, 4);
break;
case Core::ShaderInput::MaterialSpecular:
Set(*input->location, &m.specular.x, 4);
break;
case Core::ShaderInput::MaterialAmbient:
Set(*input->location, &m.ambient.x, 4);
break;
case Core::ShaderInput::MaterialSelf:
Set(*input->location, &m.self.x, 4);
break;
case Core::ShaderInput::MaterialGlossiness:
Set(*input->location, m.glossiness);
break;
case Core::ShaderInput::MaterialReflection:
Set(*input->location, m.reflection);
break;
case Core::ShaderInput::MaterialAlphaThreshold:
Set(*input->location, m.athreshold);
break;
case Core::ShaderInput::MaterialDepthBias:
Set(*input->location, m.depth_bias);
break;
case Core::ShaderInput::MaterialTexture0:
case Core::ShaderInput::MaterialTexture1:
case Core::ShaderInput::MaterialTexture2:
case Core::ShaderInput::MaterialTexture3:
case Core::ShaderInput::MaterialTexture4:
case Core::ShaderInput::MaterialTexture5:
case Core::ShaderInput::MaterialTexture6:
case Core::ShaderInput::MaterialTexture7:
if (Render::Texture *t = m.texture_table[input->semantic - Core::ShaderInput::MaterialTexture0])
Set(*input->location, *t, input->index);
break;
}
}
}
void Shader::SetLightInputs(Renderer &r, Core::Camera &view_item, Core::Light &l)
{
float k_clip_fade = 1.f;
if (l.range > 0.f) // [EJ] fade on last 10% of clip range
{
float c = l.clip_distance + l.range;
float d = Vector4::Dist(view_item.GetMatrix().GetRow(3), l.GetMatrix().GetRow(3));
k_clip_fade = 1.f - GS::Types::Clamp((d - c * 0.9f) / (c * 0.1f));
}
if (Core::Light::RenderData *light_render_data = (Core::Light::RenderData *)l.render_data.c_ptr())
for (uint n = 0; n < input_list[Core::ShaderInput::CategoryLight].GetCount(); ++n)
{
ShaderInput *input = &input_list[Core::ShaderInput::CategoryLight][n];
switch (input->semantic)
{
case Core::ShaderInput::LightRange:
Set(*input->location, l.range);
break;
case Core::ShaderInput::LightSpotEdge:
Set(*input->location, Math::Cos(l.edge_angle + l.cone_angle));
break;
case Core::ShaderInput::LightSpotCone:
Set(*input->location, Math::Cos(l.cone_angle));
break;
case Core::ShaderInput::LightShadowBias:
Set(*input->location, l.shadow_bias);
break;
case Core::ShaderInput::LightDiffuseColor:
{
Color c = l.diffuse_color * l.diffuse_intensity * k_clip_fade;
Set(*input->location, &c.x, 3);
}
break;
case Core::ShaderInput::LightSpecularColor:
{
Color c = l.specular_color * l.specular_intensity * k_clip_fade;
Set(*input->location, &c.x, 3);
}
break;
case Core::ShaderInput::LightShadowColor:
Set(*input->location, &l.shadow_color.x, 3);
break;
case Core::ShaderInput::LightViewPosition:
{
Vector4 p = l.GetMatrix().GetRow(3) * view_item.GetInverseMatrix();
Set(*input->location, &p.x, 3);
}
break;
case Core::ShaderInput::LightViewDirection:
{
Vector4 d = l.GetMatrix().GetRow(2) * Matrix3::FromMatrix4(view_item.GetMatrix()).Normalized().Transposed();
Set(*input->location, &d.x, 3);
}
break;
case Core::ShaderInput::LightShadowMatrix0:
case Core::ShaderInput::LightShadowMatrix1:
case Core::ShaderInput::LightShadowMatrix2:
case Core::ShaderInput::LightShadowMatrix3:
case Core::ShaderInput::LightShadowMatrix4:
case Core::ShaderInput::LightShadowMatrix5:
{
uint n = input->semantic - Core::ShaderInput::LightShadowMatrix0;
if (n < light_render_data->shadow_data.GetCount())
Set(*input->location, light_render_data->shadow_data[n].pmatrix * (light_render_data->shadow_data[n].imatrix * view_item.GetMatrix()));
}
break;
case Core::ShaderInput::InverseShadowMapSize:
{
float k = r.pcf_radius / r.gpu_config.shadow_size;
Set(*input->location, k);
}
break;
case Core::ShaderInput::LightShadowMap0:
case Core::ShaderInput::LightShadowMap1:
case Core::ShaderInput::LightShadowMap2:
case Core::ShaderInput::LightShadowMap3:
case Core::ShaderInput::LightShadowMap4:
case Core::ShaderInput::LightShadowMap5:
Set(*input->location, *r.shadow_map, input->index);
break;
case Core::ShaderInput::LightPSSMSliceDistance0:
case Core::ShaderInput::LightPSSMSliceDistance1:
case Core::ShaderInput::LightPSSMSliceDistance2:
case Core::ShaderInput::LightPSSMSliceDistance3:
if (light_render_data->shadow_data)
Set(*input->location, light_render_data->shadow_data[input->semantic - Core::ShaderInput::LightPSSMSliceDistance0].slice_distance);
break;
case Core::ShaderInput::ViewToLightMatrix:
Set(*input->location, l.GetInverseMatrix() * view_item.GetMatrix());
break;
case Core::ShaderInput::LightProjectionMap:
if (light_render_data->projection_texture.IsValid())
Set(*input->location, *light_render_data->projection_texture, input->index);
break;
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Shader::GetSemanticInputList(Core::ShaderInput::Semantic semantic)
{
return Core::ShaderInput::semantic_desc[semantic].category;
}
ShaderInput *Shader::GetInput(Core::ShaderInput::Semantic semantic) const
{
uint cat = GetSemanticInputList(semantic);
for (uint n = 0; n < input_list[cat].GetCount(); ++n)
if (input_list[cat][n].semantic == semantic)
return &input_list[cat][n];
return NULL;
}
ShaderInput *Shader::GetInput(const char *n) const
{
String name(n);
for (uint l = 0; l < Core::ShaderInput::CategoryLast; ++l) // need to check all categories here
for (uint n = 0; n < input_list[l].GetCount(); ++n)
if (!input_list[l][n].name.IsEmpty() && (input_list[l][n].name == name))
return &input_list[l][n];
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Shader::Create(Render::ResourceFactory &rf, const Core::Shader &shader)
{
Free();
__RASSERT_MSG__(renderer.shader_compiler != NULL, String::Format("No shader compiler available for this renderer ('%s').", renderer.GetName()));
if (!renderer.shader_compiler->Compile(shader, *this))
return false;
// Solve uniforms and attributes.
Array <AutoPtr <ShaderInputLocation> > locations(shader.input_list.GetCount());
uint solved_count[Core::ShaderInput::CategoryLast], n = 0;
Memory::Set(solved_count, 0, sizeof(uint) * Core::ShaderInput::CategoryLast);
ListForeachPtr(Core::ShaderInput *, input, shader.input_list)
{
uint input_index = GetSemanticInputList(input->semantic);
locations[n] = NewGPUShaderLocation();
if (GetLocation(input->name, *locations[n], input->type))
solved_count[input_index]++;
else
locations[n] = NULL;
++n;
}
uint texture_count = 0;
for (uint l = 0; l < Core::ShaderInput::CategoryLast; ++l)
{
uint n = 0, i = 0;
if (input_list[l].Allocate(solved_count[l]))
ListForeachPtr(Core::ShaderInput *, input, shader.input_list)
{
if ((l != GetSemanticInputList(input->semantic)) || locations[i].IsNull())
{
++i;
continue;
}
ShaderInput *gpu_input = &input_list[l][n];
gpu_input->location = locations[i].Detach();
gpu_input->Set(input);
// Allocate texture unit index and load render resource.
if (input->type == Core::ShaderInput::Uniform)
if (input->ConsumesTextureUnit())
{
if (!input->parm_t.IsEmpty())
gpu_input->parm_t = rf.LoadTexture(input->parm_t);
gpu_input->index = texture_count++;
}
++i; ++n;
}
}
return true;
}
//------------------------------------------------------------------------------