summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp
blob: 333a91cc5831e6c0bd2cad9a3f43a540647d0e62 (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
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "shader_recompiler/backend/bindings.h"
#include "shader_recompiler/backend/glasm/emit_glasm.h"
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
#include "shader_recompiler/frontend/ir/program.h"
#include "shader_recompiler/profile.h"
#include "shader_recompiler/runtime_info.h"

namespace Shader::Backend::GLASM {
namespace {
std::string_view InterpDecorator(Interpolation interp) {
    switch (interp) {
    case Interpolation::Smooth:
        return "";
    case Interpolation::Flat:
        return "FLAT ";
    case Interpolation::NoPerspective:
        return "NOPERSPECTIVE ";
    }
    throw InvalidArgument("Invalid interpolation {}", interp);
}

bool IsInputArray(Stage stage) {
    return stage == Stage::Geometry || stage == Stage::TessellationControl ||
           stage == Stage::TessellationEval;
}
} // Anonymous namespace

EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
                         const RuntimeInfo& runtime_info_)
    : info{program.info}, profile{profile_}, runtime_info{runtime_info_} {
    // FIXME: Temporary partial implementation
    u32 cbuf_index{};
    for (const auto& desc : info.constant_buffer_descriptors) {
        if (desc.count != 1) {
            throw NotImplementedException("Constant buffer descriptor array");
        }
        Add("CBUFFER c{}[]={{program.buffer[{}]}};", desc.index, cbuf_index);
        ++cbuf_index;
    }
    u32 ssbo_index{};
    for (const auto& desc : info.storage_buffers_descriptors) {
        if (desc.count != 1) {
            throw NotImplementedException("Storage buffer descriptor array");
        }
        if (runtime_info.glasm_use_storage_buffers) {
            Add("STORAGE ssbo{}[]={{program.storage[{}]}};", ssbo_index, bindings.storage_buffer);
            ++bindings.storage_buffer;
            ++ssbo_index;
        }
    }
    if (!runtime_info.glasm_use_storage_buffers) {
        if (const size_t num = info.storage_buffers_descriptors.size(); num > 0) {
            const size_t index{num + PROGRAM_LOCAL_PARAMETER_STORAGE_BUFFER_BASE};
            Add("PARAM c[{}]={{program.local[0..{}]}};", index, index - 1);
        }
    }
    stage = program.stage;
    switch (program.stage) {
    case Stage::VertexA:
    case Stage::VertexB:
        stage_name = "vertex";
        attrib_name = "vertex";
        break;
    case Stage::TessellationControl:
    case Stage::TessellationEval:
        stage_name = "primitive";
        attrib_name = "primitive";
        break;
    case Stage::Geometry:
        stage_name = "primitive";
        attrib_name = "vertex";
        break;
    case Stage::Fragment:
        stage_name = "fragment";
        attrib_name = "fragment";
        break;
    case Stage::Compute:
        stage_name = "invocation";
        break;
    }
    const std::string_view attr_stage{stage == Stage::Fragment ? "fragment" : "vertex"};
    const VaryingState loads{info.loads.mask | info.passthrough.mask};
    for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
        if (loads.Generic(index)) {
            Add("{}ATTRIB in_attr{}[]={{{}.attrib[{}..{}]}};",
                InterpDecorator(info.interpolation[index]), index, attr_stage, index, index);
        }
    }
    if (IsInputArray(stage) && loads.AnyComponent(IR::Attribute::PositionX)) {
        Add("ATTRIB vertex_position=vertex.position;");
    }
    if (info.uses_invocation_id) {
        Add("ATTRIB primitive_invocation=primitive.invocation;");
    }
    if (info.uses_invocation_info &&
        (stage == Stage::TessellationControl || stage == Stage::TessellationEval)) {
        Add("ATTRIB primitive_vertexcount = primitive.vertexcount;");
    }
    if (info.stores_tess_level_outer) {
        Add("OUTPUT result_patch_tessouter[]={{result.patch.tessouter[0..3]}};");
    }
    if (info.stores_tess_level_inner) {
        Add("OUTPUT result_patch_tessinner[]={{result.patch.tessinner[0..1]}};");
    }
    if (info.stores.ClipDistances()) {
        Add("OUTPUT result_clip[]={{result.clip[0..7]}};");
    }
    for (size_t index = 0; index < info.uses_patches.size(); ++index) {
        if (!info.uses_patches[index]) {
            continue;
        }
        if (stage == Stage::TessellationControl) {
            Add("OUTPUT result_patch_attrib{}[]={{result.patch.attrib[{}..{}]}};"
                "ATTRIB primitive_out_patch_attrib{}[]={{primitive.out.patch.attrib[{}..{}]}};",
                index, index, index, index, index, index);
        } else {
            Add("ATTRIB primitive_patch_attrib{}[]={{primitive.patch.attrib[{}..{}]}};", index,
                index, index);
        }
    }
    if (stage == Stage::Fragment) {
        Add("OUTPUT frag_color0=result.color;");
        for (size_t index = 1; index < info.stores_frag_color.size(); ++index) {
            Add("OUTPUT frag_color{}=result.color[{}];", index, index);
        }
    }
    for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
        if (info.stores.Generic(index)) {
            Add("OUTPUT out_attr{}[]={{result.attrib[{}..{}]}};", index, index, index);
        }
    }
    image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
    for (const auto& desc : info.image_buffer_descriptors) {
        image_buffer_bindings.push_back(bindings.image);
        bindings.image += desc.count;
    }
    image_bindings.reserve(info.image_descriptors.size());
    for (const auto& desc : info.image_descriptors) {
        image_bindings.push_back(bindings.image);
        bindings.image += desc.count;
    }
    texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
    for (const auto& desc : info.texture_buffer_descriptors) {
        texture_buffer_bindings.push_back(bindings.texture);
        bindings.texture += desc.count;
    }
    texture_bindings.reserve(info.texture_descriptors.size());
    for (const auto& desc : info.texture_descriptors) {
        texture_bindings.push_back(bindings.texture);
        bindings.texture += desc.count;
    }
}

} // namespace Shader::Backend::GLASM