mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Pica: Use a union for PicaShaderConfig
This commit is contained in:
		
							parent
							
								
									5fc8eb227a
								
							
						
					
					
						commit
						f74652d2fe
					
				@ -39,17 +39,24 @@ struct ScreenInfo;
 | 
			
		||||
 * 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)
 | 
			
		||||
 * 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.
 | 
			
		||||
    static PicaShaderConfig CurrentConfig() {
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
        // Copy relevant tev stages fields.
 | 
			
		||||
@ -59,86 +66,84 @@ struct PicaShaderConfig {
 | 
			
		||||
        DEBUG_ASSERT(res.tev_stages.size() == tev_stages.size());
 | 
			
		||||
        for (size_t i = 0; i < tev_stages.size(); i++) {
 | 
			
		||||
            const auto& tev_stage = tev_stages[i];
 | 
			
		||||
            res.tev_stages[i].sources_raw = tev_stage.sources_raw;
 | 
			
		||||
            res.tev_stages[i].modifiers_raw = tev_stage.modifiers_raw;
 | 
			
		||||
            res.tev_stages[i].ops_raw = tev_stage.ops_raw;
 | 
			
		||||
            res.tev_stages[i].scales_raw = tev_stage.scales_raw;
 | 
			
		||||
            state.tev_stages[i].sources_raw = tev_stage.sources_raw;
 | 
			
		||||
            state.tev_stages[i].modifiers_raw = tev_stage.modifiers_raw;
 | 
			
		||||
            state.tev_stages[i].ops_raw = tev_stage.ops_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_a.Value() << 4;
 | 
			
		||||
 | 
			
		||||
        // Fragment lighting
 | 
			
		||||
 | 
			
		||||
        res.lighting.enable = !regs.lighting.disable;
 | 
			
		||||
        res.lighting.src_num = regs.lighting.num_lights + 1;
 | 
			
		||||
        state.lighting.enable = !regs.lighting.disable;
 | 
			
		||||
        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);
 | 
			
		||||
            const auto& light = regs.lighting.light[num];
 | 
			
		||||
            res.lighting.light[light_index].num = num;
 | 
			
		||||
            res.lighting.light[light_index].directional = light.directional != 0;
 | 
			
		||||
            res.lighting.light[light_index].two_sided_diffuse = light.two_sided_diffuse != 0;
 | 
			
		||||
            res.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();
 | 
			
		||||
            res.lighting.light[light_index].dist_atten_scale = Pica::float20::FromRaw(light.dist_atten_scale).ToFloat32();
 | 
			
		||||
            state.lighting.light[light_index].num = num;
 | 
			
		||||
            state.lighting.light[light_index].directional = light.directional != 0;
 | 
			
		||||
            state.lighting.light[light_index].two_sided_diffuse = light.two_sided_diffuse != 0;
 | 
			
		||||
            state.lighting.light[light_index].dist_atten_enable = !regs.lighting.IsDistAttenDisabled(num);
 | 
			
		||||
            state.lighting.light[light_index].dist_atten_bias = Pica::float20::FromRaw(light.dist_atten_bias).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;
 | 
			
		||||
        res.lighting.lut_d0.abs_input = regs.lighting.abs_lut_input.disable_d0 == 0;
 | 
			
		||||
        res.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.enable = regs.lighting.disable_lut_d0 == 0;
 | 
			
		||||
        state.lighting.lut_d0.abs_input = regs.lighting.abs_lut_input.disable_d0 == 0;
 | 
			
		||||
        state.lighting.lut_d0.type = regs.lighting.lut_input.d0.Value();
 | 
			
		||||
        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;
 | 
			
		||||
        res.lighting.lut_d1.abs_input = regs.lighting.abs_lut_input.disable_d1 == 0;
 | 
			
		||||
        res.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.enable = regs.lighting.disable_lut_d1 == 0;
 | 
			
		||||
        state.lighting.lut_d1.abs_input = regs.lighting.abs_lut_input.disable_d1 == 0;
 | 
			
		||||
        state.lighting.lut_d1.type = regs.lighting.lut_input.d1.Value();
 | 
			
		||||
        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;
 | 
			
		||||
        res.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0;
 | 
			
		||||
        res.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.enable = regs.lighting.disable_lut_fr == 0;
 | 
			
		||||
        state.lighting.lut_fr.abs_input = regs.lighting.abs_lut_input.disable_fr == 0;
 | 
			
		||||
        state.lighting.lut_fr.type = regs.lighting.lut_input.fr.Value();
 | 
			
		||||
        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;
 | 
			
		||||
        res.lighting.lut_rr.abs_input = regs.lighting.abs_lut_input.disable_rr == 0;
 | 
			
		||||
        res.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.enable = regs.lighting.disable_lut_rr == 0;
 | 
			
		||||
        state.lighting.lut_rr.abs_input = regs.lighting.abs_lut_input.disable_rr == 0;
 | 
			
		||||
        state.lighting.lut_rr.type = regs.lighting.lut_input.rr.Value();
 | 
			
		||||
        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;
 | 
			
		||||
        res.lighting.lut_rg.abs_input = regs.lighting.abs_lut_input.disable_rg == 0;
 | 
			
		||||
        res.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.enable = regs.lighting.disable_lut_rg == 0;
 | 
			
		||||
        state.lighting.lut_rg.abs_input = regs.lighting.abs_lut_input.disable_rg == 0;
 | 
			
		||||
        state.lighting.lut_rg.type = regs.lighting.lut_input.rg.Value();
 | 
			
		||||
        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;
 | 
			
		||||
        res.lighting.lut_rb.abs_input = regs.lighting.abs_lut_input.disable_rb == 0;
 | 
			
		||||
        res.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.enable = regs.lighting.disable_lut_rb == 0;
 | 
			
		||||
        state.lighting.lut_rb.abs_input = regs.lighting.abs_lut_input.disable_rb == 0;
 | 
			
		||||
        state.lighting.lut_rb.type = regs.lighting.lut_input.rb.Value();
 | 
			
		||||
        state.lighting.lut_rb.scale = regs.lighting.lut_scale.GetScale(regs.lighting.lut_scale.rb);
 | 
			
		||||
 | 
			
		||||
        res.lighting.config = regs.lighting.config;
 | 
			
		||||
        res.lighting.fresnel_selector = regs.lighting.fresnel_selector;
 | 
			
		||||
        res.lighting.bump_mode = regs.lighting.bump_mode;
 | 
			
		||||
        res.lighting.bump_selector = regs.lighting.bump_selector;
 | 
			
		||||
        res.lighting.bump_renorm = regs.lighting.disable_bump_renorm == 0;
 | 
			
		||||
        res.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0;
 | 
			
		||||
        state.lighting.config = regs.lighting.config;
 | 
			
		||||
        state.lighting.fresnel_selector = regs.lighting.fresnel_selector;
 | 
			
		||||
        state.lighting.bump_mode = regs.lighting.bump_mode;
 | 
			
		||||
        state.lighting.bump_selector = regs.lighting.bump_selector;
 | 
			
		||||
        state.lighting.bump_renorm = regs.lighting.disable_bump_renorm == 0;
 | 
			
		||||
        state.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0;
 | 
			
		||||
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
        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 {
 | 
			
		||||
        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.
 | 
			
		||||
    //       This makes BitField not TC when used in a union or struct so we have to resort
 | 
			
		||||
    //       to this ugly hack.
 | 
			
		||||
@ -159,40 +164,45 @@ struct PicaShaderConfig {
 | 
			
		||||
            return stage;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    std::array<TevStageConfigRaw, 6> tev_stages;
 | 
			
		||||
    u8 combiner_buffer_input;
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        struct {
 | 
			
		||||
            unsigned num;
 | 
			
		||||
            bool directional;
 | 
			
		||||
            bool two_sided_diffuse;
 | 
			
		||||
            bool dist_atten_enable;
 | 
			
		||||
            GLfloat dist_atten_scale;
 | 
			
		||||
            GLfloat dist_atten_bias;
 | 
			
		||||
        } light[8];
 | 
			
		||||
    struct State {
 | 
			
		||||
 | 
			
		||||
        bool enable;
 | 
			
		||||
        unsigned src_num;
 | 
			
		||||
        Pica::Regs::LightingBumpMode bump_mode;
 | 
			
		||||
        unsigned bump_selector;
 | 
			
		||||
        bool bump_renorm;
 | 
			
		||||
        bool clamp_highlights;
 | 
			
		||||
 | 
			
		||||
        Pica::Regs::LightingConfig config;
 | 
			
		||||
        Pica::Regs::LightingFresnelSelector fresnel_selector;
 | 
			
		||||
        Pica::Regs::CompareFunc alpha_test_func;
 | 
			
		||||
        std::array<TevStageConfigRaw, 6> tev_stages;
 | 
			
		||||
        u8 combiner_buffer_input;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            struct {
 | 
			
		||||
                unsigned num;
 | 
			
		||||
                bool directional;
 | 
			
		||||
                bool two_sided_diffuse;
 | 
			
		||||
                bool dist_atten_enable;
 | 
			
		||||
                GLfloat dist_atten_scale;
 | 
			
		||||
                GLfloat dist_atten_bias;
 | 
			
		||||
            } light[8];
 | 
			
		||||
 | 
			
		||||
            bool enable;
 | 
			
		||||
            bool abs_input;
 | 
			
		||||
            Pica::Regs::LightingLutInput type;
 | 
			
		||||
            float scale;
 | 
			
		||||
        } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
 | 
			
		||||
    } lighting;
 | 
			
		||||
            unsigned src_num;
 | 
			
		||||
            Pica::Regs::LightingBumpMode bump_mode;
 | 
			
		||||
            unsigned bump_selector;
 | 
			
		||||
            bool bump_renorm;
 | 
			
		||||
            bool clamp_highlights;
 | 
			
		||||
 | 
			
		||||
            Pica::Regs::LightingConfig config;
 | 
			
		||||
            Pica::Regs::LightingFresnelSelector fresnel_selector;
 | 
			
		||||
 | 
			
		||||
            struct {
 | 
			
		||||
                bool enable;
 | 
			
		||||
                bool abs_input;
 | 
			
		||||
                Pica::Regs::LightingLutInput type;
 | 
			
		||||
                float scale;
 | 
			
		||||
            } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
 | 
			
		||||
        } lighting;
 | 
			
		||||
 | 
			
		||||
    } state;
 | 
			
		||||
};
 | 
			
		||||
#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
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
@ -200,7 +210,7 @@ namespace std {
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<PicaShaderConfig> {
 | 
			
		||||
    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
 | 
			
		||||
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)) {
 | 
			
		||||
        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
 | 
			
		||||
static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
 | 
			
		||||
    const auto& lighting = config.state.lighting;
 | 
			
		||||
 | 
			
		||||
    // Define lighting globals
 | 
			
		||||
    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"
 | 
			
		||||
@ -338,17 +340,17 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
 | 
			
		||||
           "vec3 refl_value = vec3(0.0);\n";
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
        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";
 | 
			
		||||
 | 
			
		||||
        // 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))";
 | 
			
		||||
            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
 | 
			
		||||
        LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
@ -361,7 +363,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
 | 
			
		||||
    out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
 | 
			
		||||
 | 
			
		||||
    // 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)";
 | 
			
		||||
        std::string index;
 | 
			
		||||
        switch (input) {
 | 
			
		||||
@ -389,7 +391,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
 | 
			
		||||
 | 
			
		||||
        if (abs) {
 | 
			
		||||
            // 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))";
 | 
			
		||||
        } else {
 | 
			
		||||
            // 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
 | 
			
		||||
    for (unsigned light_index = 0; light_index < config.lighting.src_num; ++light_index) {
 | 
			
		||||
        const auto& light_config = config.lighting.light[light_index];
 | 
			
		||||
    for (unsigned light_index = 0; light_index < lighting.src_num; ++light_index) {
 | 
			
		||||
        const auto& light_config = lighting.light[light_index];
 | 
			
		||||
        std::string light_src = "light_src[" + std::to_string(light_config.num) + "]";
 | 
			
		||||
 | 
			
		||||
        // 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
 | 
			
		||||
        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
 | 
			
		||||
        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
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, config.lighting.lut_d0.type, config.lighting.lut_d0.abs_input);
 | 
			
		||||
            d0_lut_value = "(" + std::to_string(config.lighting.lut_d0.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution0, index) + ")";
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
 | 
			
		||||
            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)";
 | 
			
		||||
 | 
			
		||||
        // 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)) {
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, config.lighting.lut_rr.type, config.lighting.lut_rr.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(config.lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
 | 
			
		||||
        if (lighting.lut_rr.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectRed)) {
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
 | 
			
		||||
            out += "refl_value.r = " + value + ";\n";
 | 
			
		||||
        } else {
 | 
			
		||||
            out += "refl_value.r = 1.0;\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 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)) {
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, config.lighting.lut_rg.type, config.lighting.lut_rg.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(config.lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
 | 
			
		||||
        if (lighting.lut_rg.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectGreen)) {
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
 | 
			
		||||
            out += "refl_value.g = " + value + ";\n";
 | 
			
		||||
        } else {
 | 
			
		||||
            out += "refl_value.g = refl_value.r;\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 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)) {
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, config.lighting.lut_rb.type, config.lighting.lut_rb.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(config.lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
 | 
			
		||||
        if (lighting.lut_rb.enable && Pica::Regs::IsLightingSamplerSupported(lighting.config, Pica::Regs::LightingSampler::ReflectBlue)) {
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
 | 
			
		||||
            out += "refl_value.b = " + value + ";\n";
 | 
			
		||||
        } else {
 | 
			
		||||
            out += "refl_value.b = refl_value.r;\n";
 | 
			
		||||
@ -472,27 +474,27 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
 | 
			
		||||
 | 
			
		||||
        // Specular 1 component
 | 
			
		||||
        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
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, config.lighting.lut_d1.type, config.lighting.lut_d1.abs_input);
 | 
			
		||||
            d1_lut_value = "(" + std::to_string(config.lighting.lut_d1.scale) + " * " + GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
 | 
			
		||||
            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)";
 | 
			
		||||
 | 
			
		||||
        // 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
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, config.lighting.lut_fr.type, config.lighting.lut_fr.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(config.lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
 | 
			
		||||
            std::string index = GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
 | 
			
		||||
            std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
 | 
			
		||||
 | 
			
		||||
            // Enabled for difffuse lighting alpha component
 | 
			
		||||
            if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
 | 
			
		||||
                config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
 | 
			
		||||
            if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
 | 
			
		||||
                lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
 | 
			
		||||
                out += "diffuse_sum.a  *= " + value + ";\n";
 | 
			
		||||
 | 
			
		||||
            // Enabled for the specular lighting alpha component
 | 
			
		||||
            if (config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
 | 
			
		||||
                config.lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
 | 
			
		||||
            if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
 | 
			
		||||
                lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
 | 
			
		||||
                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) {
 | 
			
		||||
    const auto& state = config.state;
 | 
			
		||||
 | 
			
		||||
    std::string out = R"(
 | 
			
		||||
#version 330 core
 | 
			
		||||
#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
 | 
			
		||||
    if (config.alpha_test_func == Regs::CompareFunc::Never) {
 | 
			
		||||
    if (state.alpha_test_func == Regs::CompareFunc::Never) {
 | 
			
		||||
        out += "discard; }";
 | 
			
		||||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (config.lighting.enable)
 | 
			
		||||
    if (state.lighting.enable)
 | 
			
		||||
        WriteLighting(out, config);
 | 
			
		||||
 | 
			
		||||
    out += "vec4 combiner_buffer = vec4(0.0);\n";
 | 
			
		||||
    out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\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);
 | 
			
		||||
 | 
			
		||||
    if (config.alpha_test_func != Regs::CompareFunc::Always) {
 | 
			
		||||
    if (state.alpha_test_func != Regs::CompareFunc::Always) {
 | 
			
		||||
        out += "if (";
 | 
			
		||||
        AppendAlphaTestCondition(out, config.alpha_test_func);
 | 
			
		||||
        AppendAlphaTestCondition(out, state.alpha_test_func);
 | 
			
		||||
        out += ") discard;\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
struct PicaShaderConfig;
 | 
			
		||||
union PicaShaderConfig;
 | 
			
		||||
 | 
			
		||||
namespace GLShader {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user