summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl/gl_shader_gen.h
blob: ea6d216d1c30e766f1d6223be3387c0c0a400e24 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <cstring>
#include <functional>
#include <string>
#include <type_traits>
#include "video_core/regs.h"

namespace GLShader {

enum Attributes {
    ATTRIBUTE_POSITION,
    ATTRIBUTE_COLOR,
    ATTRIBUTE_TEXCOORD0,
    ATTRIBUTE_TEXCOORD1,
    ATTRIBUTE_TEXCOORD2,
    ATTRIBUTE_TEXCOORD0_W,
    ATTRIBUTE_NORMQUAT,
    ATTRIBUTE_VIEW,
};

/**
 * This struct contains all state used to generate the GLSL shader program that emulates the current
 * Pica register configuration. This struct is used as a cache key for generated GLSL shader
 * programs. The functions in gl_shader_gen.cpp should retrieve state from this struct only, not by
 * 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.
 */
union PicaShaderConfig {

    /// Construct a PicaShaderConfig with the given Pica register configuration.
    static PicaShaderConfig BuildFromRegs(const Pica::Regs& regs);

    bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
        return (stage_index < 4) && (state.combiner_buffer_input & (1 << stage_index));
    }

    bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
        return (stage_index < 4) && ((state.combiner_buffer_input >> 4) & (1 << stage_index));
    }

    bool operator==(const PicaShaderConfig& o) const {
        return std::memcmp(&state, &o.state, sizeof(PicaShaderConfig::State)) == 0;
    };

    // 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.
    //       Once that bug is fixed we can use Pica::Regs::TevStageConfig here.
    //       Doesn't include const_color because we don't sync it, see comment in BuildFromRegs()
    struct TevStageConfigRaw {
        u32 sources_raw;
        u32 modifiers_raw;
        u32 ops_raw;
        u32 scales_raw;
        explicit operator Pica::TexturingRegs::TevStageConfig() const noexcept {
            Pica::TexturingRegs::TevStageConfig stage;
            stage.sources_raw = sources_raw;
            stage.modifiers_raw = modifiers_raw;
            stage.ops_raw = ops_raw;
            stage.const_color = 0;
            stage.scales_raw = scales_raw;
            return stage;
        }
    };

    struct State {
        Pica::FramebufferRegs::CompareFunc alpha_test_func;
        Pica::RasterizerRegs::ScissorMode scissor_test_mode;
        Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
        bool texture2_use_coord1;
        std::array<TevStageConfigRaw, 6> tev_stages;
        u8 combiner_buffer_input;

        Pica::RasterizerRegs::DepthBuffering depthmap_enable;
        Pica::TexturingRegs::FogMode fog_mode;
        bool fog_flip;

        struct {
            struct {
                unsigned num;
                bool directional;
                bool two_sided_diffuse;
                bool dist_atten_enable;
            } light[8];

            bool enable;
            unsigned src_num;
            Pica::LightingRegs::LightingBumpMode bump_mode;
            unsigned bump_selector;
            bool bump_renorm;
            bool clamp_highlights;

            Pica::LightingRegs::LightingConfig config;
            Pica::LightingRegs::LightingFresnelSelector fresnel_selector;

            struct {
                bool enable;
                bool abs_input;
                Pica::LightingRegs::LightingLutInput type;
                float scale;
            } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
        } lighting;

        struct {
            bool enable;
            u32 coord;
            Pica::TexturingRegs::ProcTexClamp u_clamp, v_clamp;
            Pica::TexturingRegs::ProcTexCombiner color_combiner, alpha_combiner;
            bool separate_alpha;
            bool noise_enable;
            Pica::TexturingRegs::ProcTexShift u_shift, v_shift;
            u32 lut_width;
            u32 lut_offset;
            Pica::TexturingRegs::ProcTexFilter lut_filter;
        } proctex;

    } state;
};
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
static_assert(std::is_trivially_copyable<PicaShaderConfig::State>::value,
              "PicaShaderConfig::State must be trivially copyable");
#endif

/**
 * Generates the GLSL vertex shader program source code for the current Pica state
 * @returns String of the shader source code
 */
std::string GenerateVertexShader();

/**
 * Generates the GLSL fragment shader program source code for the current Pica state
 * @param config ShaderCacheKey object generated for the current Pica state, used for the shader
 *               configuration (NOTE: Use state in this struct only, not the Pica registers!)
 * @returns String of the shader source code
 */
std::string GenerateFragmentShader(const PicaShaderConfig& config);

} // namespace GLShader

namespace std {
template <>
struct hash<GLShader::PicaShaderConfig> {
    size_t operator()(const GLShader::PicaShaderConfig& k) const {
        return Common::ComputeHash64(&k.state, sizeof(GLShader::PicaShaderConfig::State));
    }
};
} // namespace std