vk_shader_gen_spv: Emulate fog

* Fixes the intro of MM3D
This commit is contained in:
GPUCode
2023-02-27 20:50:24 +02:00
parent dfd8ded206
commit 07f85cf639
2 changed files with 66 additions and 14 deletions

View File

@@ -59,20 +59,23 @@ void FragmentModule::Generate() {
WriteAlphaTestCondition(config.state.alpha_test_func); WriteAlphaTestCondition(config.state.alpha_test_func);
if (config.state.fog_mode == TexturingRegs::FogMode::Gas) {
Core::System::GetInstance().TelemetrySession().AddField(
Common::Telemetry::FieldType::Session, "VideoCore_Pica_UseGasMode", true);
LOG_CRITICAL(Render_Vulkan, "Unimplemented gas mode");
OpKill();
OpFunctionEnd();
return;
}
// After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use // After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use
// default near = 0 and far = 1, and undo the transformation to get the original z_over_w, then // default near = 0 and far = 1, and undo the transformation to get the original z_over_w, then
// do our own transformation according to PICA specification. // do our own transformation according to PICA specification.
WriteDepth(); WriteDepth();
// Emulate the fog
switch (config.state.fog_mode) {
case TexturingRegs::FogMode::Fog:
WriteFog();
break;
case TexturingRegs::FogMode::Gas:
WriteGas();
break;
default:
break;
}
Id color{Byteround(last_tex_env_out, 4)}; Id color{Byteround(last_tex_env_out, 4)};
if (config.state.emulate_logic_op) { if (config.state.emulate_logic_op) {
switch (config.state.logic_op) { switch (config.state.logic_op) {
@@ -112,15 +115,13 @@ void FragmentModule::WriteDepth() {
const Id z_over_w{OpFma(f32_id, ConstF32(2.f), gl_frag_coord_z, ConstF32(-1.f))}; const Id z_over_w{OpFma(f32_id, ConstF32(2.f), gl_frag_coord_z, ConstF32(-1.f))};
const Id depth_scale{GetShaderDataMember(f32_id, ConstS32(2))}; const Id depth_scale{GetShaderDataMember(f32_id, ConstS32(2))};
const Id depth_offset{GetShaderDataMember(f32_id, ConstS32(3))}; const Id depth_offset{GetShaderDataMember(f32_id, ConstS32(3))};
const Id depth{OpFma(f32_id, z_over_w, depth_scale, depth_offset)}; depth = OpFma(f32_id, z_over_w, depth_scale, depth_offset);
if (config.state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) { if (config.state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) {
const Id gl_frag_coord_w{ const Id gl_frag_coord_w{
OpLoad(f32_id, OpAccessChain(input_pointer_id, gl_frag_coord_id, ConstU32(3u)))}; OpLoad(f32_id, OpAccessChain(input_pointer_id, gl_frag_coord_id, ConstU32(3u)))};
const Id depth_over_w{OpFDiv(f32_id, depth, gl_frag_coord_w)}; depth = OpFDiv(f32_id, depth, gl_frag_coord_w);
OpStore(gl_frag_depth_id, depth_over_w);
} else {
OpStore(gl_frag_depth_id, depth);
} }
OpStore(gl_frag_depth_id, depth);
} }
void FragmentModule::WriteScissor() { void FragmentModule::WriteScissor() {
@@ -160,6 +161,50 @@ void FragmentModule::WriteScissor() {
AddLabel(merge_block); AddLabel(merge_block);
} }
void FragmentModule::WriteFog() {
// Get index into fog LUT
Id fog_index{};
if (config.state.fog_flip) {
fog_index = OpFMul(f32_id, OpFSub(f32_id, ConstF32(1.f), depth), ConstF32(128.f));
} else {
fog_index = OpFMul(f32_id, depth, ConstF32(128.f));
}
// Generate clamped fog factor from LUT for given fog index
const Id fog_i{OpFClamp(f32_id, OpFloor(f32_id, fog_index), ConstF32(0.f), ConstF32(127.f))};
const Id fog_f{OpFSub(f32_id, fog_index, fog_i)};
const Id fog_lut_offset{GetShaderDataMember(i32_id, ConstS32(10))};
const Id coord{OpIAdd(i32_id, OpConvertFToS(i32_id, fog_i), fog_lut_offset)};
if (!Sirit::ValidId(texture_buffer_lut_lf)) {
const Id sampled_image{TypeSampledImage(image_buffer_id)};
texture_buffer_lut_lf = OpLoad(sampled_image, texture_buffer_lut_lf_id);
}
const Id fog_lut_entry_rgba{
OpImageFetch(vec_ids.Get(4), OpImage(image_buffer_id, texture_buffer_lut_lf), coord)};
const Id fog_lut_r{OpCompositeExtract(f32_id, fog_lut_entry_rgba, 0)};
const Id fog_lut_g{OpCompositeExtract(f32_id, fog_lut_entry_rgba, 1)};
Id fog_factor{OpFma(f32_id, fog_f, fog_lut_g, fog_lut_r)};
fog_factor = OpFClamp(f32_id, fog_factor, ConstF32(0.f), ConstF32(1.f));
// Blend the fog
const Id tex_env_rgb{
OpVectorShuffle(vec_ids.Get(3), last_tex_env_out, last_tex_env_out, 0, 1, 2)};
const Id fog_color{GetShaderDataMember(vec_ids.Get(3), ConstS32(20))};
const Id fog_factor_rgb{
OpCompositeConstruct(vec_ids.Get(3), fog_factor, fog_factor, fog_factor)};
const Id fog_result{OpFMix(vec_ids.Get(3), fog_color, tex_env_rgb, fog_factor_rgb)};
last_tex_env_out = OpVectorShuffle(vec_ids.Get(4), fog_result, last_tex_env_out, 0, 1, 2, 6);
}
void FragmentModule::WriteGas() {
// TODO: Implement me
Core::System::GetInstance().TelemetrySession().AddField(Common::Telemetry::FieldType::Session,
"VideoCore_Pica_UseGasMode", true);
LOG_CRITICAL(Render_Vulkan, "Unimplemented gas mode");
OpKill();
OpFunctionEnd();
}
void FragmentModule::WriteLighting() { void FragmentModule::WriteLighting() {
const auto& lighting = config.state.lighting; const auto& lighting = config.state.lighting;

View File

@@ -43,6 +43,12 @@ private:
/// Writes the code to emulate fragment lighting /// Writes the code to emulate fragment lighting
void WriteLighting(); void WriteLighting();
/// Writes the code to emulate fog
void WriteFog();
/// Writes the code to emulate gas rendering
void WriteGas();
/// Writes the code to emulate the specified TEV stage /// Writes the code to emulate the specified TEV stage
void WriteTevStage(s32 index); void WriteTevStage(s32 index);
@@ -235,6 +241,7 @@ private:
Id gl_frag_coord_id{}; Id gl_frag_coord_id{};
Id gl_frag_depth_id{}; Id gl_frag_depth_id{};
Id depth{};
Id tex0_id{}; Id tex0_id{};
Id tex1_id{}; Id tex1_id{};