From 0bfd5e3536e2feb92b28bfcd4ce18296ba773f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Foucault?= Date: Fri, 4 Oct 2024 11:33:21 +0200 Subject: [PATCH] GPU: Add GLSL preprocessor This splits the GLSL processing into its own file as it will grow in complexity. Removes the complexity from `datatoc` and chain them during the build process. Rel #128076 Pull Request: https://projects.blender.org/blender/blender/pulls/128261 --- build_files/cmake/macros.cmake | 54 ++++--- intern/opencolorio/CMakeLists.txt | 2 +- intern/opensubdiv/CMakeLists.txt | 3 +- source/blender/CMakeLists.txt | 1 + .../realtime_compositor/CMakeLists.txt | 2 +- source/blender/datatoc/datatoc.cc | 135 +----------------- source/blender/draw/CMakeLists.txt | 2 +- source/blender/gpu/CMakeLists.txt | 4 +- .../gpu/glsl_preprocess/CMakeLists.txt | 13 ++ .../gpu/glsl_preprocess/glsl_preprocess.cc | 73 ++++++++++ 10 files changed, 128 insertions(+), 161 deletions(-) create mode 100644 source/blender/gpu/glsl_preprocess/CMakeLists.txt create mode 100644 source/blender/gpu/glsl_preprocess/glsl_preprocess.cc diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index efd5e19fa27..daf63d97ef0 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -974,7 +974,6 @@ function(delayed_do_install endfunction() # Same as above but generates the var name and output automatic. -# Takes optional: `STRIP_LEADING_C_COMMENTS` argument. function(data_to_c file_from file_to list_to_add @@ -985,19 +984,10 @@ function(data_to_c get_filename_component(_file_to_path ${file_to} PATH) - set(optional_args "") - foreach(f ${ARGN}) - if(f STREQUAL "STRIP_LEADING_C_COMMENTS") - set(optional_args "--options=strip_leading_c_comments") - else() - message(FATAL_ERROR "Unknown optional argument ${f} to \"data_to_c\"") - endif() - endforeach() - add_custom_command( OUTPUT ${file_to} COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} - COMMAND "$" ${file_from} ${file_to} ${optional_args} + COMMAND "$" ${file_from} ${file_to} DEPENDS ${file_from} datatoc) set_source_files_properties(${file_to} PROPERTIES GENERATED TRUE) @@ -1005,7 +995,6 @@ endfunction() # Same as above but generates the var name and output automatic. -# Takes optional: `STRIP_LEADING_C_COMMENTS` argument. function(data_to_c_simple file_from list_to_add @@ -1022,24 +1011,45 @@ function(data_to_c_simple get_filename_component(_file_to_path ${_file_to} PATH) - set(optional_args "") - foreach(f ${ARGN}) - if(f STREQUAL "STRIP_LEADING_C_COMMENTS") - set(optional_args "--options=strip_leading_c_comments") - else() - message(FATAL_ERROR "Unknown optional argument ${f} to \"data_to_c_simple\"") - endif() - endforeach() - add_custom_command( OUTPUT ${_file_to} COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} - COMMAND "$" ${_file_from} ${_file_to} ${optional_args} + COMMAND "$" ${_file_from} ${_file_to} DEPENDS ${_file_from} datatoc) set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE) endfunction() + +# Process glsl file and convert it to c +function(glsl_to_c + file_from + list_to_add + ) + + # remove ../'s + get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH) + get_filename_component(_file_tmp ${CMAKE_CURRENT_BINARY_DIR}/${file_from} REALPATH) + get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c REALPATH) + + list(APPEND ${list_to_add} ${_file_to}) + source_group(Generated FILES ${_file_to}) + list(APPEND ${list_to_add} ${file_from}) + set(${list_to_add} ${${list_to_add}} PARENT_SCOPE) + + get_filename_component(_file_to_path ${_file_to} PATH) + + add_custom_command( + OUTPUT ${_file_to} + COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path} + COMMAND "$" ${_file_from} ${_file_tmp} + COMMAND "$" ${_file_tmp} ${_file_to} + DEPENDS ${_file_from} datatoc glsl_preprocess) + + set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE) +endfunction() + + function(msgfmt_simple file_from list_to_add diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index 98b7d8946e0..f712bb42acf 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -66,7 +66,7 @@ if(WITH_OPENCOLORIO) set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) + glsl_to_c(${GLSL_FILE} GLSL_C) endforeach() blender_add_lib(bf_ocio_shaders "${GLSL_C}" "" "" "") diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 261da1d5399..7206d8d719c 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -85,10 +85,9 @@ if(WITH_OPENSUBDIV) add_definitions(-D_USE_MATH_DEFINES) endif() - data_to_c_simple( + glsl_to_c( internal/evaluator/shaders/glsl_compute_kernel.glsl SRC - STRIP_LEADING_C_COMMENTS ) else() list(APPEND SRC diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index c53faf2dfbc..636de9aa40f 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -137,6 +137,7 @@ set(SRC_DNA_OTHER_INC ) add_subdirectory(datatoc) +add_subdirectory(gpu/glsl_preprocess) add_subdirectory(editors) add_subdirectory(windowmanager) add_subdirectory(animrig) diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index d42e3f31b8e..d0d197a2884 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -280,7 +280,7 @@ set(GLSL_SRC set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) + glsl_to_c(${GLSL_FILE} GLSL_C) endforeach() blender_add_lib(bf_compositor_shaders "${GLSL_C}" "" "" "") diff --git a/source/blender/datatoc/datatoc.cc b/source/blender/datatoc/datatoc.cc index 265777eb2bd..a7eb38c3c99 100644 --- a/source/blender/datatoc/datatoc.cc +++ b/source/blender/datatoc/datatoc.cc @@ -31,95 +31,6 @@ static char *arg_basename(char *string) return std::max({string, lfslash, lbslash}); } -/** - * Detect leading C-style comments and seek the file to it's end, - * returning the number of bytes skipped and setting `r_newlines` - * or return zero and seek to the file start. - * - * The number of newlines is used so the number of lines matches - * the generated data, so any errors provide useful line numbers - * (this could be made optional, as there may be cases where it's not helpful). - */ -static int strip_leading_c_comment(FILE *fpin, int size, int *r_newlines) -{ - *r_newlines = 0; - if (size < 4) { - return 0; - } - - enum { - IS_SPACE = 1, - IS_COMMENT = 2, - IS_COMMENT_MAYBE_BEG = 3, - IS_COMMENT_MAYBE_END = 4, - } context = IS_SPACE; - - /* Last known valid offset. */ - int offset_checkpoint = 0; - int newlines_checkpoint = 0; - - int offset = 0; - int newlines = 0; - - while (offset < size) { - const char c_curr = getc(fpin); - offset += 1; - - if (context == IS_SPACE) { - if (c_curr == ' ' || c_curr == '\t' || c_curr == '\n') { - /* Pass. */ - } - else if (c_curr == '/') { - context = IS_COMMENT_MAYBE_BEG; - } - else { - /* Non-space and non-comment, exit. */ - break; - } - } - else if (context == IS_COMMENT) { - if (c_curr == '*') { - context = IS_COMMENT_MAYBE_END; - } - } - else if (context == IS_COMMENT_MAYBE_BEG) { - if (c_curr == '*') { - context = IS_COMMENT; - } - else { - /* Non-comment text, exit. */ - break; - } - } - else if (context == IS_COMMENT_MAYBE_END) { - if (c_curr == '/') { - context = IS_SPACE; - } - else if (c_curr == '*') { - /* Pass. */ - } - else { - context = IS_COMMENT; - } - } - - if (c_curr == '\n') { - newlines += 1; - } - - if (context == IS_SPACE) { - offset_checkpoint = offset; - newlines_checkpoint = newlines; - } - } - - if (offset != offset_checkpoint) { - fseek(fpin, offset_checkpoint, SEEK_SET); - } - *r_newlines = newlines_checkpoint; - return offset_checkpoint; -} - int main(int argc, char **argv) { FILE *fpin, *fpout; @@ -127,36 +38,11 @@ int main(int argc, char **argv) int i; int argv_len; - bool strip_leading_c_comments_test = false; - int leading_newlines = 0; - - if (argc < 2) { - printf( - "Usage: " - "datatoc [--options=strip_leading_c_comments]\n"); + if (argc != 3) { + printf("Usage: datatoc \n"); exit(1); } - if (argc > 3) { - const char *arg_extra = argv[3]; - const char *arg_transform = "--options="; - if (STRPREFIX(arg_extra, arg_transform)) { - /* We may want to have other options in the future. */ - const char *options = arg_extra + strlen(arg_transform); - if (strcmp(options, "strip_leading_c_comments") == 0) { - strip_leading_c_comments_test = true; - } - else { - printf("Unknown --options=<%s>\n", options); - exit(1); - } - } - else { - printf("Unknown argument <%s>, expected --options=[...] or none.\n", arg_extra); - exit(1); - } - } - fpin = fopen(argv[1], "rb"); if (!fpin) { printf("Unable to open input <%s>\n", argv[1]); @@ -169,11 +55,6 @@ int main(int argc, char **argv) size = ftell(fpin); fseek(fpin, 0L, SEEK_SET); - if (strip_leading_c_comments_test) { - const int size_offset = strip_leading_c_comment(fpin, size, &leading_newlines); - size -= size_offset; /* The comment is skipped, */ - } - if (argv[1][0] == '.') { argv[1]++; } @@ -201,19 +82,9 @@ int main(int argc, char **argv) fprintf(fpout, "extern const int datatoc_%s_size;\n", argv[1]); fprintf(fpout, "extern const char datatoc_%s[];\n\n", argv[1]); - fprintf(fpout, "const int datatoc_%s_size = %d;\n", argv[1], int(leading_newlines + size)); + fprintf(fpout, "const int datatoc_%s_size = %d;\n", argv[1], int(size)); fprintf(fpout, "const char datatoc_%s[] = {\n", argv[1]); - if (leading_newlines) { - while (leading_newlines--) { - if (leading_newlines % 32 == 31) { - fprintf(fpout, "\n"); - } - fprintf(fpout, "%3d,", '\n'); - } - fprintf(fpout, "\n"); - } - while (size--) { /* Even though this file is generated and doesn't need new-lines, * these files may be loaded by developers when looking up symbols. diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 2d53042d67f..740ddabceae 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -800,7 +800,7 @@ set(GLSL_SRC set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) + glsl_to_c(${GLSL_FILE} GLSL_C) endforeach() blender_add_lib(bf_draw_shaders "${GLSL_C}" "" "" "") diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 1136606fd87..b34c1363f98 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -698,13 +698,13 @@ if(WITH_METAL_BACKEND) set(MSL_C) foreach(MSL_FILE ${MSL_SRC}) - data_to_c_simple(${MSL_FILE} MSL_C STRIP_LEADING_C_COMMENTS) + glsl_to_c(${MSL_FILE} MSL_C) endforeach() endif() set(GLSL_C) foreach(GLSL_FILE ${GLSL_SRC}) - data_to_c_simple(${GLSL_FILE} GLSL_C STRIP_LEADING_C_COMMENTS) + glsl_to_c(${GLSL_FILE} GLSL_C) endforeach() set(SHADER_C) diff --git a/source/blender/gpu/glsl_preprocess/CMakeLists.txt b/source/blender/gpu/glsl_preprocess/CMakeLists.txt new file mode 100644 index 00000000000..ad3f33e25e2 --- /dev/null +++ b/source/blender/gpu/glsl_preprocess/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2023 Blender Authors +# +# SPDX-License-Identifier: GPL-2.0-or-later + + +# ----------------------------------------------------------------------------- +# Build `glsl_preprocess` executable. +set(SRC + glsl_preprocess.cc +) + +# `SRC_DNA_INC` is defined in the parent directory. +add_executable(glsl_preprocess ${SRC}) diff --git a/source/blender/gpu/glsl_preprocess/glsl_preprocess.cc b/source/blender/gpu/glsl_preprocess/glsl_preprocess.cc new file mode 100644 index 00000000000..f8e45fc2ceb --- /dev/null +++ b/source/blender/gpu/glsl_preprocess/glsl_preprocess.cc @@ -0,0 +1,73 @@ +/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup glsl_preprocess + */ + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + if (argc != 3) { + std::cerr << "Usage: glsl_preprocess " << std::endl; + exit(1); + } + + const char *input_file_name = argv[1]; + const char *output_file_name = argv[2]; + + /* Open the input file for reading */ + std::ifstream input_file(input_file_name); + if (!input_file) { + std::cerr << "Error: Could not open input file " << input_file_name << std::endl; + exit(1); + } + + /* Open the output file for writing */ + std::ofstream output_file(output_file_name); + if (!output_file) { + std::cerr << "Error: Could not open output file " << output_file_name << std::endl; + input_file.close(); + exit(1); + } + + bool first_comment = true; + bool inside_comment = false; + + std::string line; + while (std::getline(input_file, line)) { + /* Remove licence headers (first comment). */ + if (line.rfind("/*", 0) == 0 && first_comment) { + first_comment = false; + inside_comment = true; + } + + const bool skip_line = inside_comment; + + if (inside_comment && (line.find("*/") != std::string::npos)) { + inside_comment = false; + } + + if (skip_line) { + line = ""; + } +#if 0 /* Wait until we support this new syntax. */ + else if (line.rfind("#include ", 0) == 0 || line.rfind("#pragma once", 0) == 0) { + line[0] = line[1] = '/'; + } +#endif + + output_file << line << "\n"; + } + + input_file.close(); + output_file.close(); + + return 0; +}