Blender V5.0
glsl_preprocess.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <filesystem>
10#include <fstream>
11#include <iostream>
12#include <regex>
13#include <string>
14
15#include "glsl_preprocess.hh"
16
17int main(int argc, char **argv)
18{
19 if (argc != 5) {
20 std::cerr << "Usage: glsl_preprocess <data_file_from> <data_file_to> <metadata_file_to> "
21 "<infos_file_to>"
22 << std::endl;
23 exit(1);
24 }
25
26 const char *input_file_name = argv[1];
27 const char *output_file_name = argv[2];
28 const char *metadata_file_name = argv[3];
29 const char *infos_file_name = argv[4];
30
31 /* Open the input file for reading */
32 std::ifstream input_file(input_file_name);
33 if (!input_file) {
34 std::cerr << "Error: Could not open input file " << input_file_name << std::endl;
35 exit(1);
36 }
37
38 /* We make the required directories here rather than having the build system
39 * do the work for us, as having cmake do it leads to several thousand cmake
40 * instances being launched, leading to significant overhead, see pr #141404
41 * for details. */
42 std::filesystem::path parent_dir = std::filesystem::path(output_file_name).parent_path();
43 std::error_code ec;
44 if (!std::filesystem::create_directories(parent_dir, ec)) {
45 if (ec) {
46 std::cerr << "Unable to create " << parent_dir << " : " << ec.message() << std::endl;
47 exit(1);
48 }
49 }
50
51 /* Open the output file for writing */
52 std::ofstream output_file(output_file_name, std::ofstream::out | std::ofstream::binary);
53 if (!output_file) {
54 std::cerr << "Error: Could not open output file " << output_file_name << std::endl;
55 input_file.close();
56 exit(1);
57 }
58
59 /* Open the output file for writing */
60 std::ofstream metadata_file(metadata_file_name, std::ofstream::out | std::ofstream::binary);
61 if (!output_file) {
62 std::cerr << "Error: Could not open output file " << metadata_file_name << std::endl;
63 input_file.close();
64 exit(1);
65 }
66
67 /* Open the output file for writing */
68 std::ofstream infos_file(infos_file_name, std::ofstream::out | std::ofstream::binary);
69 if (!output_file) {
70 std::cerr << "Error: Could not open output file " << infos_file_name << std::endl;
71 input_file.close();
72 exit(1);
73 }
74
75 std::stringstream buffer;
76 buffer << input_file.rdbuf();
77
78 int error = 0;
79
80 auto report_error =
81 [&](int err_line, int err_char, const std::string &line, const char *err_msg) {
82 std::cerr << input_file_name;
83 std::cerr << ':' << std::to_string(err_line) << ':' << std::to_string(err_char + 1);
84 std::cerr << ": error: " << err_msg << std::endl;
85 std::cerr << line << std::endl;
86 std::cerr << std::string(err_char, ' ') << '^' << std::endl;
87
88 error++;
89 };
90 std::string filename(output_file_name);
91 const bool is_info = filename.find("infos.hh") != std::string::npos;
92 const bool is_glsl = filename.find(".glsl") != std::string::npos;
93 const bool is_shared = filename.find("shared.h") != std::string::npos;
94 const bool is_library = is_glsl &&
95 (filename.find("gpu_shader_material_") != std::string::npos ||
96 filename.find("gpu_shader_common_") != std::string::npos ||
97 filename.find("gpu_shader_compositor_") != std::string::npos);
98
99 using Preprocessor = blender::gpu::shader::Preprocessor;
100 Preprocessor processor;
101
102 Preprocessor::SourceLanguage language = Preprocessor::language_from_filename(filename);
103
104 if (language == Preprocessor::SourceLanguage::GLSL) {
105 /* All build-time GLSL files should be considered blender-GLSL. */
106 language = Preprocessor::SourceLanguage::BLENDER_GLSL;
107 }
108
110 if (is_info) {
111 /* Until they are parsed properly. Nullify them. */
112 output_file << "";
113 }
114 else {
115 output_file << processor.process(
116 language, buffer.str(), input_file_name, is_library, is_shared, report_error, metadata);
117 }
118
119 /* TODO(fclem): Don't use regex for that. */
120 std::string metadata_function_name = "metadata_" +
121 std::regex_replace(
122 filename, std::regex(R"((?:.*)\/(.*))"), "$1");
123 std::replace(metadata_function_name.begin(), metadata_function_name.end(), '.', '_');
124
125 metadata_file << metadata.serialize(metadata_function_name);
126 if (is_info) {
127 /* Simple copy for now. But we need to rename all includes. */
128 std::string str = std::regex_replace(
129 buffer.str(), std::regex(R"(_infos.hh")"), "_infos.hh.info\"");
130 infos_file << str;
131 }
132
133 input_file.close();
134 output_file.close();
135 metadata_file.close();
136 infos_file.close();
137
138 return error;
139}
#define str(s)
#define main()
static void error(const char *str)
std::string serialize(const std::string &function_name) const