/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __PLATFORM_IOS__ #include #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 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 > 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; } //------------------------------------------------------------------------------