aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/post_processing/fx_compile.cpp
blob: 5ee11e918715a98482a755b43ba36a5cf36ff5d2 (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
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#include <cstring>
#include <memory>
#include <set>

#include "effect_codegen.hpp"
#include "effect_parser.hpp"
#include "effect_preprocessor.hpp"

#include "common/fs/fs.h"
#include "common/fs/fs_util.h"
#include "video_core/post_processing/fx_compile.h"
#include "video_core/post_processing/fx_effect.h"

namespace VideoCore {

FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
                                u32 color_bit_depth) {
    FxCompileResult result;

    if (!Common::FS::Exists(path)) {
        result.error = "Effect file not found: " + Common::FS::PathToUTF8String(path);
        return result;
    }

    reshadefx::preprocessor preprocessor;
    preprocessor.add_macro_definition("__RESHADE__", "60800");
    preprocessor.add_macro_definition("__RESHADE_PERFORMANCE_MODE__", "1");
    preprocessor.add_macro_definition("__RENDERER__", "0x20000");
    preprocessor.add_macro_definition("__VENDOR__", "0");
    preprocessor.add_macro_definition("__DEVICE__", "0");
    preprocessor.add_macro_definition("__APPLICATION__", "0");
    preprocessor.add_macro_definition("BUFFER_WIDTH", std::to_string(width));
    preprocessor.add_macro_definition("BUFFER_HEIGHT", std::to_string(height));
    preprocessor.add_macro_definition("BUFFER_RCP_WIDTH", "(1.0 / BUFFER_WIDTH)");
    preprocessor.add_macro_definition("BUFFER_RCP_HEIGHT", "(1.0 / BUFFER_HEIGHT)");
    preprocessor.add_macro_definition("BUFFER_COLOR_DEPTH", std::to_string(color_bit_depth));
    preprocessor.add_macro_definition("BUFFER_COLOR_BIT_DEPTH", std::to_string(color_bit_depth));

    for (const auto& include : GetFxIncludePaths(path)) {
        preprocessor.add_include_path(include);
    }

    if (!preprocessor.append_file(path)) {
        result.error = preprocessor.errors();
        if (result.error.empty()) {
            result.error = "Failed to preprocess " + Common::FS::PathToUTF8String(path);
        }
        return result;
    }

    std::unique_ptr<reshadefx::codegen> backend(
        reshadefx::create_codegen_spirv(true, false, false, false, true));

    reshadefx::parser parser;
    if (!parser.parse(preprocessor.output(), backend.get())) {
        result.error = parser.errors();
        if (result.error.empty()) {
            result.error = "Failed to parse " + Common::FS::PathToUTF8String(path);
        }
        return result;
    }

    result.module = backend->module();

    std::set<std::string> wanted;
    for (const auto& technique : result.module.techniques) {
        for (const auto& pass : technique.passes) {
            if (!pass.vs_entry_point.empty()) {
                wanted.insert(pass.vs_entry_point);
            }
            if (!pass.ps_entry_point.empty()) {
                wanted.insert(pass.ps_entry_point);
            }
        }
    }

    for (const auto& name : wanted) {
        std::string binary;
        std::string assembly;
        std::string errors;
        if (!backend->assemble_code_for_entry_point(name, binary, assembly, errors)) {
            result.error = "Failed to assemble entry point '" + name + "': " + errors;
            return result;
        }
        if (binary.size() % sizeof(u32) != 0) {
            result.error = "Entry point '" + name + "' produced a malformed SPIR-V module";
            return result;
        }

        std::vector<u32> words(binary.size() / sizeof(u32));
        std::memcpy(words.data(), binary.data(), binary.size());
        result.entry_points.emplace(name, std::move(words));
    }

    if (result.entry_points.empty()) {
        result.error = "Effect declares no usable entry points";
    }

    return result;
}

} // namespace VideoCore