use std::collections::BTreeMap;
use crate::shader::source;
use concinnity_core::platform::Platform;
use concinnity_core::render::shader_programs::{ShaderProgram, metal, shared};
use concinnity_core::render::shader_source::Splice;
use concinnity_shader::layout::StructLayout;
fn layout_target(platform: Platform) -> concinnity_shader::HlslTarget {
match platform {
Platform::Metal | Platform::Vulkan => concinnity_shader::HlslTarget::SpirvWithVulkanLayout,
Platform::DirectX => concinnity_shader::HlslTarget::SpirvWithDxLayout,
}
}
pub(super) struct Program {
pub row: &'static ShaderProgram,
pub splices: &'static [Splice<'static>],
}
impl Program {
fn source(&self, platform: Platform) -> String {
let defines = self.row.at(false).defines();
source::assemble(false, platform, self.row.file, &defines, self.splices)
}
}
pub(super) fn msl(program: &Program) -> Result<String, String> {
let source = program.source(Platform::Metal);
let job = concinnity_shader::HlslJob {
source: &source,
file_name: program.row.file,
entry: program.row.entry,
target: concinnity_shader::HlslTarget::Msl,
};
let work = crate::shader::compiler_work::dir()?;
concinnity_shader::compile(&job, work.path())
.map(|bytes| String::from_utf8_lossy(&bytes).into_owned())
.map_err(|e| format!("{} (metal): {e}", program.row.entry))
}
pub(super) fn layouts(
program: &Program,
platform: Platform,
) -> Result<BTreeMap<String, StructLayout>, String> {
let source = program.source(platform);
let job = concinnity_shader::HlslJob {
source: &source,
file_name: program.row.file,
entry: program.row.entry,
target: layout_target(platform),
};
let work = crate::shader::compiler_work::dir()?;
let spirv = concinnity_shader::compile(&job, work.path())
.map_err(|e| format!("{} ({}): {e}", program.row.entry, platform.key()))?;
concinnity_shader::layout::struct_layouts(&spirv)
.map_err(|e| format!("{} ({}): {e}", program.row.entry, platform.key()))
}
pub(super) static MAIN_BINDLESS_FRAG: Program = Program {
row: &shared::MAIN_BINDLESS_FRAG,
splices: &[],
};
pub(super) static MAIN_BINDLESS_FRAG_LATE_MEMBER_SHADE: Program = Program {
splices: &[Splice::inline(
"{SURFACE_FRAGMENT}",
"float4 shade(VertexOut v, GpuObjectData od) { return float4(ltc_magnitude_sample(v.uv), 0.0, 1.0); }",
)],
..MAIN_BINDLESS_FRAG
};
const PARAMS_SHADE: &str = "float4 shade(VertexOut v, GpuObjectData od) { return float4(material_param(3), 0.0, 0.0, 1.0); }";
const PARAMS_TRANSFORM: &str = "VertexOut transform(float4x4 m, float3 p, float3 n, float3 t, float3 c, float2 uv)\n\
{\n return project_vertex(m, p + n * material_param(0), n, t, c, uv);\n}\n";
pub(super) static MAIN_BINDLESS_FRAG_PARAMS_SHADE: Program = Program {
splices: &[Splice::inline("{SURFACE_FRAGMENT}", PARAMS_SHADE)],
..MAIN_BINDLESS_FRAG
};
pub(super) static MAIN_BINDLESS_VERT_PARAMS_TRANSFORM: Program = Program {
row: &shared::MAIN_BINDLESS_VERT,
splices: &[
Splice::inline("{SURFACE_VERTEX}", PARAMS_TRANSFORM),
Splice::inline("{SURFACE_FRAGMENT}", PARAMS_SHADE),
],
};
pub(super) static CULL_KERNEL: Program = Program {
row: &shared::CULL_PHASE1,
splices: &[],
};
pub(super) static LIGHT_CULL_KERNEL: Program = Program {
row: &shared::LIGHT_CULL,
splices: &[],
};
pub(super) static RT_SKIN_KERNEL: Program = Program {
row: &shared::RT_SKIN,
splices: &[],
};
pub(super) static MAIN_PREPASS_VERT: Program = Program {
row: &shared::MAIN_PREPASS_VERT,
splices: &[],
};
pub(super) static MAIN_PREPASS_FRAG: Program = Program {
row: &shared::MAIN_PREPASS_FRAG,
splices: &[],
};
pub(super) static SHADOW_VERT: Program = Program {
row: &shared::SHADOW_VERT_BINDLESS,
splices: &[],
};
pub(super) static GLASS_VERT: Program = Program {
row: &shared::GLASS_VERT,
splices: &[],
};
pub(super) static GLASS_MESH_VERT: Program = Program {
row: &shared::GLASS_MESH_VERT,
splices: &[],
};
pub(super) static WATER_VERT: Program = Program {
row: &shared::WATER_VERT,
splices: &[],
};
pub(super) static RT_REFLECTIONS_FRAG: Program = Program {
row: &shared::RT_REFLECTIONS_FRAG,
splices: &[],
};
pub(super) static DECAL_VERT: Program = Program {
row: &shared::DECAL_VERT,
splices: &[],
};
pub(super) static LINE_VERT: Program = Program {
row: &shared::LINE_VERT,
splices: &[],
};
pub(super) static PARTICLE_VERT: Program = Program {
row: &shared::PARTICLE_VERT,
splices: &[],
};
pub(super) static TEXT_VERT: Program = Program {
row: &shared::TEXT_VERT,
splices: &[],
};
pub(super) static TAA_FRAG: Program = Program {
row: &shared::TAA_FRAG,
splices: &[],
};
pub(super) static BLOOM_PREFILTER: Program = Program {
row: &shared::BLOOM_PREFILTER,
splices: &[],
};
pub(super) static COMPOSITE_FRAG: Program = Program {
row: &shared::COMPOSITE_FRAG,
splices: &[],
};
pub(super) static SSAO_KERNEL: Program = Program {
row: &shared::SSAO_KERNEL,
splices: &[],
};
pub(super) static SSR_RESOLVE: Program = Program {
row: &shared::SSR_RESOLVE,
splices: &[],
};
pub(super) static SSGI_TRACE: Program = Program {
row: &shared::SSGI_TRACE,
splices: &[],
};
pub(super) static FOG_FROXEL: Program = Program {
row: &shared::FOG_FROXEL,
splices: &[],
};
pub(super) static AUTO_EXPOSURE_BUILD: Program = Program {
row: &shared::AUTO_EXPOSURE_BUILD,
splices: &[],
};
pub(super) static HIZ_INIT_SINGLE: Program = Program {
row: &metal::HIZ_INIT_SINGLE,
splices: &[],
};
const SDF_STANDIN: Splice<'static> = Splice::inline(
"{SDF_BODY}",
"float map(float3 p, SdfParams q, float t) { return sdSphere(p, 0.5); }\n\
SdfSurface shade(float3 p, float3 n, SdfParams q, float t, float2 uv) {\n\
SdfSurface s; s.albedo = float3(1.0, 1.0, 1.0); s.roughness = 0.5;\n\
s.metallic = 0.0; s.emissive = float3(0.0, 0.0, 0.0);\n\
s.transmitted = float3(0.0, 0.0, 0.0); return s; }\n",
);
pub(super) static RAYMARCH_FRAG: Program = Program {
row: &ShaderProgram {
file: "raymarch.hlsl",
entry: "raymarch_fragment",
label: "raymarch_frag.hlsl",
gates: &["RAYMARCH_SURFACE"],
msaa: false,
},
splices: &[SDF_STANDIN],
};
pub(super) static RAYMARCH_SHADOW_VERT: Program = Program {
row: &ShaderProgram {
file: "raymarch.hlsl",
entry: "raymarch_shadow_vertex",
label: "raymarch_shadow_vert.hlsl",
gates: &["RAYMARCH_SHADOW"],
msaa: false,
},
splices: &[SDF_STANDIN],
};