mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Pica: Use a union for PicaShaderConfig
This commit is contained in:
		
							parent
							
								
									5fc8eb227a
								
							
						
					
					
						commit
						f74652d2fe
					
				
					 3 changed files with 131 additions and 117 deletions
				
			
		|  | @ -39,17 +39,24 @@ struct ScreenInfo; | ||||||
|  * directly accessing Pica registers. This should reduce the risk of bugs in shader generation where |  * directly accessing Pica registers. This should reduce the risk of bugs in shader generation where | ||||||
|  * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) |  * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) | ||||||
|  * two separate shaders sharing the same key. |  * two separate shaders sharing the same key. | ||||||
|  |  * | ||||||
|  |  * We use a union because "implicitly-defined copy/move constructor for a union X copies the object representation of X." | ||||||
|  |  * and "implicitly-defined copy assignment operator for a union X copies the object representation (3.9) of X." | ||||||
|  |  * = Bytewise copy instead of memberwise copy. | ||||||
|  |  * This is important because the padding bytes are included in the hash and comparison between objects. | ||||||
|  */ |  */ | ||||||
| struct PicaShaderConfig { | union PicaShaderConfig { | ||||||
| 
 | 
 | ||||||
|     /// Construct a PicaShaderConfig with the current Pica register configuration.
 |     /// Construct a PicaShaderConfig with the current Pica register configuration.
 | ||||||
|     static PicaShaderConfig CurrentConfig() { |     static PicaShaderConfig CurrentConfig() { | ||||||
|         PicaShaderConfig res; |         PicaShaderConfig res; | ||||||
|         std::memset(&res, 0, sizeof(PicaShaderConfig)); | 
 | ||||||
|  |         auto& state = res.state; | ||||||
|  |         std::memset(&state, 0, sizeof(PicaShaderConfig::State)); | ||||||
| 
 | 
 | ||||||
|         const auto& regs = Pica::g_state.regs; |         const auto& regs = Pica::g_state.regs; | ||||||
| 
 | 
 | ||||||
|         res.alpha_test_func = regs.output_merger.alpha_test.enable ? |         state.alpha_test_func = regs.output_merger.alpha_test.enable ? | ||||||
|             regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; |             regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; | ||||||
| 
 | 
 | ||||||
|         // Copy relevant tev stages fields.
 |         // Copy relevant tev stages fields.
 | ||||||
|  | @ -59,86 +66,84 @@ struct PicaShaderConfig { | ||||||
|         DEBUG_ASSERT(res.tev_stages.size() == tev_stages.size()); |         DEBUG_ASSERT(res.tev_stages.size() == tev_stages.size()); | ||||||
|         for (size_t i = 0; i < tev_stages.size(); i++) { |         for (size_t i = 0; i < tev_stages.size(); i++) { | ||||||
|             const auto& tev_stage = tev_stages[i]; |             const auto& tev_stage = tev_stages[i]; | ||||||
|             res.tev_stages[i].sources_raw = tev_stage.sources_raw; |             state.tev_stages[i].sources_raw = tev_stage.sources_raw; | ||||||
|             res.tev_stages[i].modifiers_raw = tev_stage.modifiers_raw; |             state.tev_stages[i].modifiers_raw = tev_stage.modifiers_raw; | ||||||
|             res.tev_stages[i].ops_raw = tev_stage.ops_raw; |             state.tev_stages[i].ops_raw = tev_stage.ops_raw; | ||||||
|             res.tev_stages[i].scales_raw = tev_stage.scales_raw; |             state.tev_stages[i].scales_raw = tev_stage.scales_raw; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         res.combiner_buffer_input = |         state.combiner_buffer_input = | ||||||
|             regs.tev_combiner_buffer_input.update_mask_rgb.Value() | |             regs.tev_combiner_buffer_input.update_mask_rgb.Value() | | ||||||
|             regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; |             regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||||||
| 
 | 
 | ||||||
|         // Fragment lighting
 |         // Fragment lighting
 | ||||||
| 
 | 
 | ||||||
|         res.lighting.enable = !regs.lighting.disable; |         state.lighting.enable = !regs.lighting.disable; | ||||||
|         res.lighting.src_num = regs.lighting.num_lights + 1; |         state.lighting.src_num = regs.lighting.num_lights + 1; | ||||||
| 
 | 
 | ||||||
|         for (unsigned light_index = 0; light_index < res.lighting.src_num; ++light_index) { |         for (unsigned light_index = 0; light_index < state.lighting.src_num; ++light_index) { | ||||||
|             unsigned num = regs.lighting.light_enable.GetNum(light_index); |             unsigned num = regs.lighting.light_enable.GetNum(light_index); | ||||||
|             const auto& light = regs.lighting.light[num]; |             const auto& light = regs.lighting.light[num]; | ||||||
|             res.lighting.light[light_index].num = num; |             state.lighting.light[light_index].num = num; | ||||||
|             res.lighting.light[light_index].directional = light.directional != 0; |             state.lighting.light[light_index].directional = light.directional != 0; | ||||||
|             res.lighting.light[light_index].two_sided_diffuse = light.two_sided_diffuse != 0; |             state.lighting.light[light_index].two_sided_diffuse = light.two_sided_diffuse != 0; | ||||||
|             res.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num); |             state.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num); | ||||||
|             res.lighting.light[light_index].dist_atten_bias = Pica::float20::FromRaw(light.dist_atten_bias).ToFloat32(); |             state.lighting.light[light_index].dist_atten_bias = Pica::float20::FromRaw(light.dist_atten_bias).ToFloat32(); | ||||||
|             res.lighting.light[light_index].dist_atten_scale = Pica::float20::FromRaw(light.dist_atten_scale).ToFloat32(); |             state.lighting.light[light_index].dist_atten_scale = Pica::float20::FromRaw(light.dist_atten_scale).ToFloat32(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         res.lighting.lut_d0.enable = regs.lighting.disable_lut_d0 == 0; |         state.lighting.lut_d0.enable = regs.lighting.disable_lut_d0 == 0; | ||||||
|         res.lighting.lut_d0.abs_input = regs.lighting.abs_lut_input.disable_d0 == 0; |         state.lighting.lut_d0.abs_input = regs.lighting.abs_lut_input.disable_d0 == 0; | ||||||
|         res.lighting.lut_d0.type = regs.lighting.lut_input.d0.Value(); |         state.lighting.lut_d0.type = regs.lighting.lut_input.d0.Value(); | ||||||
|         res.lighting.lut_d0.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d0); |         state.lighting.lut_d0.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d0); | ||||||
| 
 | 
 | ||||||
|         res.lighting.lut_d1.enable = regs.lighting.disable_lut_d1 == 0; |         state.lighting.lut_d1.enable = regs.lighting.disable_lut_d1 == 0; | ||||||
|         res.lighting.lut_d1.abs_input = regs.lighting.abs_lut_input.disable_d1 == 0; |         state.lighting.lut_d1.abs_input = regs.lighting.abs_lut_input.disable_d1 == 0; | ||||||
|         res.lighting.lut_d1.type = regs.lighting.lut_input.d1.Value(); |         state.lighting.lut_d1.type = regs.lighting.lut_input.d1.Value(); | ||||||
|         res.lighting.lut_d1.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d1); |         state.lighting.lut_d1.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.d1); | ||||||
| 
 | 
 | ||||||
|         res.lighting.lut_fr.enable = regs.lighting.disable_lut_fr == 0; |         state.lighting.lut_fr.enable = regs.lighting.disable_lut_fr == 0; | ||||||
|         res.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0; |         state.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0; | ||||||
|         res.lighting.lut_fr.type = regs.lighting.lut_input.fr.Value(); |         state.lighting.lut_fr.type = regs.lighting.lut_input.fr.Value(); | ||||||
|         res.lighting.lut_fr.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.fr); |         state.lighting.lut_fr.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.fr); | ||||||
| 
 | 
 | ||||||
|         res.lighting.lut_rr.enable = regs.lighting.disable_lut_rr == 0; |         state.lighting.lut_rr.enable = regs.lighting.disable_lut_rr == 0; | ||||||
|         res.lighting.lut_rr.abs_input = regs.lighting.abs_lut_input.disable_rr == 0; |         state.lighting.lut_rr.abs_input = regs.lighting.abs_lut_input.disable_rr == 0; | ||||||
|         res.lighting.lut_rr.type = regs.lighting.lut_input.rr.Value(); |         state.lighting.lut_rr.type = regs.lighting.lut_input.rr.Value(); | ||||||
|         res.lighting.lut_rr.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rr); |         state.lighting.lut_rr.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rr); | ||||||
| 
 | 
 | ||||||
|         res.lighting.lut_rg.enable = regs.lighting.disable_lut_rg == 0; |         state.lighting.lut_rg.enable = regs.lighting.disable_lut_rg == 0; | ||||||
|         res.lighting.lut_rg.abs_input = regs.lighting.abs_lut_input.disable_rg == 0; |         state.lighting.lut_rg.abs_input = regs.lighting.abs_lut_input.disable_rg == 0; | ||||||
|         res.lighting.lut_rg.type = regs.lighting.lut_input.rg.Value(); |         state.lighting.lut_rg.type = regs.lighting.lut_input.rg.Value(); | ||||||
|         res.lighting.lut_rg.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rg); |         state.lighting.lut_rg.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rg); | ||||||
| 
 | 
 | ||||||
|         res.lighting.lut_rb.enable = regs.lighting.disable_lut_rb == 0; |         state.lighting.lut_rb.enable = regs.lighting.disable_lut_rb == 0; | ||||||
|         res.lighting.lut_rb.abs_input = regs.lighting.abs_lut_input.disable_rb == 0; |         state.lighting.lut_rb.abs_input = regs.lighting.abs_lut_input.disable_rb == 0; | ||||||
|         res.lighting.lut_rb.type = regs.lighting.lut_input.rb.Value(); |         state.lighting.lut_rb.type = regs.lighting.lut_input.rb.Value(); | ||||||
|         res.lighting.lut_rb.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rb); |         state.lighting.lut_rb.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rb); | ||||||
| 
 | 
 | ||||||
|         res.lighting.config = regs.lighting.config; |         state.lighting.config = regs.lighting.config; | ||||||
|         res.lighting.fresnel_selector = regs.lighting.fresnel_selector; |         state.lighting.fresnel_selector = regs.lighting.fresnel_selector; | ||||||
|         res.lighting.bump_mode = regs.lighting.bump_mode; |         state.lighting.bump_mode = regs.lighting.bump_mode; | ||||||
|         res.lighting.bump_selector = regs.lighting.bump_selector; |         state.lighting.bump_selector = regs.lighting.bump_selector; | ||||||
|         res.lighting.bump_renorm = regs.lighting.disable_bump_renorm == 0; |         state.lighting.bump_renorm = regs.lighting.disable_bump_renorm == 0; | ||||||
|         res.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0; |         state.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0; | ||||||
| 
 | 
 | ||||||
|         return res; |         return res; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { |     bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { | ||||||
|         return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index)); |         return (stage_index < 4) && (state.combiner_buffer_input & (1 << stage_index)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { |     bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { | ||||||
|         return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index)); |         return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool operator ==(const PicaShaderConfig& o) const { |     bool operator ==(const PicaShaderConfig& o) const { | ||||||
|         return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0; |         return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     Pica::Regs::CompareFunc alpha_test_func; |  | ||||||
| 
 |  | ||||||
|     // NOTE: MSVC15 (Update 2) doesn't think `delete`'d constructors and operators are TC.
 |     // NOTE: MSVC15 (Update 2) doesn't think `delete`'d constructors and operators are TC.
 | ||||||
|     //       This makes BitField not TC when used in a union or struct so we have to resort
 |     //       This makes BitField not TC when used in a union or struct so we have to resort
 | ||||||
|     //       to this ugly hack.
 |     //       to this ugly hack.
 | ||||||
|  | @ -159,6 +164,10 @@ struct PicaShaderConfig { | ||||||
|             return stage; |             return stage; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     struct State { | ||||||
|  | 
 | ||||||
|  |         Pica::Regs::CompareFunc alpha_test_func; | ||||||
|         std::array<TevStageConfigRaw, 6> tev_stages; |         std::array<TevStageConfigRaw, 6> tev_stages; | ||||||
|         u8 combiner_buffer_input; |         u8 combiner_buffer_input; | ||||||
| 
 | 
 | ||||||
|  | @ -190,9 +199,10 @@ struct PicaShaderConfig { | ||||||
|             } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb; |             } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb; | ||||||
|         } lighting; |         } lighting; | ||||||
| 
 | 
 | ||||||
|  |     } state; | ||||||
| }; | }; | ||||||
| #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | ||||||
| static_assert(std::is_trivially_copyable<PicaShaderConfig>::value, "PicaShaderConfig must be trivially copyable"); | static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value, "PicaShaderConfig::State must be trivially copyable"); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| namespace std { | namespace std { | ||||||
|  | @ -200,7 +210,7 @@ namespace std { | ||||||
| template <> | template <> | ||||||
| struct hash<PicaShaderConfig> { | struct hash<PicaShaderConfig> { | ||||||
|     size_t operator()(const PicaShaderConfig& k) const { |     size_t operator()(const PicaShaderConfig& k) const { | ||||||
|         return Common::ComputeHash64(&k, sizeof(PicaShaderConfig)); |         return Common::ComputeHash64(&k.state, sizeof(PicaShaderConfig::State)); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -287,7 +287,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | ||||||
| 
 | 
 | ||||||
| /// Writes the code to emulate the specified TEV stage
 | /// Writes the code to emulate the specified TEV stage
 | ||||||
| static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | ||||||
|     const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.tev_stages[index]); |     const auto stage = static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); | ||||||
|     if (!IsPassThroughTevStage(stage)) { |     if (!IsPassThroughTevStage(stage)) { | ||||||
|         std::string index_name = std::to_string(index); |         std::string index_name = std::to_string(index); | ||||||
| 
 | 
 | ||||||
|  | @ -331,6 +331,8 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi | ||||||
| 
 | 
 | ||||||
| /// Writes the code to emulate fragment lighting
 | /// Writes the code to emulate fragment lighting
 | ||||||
| static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
|  |     const auto& lighting = config.state.lighting; | ||||||
|  | 
 | ||||||
|     // Define lighting globals
 |     // Define lighting globals
 | ||||||
|     out += "vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" |     out += "vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" | ||||||
|            "vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" |            "vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);\n" | ||||||
|  | @ -338,17 +340,17 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
|            "vec3 refl_value = vec3(0.0);\n"; |            "vec3 refl_value = vec3(0.0);\n"; | ||||||
| 
 | 
 | ||||||
|     // Compute fragment normals
 |     // Compute fragment normals
 | ||||||
|     if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { |     if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { | ||||||
|         // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture
 |         // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture
 | ||||||
|         std::string bump_selector = std::to_string(config.lighting.bump_selector); |         std::string bump_selector = std::to_string(lighting.bump_selector); | ||||||
|         out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n"; |         out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n"; | ||||||
| 
 | 
 | ||||||
|         // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result
 |         // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result
 | ||||||
|         if (config.lighting.bump_renorm) { |         if (lighting.bump_renorm) { | ||||||
|             std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; |             std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; | ||||||
|             out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; |             out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; | ||||||
|         } |         } | ||||||
|     } else if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { |     } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { | ||||||
|         // Bump mapping is enabled using a tangent map
 |         // Bump mapping is enabled using a tangent map
 | ||||||
|         LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)"); |         LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)"); | ||||||
|         UNIMPLEMENTED(); |         UNIMPLEMENTED(); | ||||||
|  | @ -361,7 +363,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
|     out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; |     out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; | ||||||
| 
 | 
 | ||||||
|     // Gets the index into the specified lookup table for specular lighting
 |     // Gets the index into the specified lookup table for specular lighting
 | ||||||
|     auto GetLutIndex = [config](unsigned light_num, Regs::LightingLutInput input, bool abs) { |     auto GetLutIndex = [&lighting](unsigned light_num, Regs::LightingLutInput input, bool abs) { | ||||||
|         const std::string half_angle = "normalize(normalize(view) + light_vector)"; |         const std::string half_angle = "normalize(normalize(view) + light_vector)"; | ||||||
|         std::string index; |         std::string index; | ||||||
|         switch (input) { |         switch (input) { | ||||||
|  | @ -389,7 +391,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
| 
 | 
 | ||||||
|         if (abs) { |         if (abs) { | ||||||
|             // LUT index is in the range of (0.0, 1.0)
 |             // LUT index is in the range of (0.0, 1.0)
 | ||||||
|             index = config.lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; |             index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; | ||||||
|             return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))"; |             return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))"; | ||||||
|         } else { |         } else { | ||||||
|             // LUT index is in the range of (-1.0, 1.0)
 |             // LUT index is in the range of (-1.0, 1.0)
 | ||||||
|  | @ -407,8 +409,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Write the code to emulate each enabled light
 |     // Write the code to emulate each enabled light
 | ||||||
|     for (unsigned light_index = 0; light_index < config.lighting.src_num; ++light_index) { |     for (unsigned light_index = 0; light_index < lighting.src_num; ++light_index) { | ||||||
|         const auto& light_config = config.lighting.light[light_index]; |         const auto& light_config = lighting.light[light_index]; | ||||||
|         std::string light_src = "light_src[" + std::to_string(light_config.num) + "]"; |         std::string light_src = "light_src[" + std::to_string(light_config.num) + "]"; | ||||||
| 
 | 
 | ||||||
|         // Compute light vector (directional or positional)
 |         // Compute light vector (directional or positional)
 | ||||||
|  | @ -432,39 +434,39 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // If enabled, clamp specular component if lighting result is negative
 |         // If enabled, clamp specular component if lighting result is negative
 | ||||||
|         std::string clamp_highlights = config.lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; |         std::string clamp_highlights = lighting.clamp_highlights ? "(dot(light_vector, normal) <= 0.0 ? 0.0 : 1.0)" : "1.0"; | ||||||
| 
 | 
 | ||||||
|         // Specular 0 component
 |         // Specular 0 component
 | ||||||
|         std::string d0_lut_value = "1.0"; |         std::string d0_lut_value = "1.0"; | ||||||
|         if (config.lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Distribution0)) { |         if (lighting.lut_d0.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution0)) { | ||||||
|             // Lookup specular "distribution 0" LUT value
 |             // Lookup specular "distribution 0" LUT value
 | ||||||
|             std::string index = GetLutIndex(light_config.num, config.lighting.lut_d0.type, config.lighting.lut_d0.abs_input); |             std::string index = GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); | ||||||
|             d0_lut_value = "(" + std::to_string(config.lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; |             d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; | ||||||
|         } |         } | ||||||
|         std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; |         std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; | ||||||
| 
 | 
 | ||||||
|         // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
 |         // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
 | ||||||
|         if (config.lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectRed)) { |         if (lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectRed)) { | ||||||
|             std::string index = GetLutIndex(light_config.num, config.lighting.lut_rr.type, config.lighting.lut_rr.abs_input); |             std::string index = GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); | ||||||
|             std::string value = "(" + std::to_string(config.lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; |             std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; | ||||||
|             out += "refl_value.r = " + value + ";\n"; |             out += "refl_value.r = " + value + ";\n"; | ||||||
|         } else { |         } else { | ||||||
|             out += "refl_value.r = 1.0;\n"; |             out += "refl_value.r = 1.0;\n"; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
 |         // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
 | ||||||
|         if (config.lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) { |         if (lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) { | ||||||
|             std::string index = GetLutIndex(light_config.num, config.lighting.lut_rg.type, config.lighting.lut_rg.abs_input); |             std::string index = GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); | ||||||
|             std::string value = "(" + std::to_string(config.lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; |             std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; | ||||||
|             out += "refl_value.g = " + value + ";\n"; |             out += "refl_value.g = " + value + ";\n"; | ||||||
|         } else { |         } else { | ||||||
|             out += "refl_value.g = refl_value.r;\n"; |             out += "refl_value.g = refl_value.r;\n"; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
 |         // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
 | ||||||
|         if (config.lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) { |         if (lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) { | ||||||
|             std::string index = GetLutIndex(light_config.num, config.lighting.lut_rb.type, config.lighting.lut_rb.abs_input); |             std::string index = GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); | ||||||
|             std::string value = "(" + std::to_string(config.lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; |             std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; | ||||||
|             out += "refl_value.b = " + value + ";\n"; |             out += "refl_value.b = " + value + ";\n"; | ||||||
|         } else { |         } else { | ||||||
|             out += "refl_value.b = refl_value.r;\n"; |             out += "refl_value.b = refl_value.r;\n"; | ||||||
|  | @ -472,27 +474,27 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
| 
 | 
 | ||||||
|         // Specular 1 component
 |         // Specular 1 component
 | ||||||
|         std::string d1_lut_value = "1.0"; |         std::string d1_lut_value = "1.0"; | ||||||
|         if (config.lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Distribution1)) { |         if (lighting.lut_d1.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Distribution1)) { | ||||||
|             // Lookup specular "distribution 1" LUT value
 |             // Lookup specular "distribution 1" LUT value
 | ||||||
|             std::string index = GetLutIndex(light_config.num, config.lighting.lut_d1.type, config.lighting.lut_d1.abs_input); |             std::string index = GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); | ||||||
|             d1_lut_value = "(" + std::to_string(config.lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; |             d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; | ||||||
|         } |         } | ||||||
|         std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; |         std::string specular_1 = "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; | ||||||
| 
 | 
 | ||||||
|         // Fresnel
 |         // Fresnel
 | ||||||
|         if (config.lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(config.lighting.config, Pica::Regs::LightingSampler::Fresnel)) { |         if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::Fresnel)) { | ||||||
|             // Lookup fresnel LUT value
 |             // Lookup fresnel LUT value
 | ||||||
|             std::string index = GetLutIndex(light_config.num, config.lighting.lut_fr.type, config.lighting.lut_fr.abs_input); |             std::string index = GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); | ||||||
|             std::string value = "(" + std::to_string(config.lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; |             std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; | ||||||
| 
 | 
 | ||||||
|             // Enabled for difffuse lighting alpha component
 |             // Enabled for difffuse lighting alpha component
 | ||||||
|             if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || |             if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || | ||||||
|                 config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) |                 lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) | ||||||
|                 out += "diffuse_sum.a  *= " + value + ";\n"; |                 out += "diffuse_sum.a  *= " + value + ";\n"; | ||||||
| 
 | 
 | ||||||
|             // Enabled for the specular lighting alpha component
 |             // Enabled for the specular lighting alpha component
 | ||||||
|             if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha || |             if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha || | ||||||
|                 config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) |                 lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) | ||||||
|                 out += "specular_sum.a *= " + value + ";\n"; |                 out += "specular_sum.a *= " + value + ";\n"; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -510,6 +512,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::string GenerateFragmentShader(const PicaShaderConfig& config) { | std::string GenerateFragmentShader(const PicaShaderConfig& config) { | ||||||
|  |     const auto& state = config.state; | ||||||
|  | 
 | ||||||
|     std::string out = R"( |     std::string out = R"( | ||||||
| #version 330 core | #version 330 core | ||||||
| #define NUM_TEV_STAGES 6 | #define NUM_TEV_STAGES 6 | ||||||
|  | @ -555,24 +559,24 @@ vec4 secondary_fragment_color = vec4(0.0); | ||||||
| )"; | )"; | ||||||
| 
 | 
 | ||||||
|     // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 |     // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 | ||||||
|     if (config.alpha_test_func == Regs::CompareFunc::Never) { |     if (state.alpha_test_func == Regs::CompareFunc::Never) { | ||||||
|         out += "discard; }"; |         out += "discard; }"; | ||||||
|         return out; |         return out; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (config.lighting.enable) |     if (state.lighting.enable) | ||||||
|         WriteLighting(out, config); |         WriteLighting(out, config); | ||||||
| 
 | 
 | ||||||
|     out += "vec4 combiner_buffer = vec4(0.0);\n"; |     out += "vec4 combiner_buffer = vec4(0.0);\n"; | ||||||
|     out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"; |     out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"; | ||||||
|     out += "vec4 last_tex_env_out = vec4(0.0);\n"; |     out += "vec4 last_tex_env_out = vec4(0.0);\n"; | ||||||
| 
 | 
 | ||||||
|     for (size_t index = 0; index < config.tev_stages.size(); ++index) |     for (size_t index = 0; index < state.tev_stages.size(); ++index) | ||||||
|         WriteTevStage(out, config, (unsigned)index); |         WriteTevStage(out, config, (unsigned)index); | ||||||
| 
 | 
 | ||||||
|     if (config.alpha_test_func != Regs::CompareFunc::Always) { |     if (state.alpha_test_func != Regs::CompareFunc::Always) { | ||||||
|         out += "if ("; |         out += "if ("; | ||||||
|         AppendAlphaTestCondition(out, config.alpha_test_func); |         AppendAlphaTestCondition(out, state.alpha_test_func); | ||||||
|         out += ") discard;\n"; |         out += ") discard;\n"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| struct PicaShaderConfig; | union PicaShaderConfig; | ||||||
| 
 | 
 | ||||||
| namespace GLShader { | namespace GLShader { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue