From c58df08b60da605a5b1e77367af783c064dd292d Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Thu, 22 Apr 2021 14:24:30 +0100 Subject: [PATCH] Replaced Shader Generator script with an executable for cross-platform support Change-Id: I203b30afb74ad69b8b7faed5271478c20d4445cc --- automated-tests/.gitignore | 2 +- .../src/dali-shader-generator/CMakeLists.txt | 49 +++ .../shader/fragment-shader.frag | 14 + .../dali-shader-generator/shader/shader-define.def | 2 + .../shader/vertex-shader.vert | 59 ++++ .../tct-dali-shader-generator-core.cpp | 6 + build/tizen/.gitignore | 3 +- build/tizen/CMakeLists.txt | 29 +- build/tizen/dali-scene-loader/CMakeLists.txt | 26 +- build/tizen/shader-generator.sh | 62 ---- dali-toolkit/internal/file.list | 1 - dali-toolkit/shader-generator/shader-generator.cpp | 373 +++++++++++++++++++++ packaging/dali-toolkit.spec | 1 + 13 files changed, 551 insertions(+), 76 deletions(-) create mode 100644 automated-tests/src/dali-shader-generator/CMakeLists.txt create mode 100644 automated-tests/src/dali-shader-generator/shader/fragment-shader.frag create mode 100644 automated-tests/src/dali-shader-generator/shader/shader-define.def create mode 100644 automated-tests/src/dali-shader-generator/shader/vertex-shader.vert create mode 100644 automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp delete mode 100755 build/tizen/shader-generator.sh create mode 100644 dali-toolkit/shader-generator/shader-generator.cpp diff --git a/automated-tests/.gitignore b/automated-tests/.gitignore index b12e784..17d54d9 100644 --- a/automated-tests/.gitignore +++ b/automated-tests/.gitignore @@ -2,5 +2,5 @@ build build.log tct*core.h -CMakeLists.txt +/CMakeLists.txt results_xml.* diff --git a/automated-tests/src/dali-shader-generator/CMakeLists.txt b/automated-tests/src/dali-shader-generator/CMakeLists.txt new file mode 100644 index 0000000..7057a36 --- /dev/null +++ b/automated-tests/src/dali-shader-generator/CMakeLists.txt @@ -0,0 +1,49 @@ +SET(PKG_NAME "dali-shader-generator") + +SET(EXEC_NAME "tct-${PKG_NAME}-core") + +PKG_CHECK_MODULES(${EXEC_NAME} REQUIRED + dali2-toolkit +) + +ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp) + +INSTALL(PROGRAMS ${EXEC_NAME} + DESTINATION ${BIN_DIR}/${EXEC_NAME} +) + +SET(SHADER_GENERATOR dali-shader-generator) +SET(GENERATED_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/shader/generated) +SET(SHADER_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/shader) + +ADD_CUSTOM_TARGET(test_help ALL COMMAND ${SHADER_GENERATOR} -h | grep "DALi Shader Generator" > /dev/null 2>&1 && echo "test_help Succeeded" VERBATIM) +ADD_CUSTOM_TARGET(test_no_params ALL COMMAND ${SHADER_GENERATOR} > /dev/null 2>&1 || echo "test_no_params Succeeded" VERBATIM) +ADD_CUSTOM_TARGET(test_version ALL COMMAND ${SHADER_GENERATOR} -v | wc -l | grep 1 > /dev/null 2>&1 && echo "test_version Succeeded" VERBATIM) +ADD_CUSTOM_TARGET(test_invalid_option ALL COMMAND ${SHADER_GENERATOR} --undeclared > /dev/null 2>&1 || echo "test_invalid_option Succeeded" VERBATIM) +ADD_CUSTOM_TARGET(test_too_many_params ALL COMMAND ${SHADER_GENERATOR} ONE TWO THREE > /dev/null 2>&1 || echo "test_too_many_params Succeeded" VERBATIM) +ADD_CUSTOM_TARGET(test_invalid_indir ALL COMMAND ${SHADER_GENERATOR} ONE TWO > /dev/null 2>&1 || echo "test_invalid_indir Succeeded" VERBATIM) +ADD_CUSTOM_TARGET( + test_check_built_in_created + ALL + COMMAND ${SHADER_GENERATOR} . ${GENERATED_FOLDER} | grep builtin-shader | wc -l | grep 2 > /dev/null 2>&1 && echo "test_check_built_in_created Succeeded" + VERBATIM) +ADD_CUSTOM_TARGET( + test_check_built_in_not_created + ALL + COMMAND ${SHADER_GENERATOR} --skip . ${GENERATED_FOLDER} | grep builtin-shader > /dev/null 2>&1 || echo "test_check_built_in_not_created Succeeded" + VERBATIM) +ADD_CUSTOM_TARGET( + test_frag_correct + ALL + COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_FRAGMENT_SHADER_FRAG" | grep "fragment-shader-frag.h" > /dev/null 2>&1 && echo "test_frag_correct Succeeded" + VERBATIM) +ADD_CUSTOM_TARGET( + test_vert_correct + ALL + COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_VERTEX_SHADER_VERT" | grep "vertex-shader-vert.h" > /dev/null 2>&1 && echo "test_vert_correct Succeeded" + VERBATIM) +ADD_CUSTOM_TARGET( + test_def_correct + ALL + COMMAND ${SHADER_GENERATOR} ${SHADER_FOLDER} ${GENERATED_FOLDER} | grep "SHADER_SHADER_DEFINE_DEF" | grep "shader-define-def.h" > /dev/null 2>&1 && echo "test_def_correct Succeeded" + VERBATIM) diff --git a/automated-tests/src/dali-shader-generator/shader/fragment-shader.frag b/automated-tests/src/dali-shader-generator/shader/fragment-shader.frag new file mode 100644 index 0000000..d9b3d5a --- /dev/null +++ b/automated-tests/src/dali-shader-generator/shader/fragment-shader.frag @@ -0,0 +1,14 @@ +varying mediump vec2 vTexCoord; + +uniform sampler2D sTexture; +uniform lowp vec4 uColor; + +void main() +{ + mediump vec4 color = texture2D( sTexture, vTexCoord ); + if(color.a <= 0.0001) + { + discard; + } + gl_FragColor = color * uColor; +} diff --git a/automated-tests/src/dali-shader-generator/shader/shader-define.def b/automated-tests/src/dali-shader-generator/shader/shader-define.def new file mode 100644 index 0000000..c6e148b --- /dev/null +++ b/automated-tests/src/dali-shader-generator/shader/shader-define.def @@ -0,0 +1,2 @@ +#version 300 es +precision highp float; diff --git a/automated-tests/src/dali-shader-generator/shader/vertex-shader.vert b/automated-tests/src/dali-shader-generator/shader/vertex-shader.vert new file mode 100644 index 0000000..e5cbaa7 --- /dev/null +++ b/automated-tests/src/dali-shader-generator/shader/vertex-shader.vert @@ -0,0 +1,59 @@ +attribute mediump vec2 aPosition; +uniform highp mat4 uMvpMatrix; +uniform highp vec3 uSize; + +uniform mediump vec2 start_point; +uniform mediump vec2 end_point; +uniform mediump vec2 rotate_center; +uniform mediump float rotate_angle; + +varying mediump vec2 vTexCoord; +varying mediump vec2 vStart; +varying mediump vec2 vEnd; + +vec2 rotate(vec2 x, vec2 c, float a) +{ + vec2 d = x - c; + vec2 r = vec2(d.x * cos(a) - d.y * sin(a), d.x * sin(a) + d.y * cos(a)); + +#ifdef UNIT_TYPE_BOUNDING_BOX + return r + c; +#endif + + /* UnitType::OBJECT_BOUNDING_BOX */ +#ifdef UNIT_TYPE_USER + return (r + c) / uSize.x; +#endif + /* UnitType::USER_SPACE*/ +} + +//Visual size and offset +uniform mediump vec2 offset; +uniform highp vec2 size; +uniform mediump vec4 offsetSizeMode; +uniform mediump vec2 origin; +uniform mediump vec2 anchorPoint; + +vec4 ComputeVertexPosition() +{ + vec2 visualSize = mix( uSize.xy*size, size, offsetSizeMode.zw ); + vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy ); + return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 ); +} + +void main() +{ + vStart = rotate( start_point, rotate_center, rotate_angle ); + vEnd = rotate( end_point, rotate_center, rotate_angle ); + gl_Position = uMvpMatrix * ComputeVertexPosition(); + +#ifdef UNIT_TYPE_BOUNDING_BOX + vTexCoord = vec2(aPosition.x, -aPosition.y); +#endif +/* UnitType::OBJECT_BOUNDING_BOX */ + +#ifdef UNIT_TYPE_USER + vTexCoord = vec2(aPosition.x, -aPosition.y * uSize.y / uSize.x); +#endif +/* UnitType::USER_SPACE*/ +} diff --git a/automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp b/automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp new file mode 100644 index 0000000..842fd98 --- /dev/null +++ b/automated-tests/src/dali-shader-generator/tct-dali-shader-generator-core.cpp @@ -0,0 +1,6 @@ +#include +int main(int argc, char * const argv[]) +{ + std::cout << "All tests run as part of Cmake build." << std::endl; + return 0; +} diff --git a/build/tizen/.gitignore b/build/tizen/.gitignore index e59a17f..2d253c9 100644 --- a/build/tizen/.gitignore +++ b/build/tizen/.gitignore @@ -2,4 +2,5 @@ build dali.info *.dylib dali2-*-config.cmake -libdali2-scene-loader.so* \ No newline at end of file +libdali2-scene-loader.so* +dali-shader-generator diff --git a/build/tizen/CMakeLists.txt b/build/tizen/CMakeLists.txt index 8be2625..906453d 100644 --- a/build/tizen/CMakeLists.txt +++ b/build/tizen/CMakeLists.txt @@ -286,13 +286,40 @@ ENDIF() # Generate source files for shaders SET(SHADER_SOURCE_DIR "${ROOT_SRC_DIR}/dali-toolkit/internal/graphics/shaders/") SET(SHADER_GENERATED_DIR "${ROOT_SRC_DIR}/dali-toolkit/internal/graphics/generated") -EXECUTE_PROCESS( COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/shader-generator.sh ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR}" ) SET(GENERATED_SHADER_DIR ${ROOT_SRC_DIR}/dali-toolkit/internal/graphics/) SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${GENERATED_SHADER_DIR}/generated/" "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h") +SET(SHADER_GENERATOR_NAME dali-shader-generator) +SET(SHADER_GENERATOR_SOURCES ${ROOT_SRC_DIR}/dali-toolkit/shader-generator/shader-generator.cpp) + +IF(NOT ANDROID) + ADD_EXECUTABLE(${SHADER_GENERATOR_NAME} ${SHADER_GENERATOR_SOURCES}) + INSTALL(TARGETS ${SHADER_GENERATOR_NAME} DESTINATION ${BINDIR}) +ELSE() + # Need to build dali-shader-generator using the host compiler, not the android cross-compiler so + # that it can be run on the host machine + OPTION(ANDROID_HOST_COMPILER "Provide the host compiler used by Android (Mandatory for Android") + IF(${ANDROID_HOST_COMPILER} STREQUAL "OFF") + MESSAGE(FATAL_ERROR "-DANDROID_HOST_COMPILER=\"Compiler\" must be set") + ENDIF() + + ADD_CUSTOM_COMMAND(OUTPUT ${SHADER_GENERATOR_NAME} + COMMAND ${ANDROID_HOST_COMPILER} -o ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} -std=c++17 ${SHADER_GENERATOR_SOURCES}) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + DESTINATION bin) +ENDIF() + +SET(BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp") +ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP} + DEPENDS ${SHADER_GENERATOR_NAME} + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR}) + +SET(SOURCES ${SOURCES} ${BUILT_IN_SHADER_GEN_CPP}) + IF( WIN32 OR APPLE ) SET( DALICORE_LDFLAGS "${DALICORE_LDFLAGS}" diff --git a/build/tizen/dali-scene-loader/CMakeLists.txt b/build/tizen/dali-scene-loader/CMakeLists.txt index ae7fea2..7789dda 100644 --- a/build/tizen/dali-scene-loader/CMakeLists.txt +++ b/build/tizen/dali-scene-loader/CMakeLists.txt @@ -77,6 +77,22 @@ include_directories(${repo_root_dir} ${prefix_include_dir} ) +# Generate source files for shaders +SET(SHADER_SOURCE_DIR "${scene_loader_dir}/internal/graphics/shaders/") +SET(SHADER_GENERATED_DIR "${scene_loader_dir}/internal/graphics/generated") + +SET(GENERATED_SHADER_DIR ${scene_loader_dir}/internal/graphics/) +SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${GENERATED_SHADER_DIR}/generated/" + "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h") + +SET( BUILT_IN_SHADER_GEN_CPP "${GENERATED_SHADER_DIR}/generated/builtin-shader-gen.cpp") +ADD_CUSTOM_COMMAND(OUTPUT ${BUILT_IN_SHADER_GEN_CPP} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME} + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../${SHADER_GENERATOR_NAME} ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR}) + +SET( scene_loader_src_files ${scene_loader_src_files} ${BUILT_IN_SHADER_GEN_CPP} ) + add_library(${name} SHARED ${scene_loader_src_files}) target_link_libraries(${name} ${DALICORE_LDFLAGS} ${DALIADAPTOR_LDFLAGS} @@ -87,16 +103,6 @@ if( ANDROID ) target_link_libraries(${name} log) endif() -# Generate source files for shaders -SET(SHADER_SOURCE_DIR "${scene_loader_dir}/internal/graphics/shaders/") -SET(SHADER_GENERATED_DIR "${scene_loader_dir}/internal/graphics/generated") -EXECUTE_PROCESS( COMMAND bash -c "${repo_root_dir}/build/tizen/shader-generator.sh ${SHADER_SOURCE_DIR} ${SHADER_GENERATED_DIR}" ) - -SET(GENERATED_SHADER_DIR ${scene_loader_dir}/internal/graphics/) -SET_PROPERTY(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - "${GENERATED_SHADER_DIR}/generated/" - "${GENERATED_SHADER_DIR}/builtin-shader-extern-gen.h") - IF( INSTALL_CMAKE_MODULES ) SET_TARGET_PROPERTIES( ${name} PROPERTIES diff --git a/build/tizen/shader-generator.sh b/build/tizen/shader-generator.sh deleted file mode 100755 index 7b6b2fc..0000000 --- a/build/tizen/shader-generator.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -indir=$1 -outdir=$2 - -mkdir -p $outdir - -if [ ! -e $indir ] ; then - echo "Error! "$indir" not found!" - exit 0 -fi - -cd $indir -all_shaders=$(ls -1 *.{vert,frag,def}) -cd $OLDPWD - -# Generate one header file per shader which is defined as a const std::string_view -for name in $all_shaders ; do - echo "Generating header files for $name..." - varname=$(echo "SHADER_$name" | tr [a-z] [A-Z] | sed -e 's/-/_/g;s/\./_/g;') - - newname=$(echo ${name} | sed -e 's/\./-/;')".h" - echo Writing $newname - - shader_fullpath=$(echo ${indir})$name - - header_name="${varname}_GEN_H" - echo "const std::string_view" "$varname""{" > $outdir/$newname - cat $shader_fullpath | sed -e 's/^..*$/"&\\n"/' >> $outdir/$newname - echo "};" >> $outdir/$newname -done - -# Generate one cpp file that includes all the previously generated string_views for shaders -echo "Generating cpp file..." -echo -e "#include \"../builtin-shader-extern-gen.h\"\n" > $outdir/builtin-shader-gen.cpp - -varnames= -for name in $all_shaders ; do - varname=$(echo "SHADER_$name" | tr [a-z] [A-Z] | sed -e 's/-/_/g;s/\./_/g;') - newname=$(echo ${name} | sed -e 's/\./-/;')".h" - varnames="${varnames} $varname" - echo "#include \"$newname\"" >> $outdir/builtin-shader-gen.cpp -done - -# Generate one header file that defines all the shader string_views as extern variables -echo "Generating extern header file ( for external use )..." -echo "#ifndef GRAPHICS_BUILTIN_SHADER_EXTERN_GEN_H" > $outdir/../builtin-shader-extern-gen.h -echo -e "#define GRAPHICS_BUILTIN_SHADER_EXTERN_GEN_H\n" >> $outdir/../builtin-shader-extern-gen.h - -echo "#include " >> $outdir/../builtin-shader-extern-gen.h -echo "" >> $outdir/../builtin-shader-extern-gen.h - -for name in $all_shaders ; do - varname=$(echo "SHADER_$name" | tr [a-z] [A-Z] | sed -e 's/-/_/g;s/\./_/g;') - newname=$(echo ${name} | sed -e 's/\./-/;')".h" - echo "extern const std::string_view $varname;" >> $outdir/../builtin-shader-extern-gen.h -done -cat >> $outdir/../builtin-shader-extern-gen.h << EOF - -#endif // GRAPHICS_BUILTIN_SHADER_EXTERN_GEN_H -EOF - diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index ede26c1..35ac87b 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -182,7 +182,6 @@ SET( toolkit_src_files ${toolkit_src_dir}/transition-effects/cube-transition-wave-effect-impl.cpp ${toolkit_src_dir}/text/xhtml-entities.cpp ${toolkit_src_dir}/drag-drop-detector/drag-and-drop-detector-impl.cpp - ${toolkit_src_dir}/graphics/generated/builtin-shader-gen.cpp ) SET( SOURCES ${SOURCES} diff --git a/dali-toolkit/shader-generator/shader-generator.cpp b/dali-toolkit/shader-generator/shader-generator.cpp new file mode 100644 index 0000000..d386fb3 --- /dev/null +++ b/dali-toolkit/shader-generator/shader-generator.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +namespace fs = filesystem; + +namespace +{ +/////////////////////////////////////////////////////////////////////////////////////////////////// +string PROGRAM_NAME; ///< We set the program name on this global early on for use in Usage. +string_view VERSION = "1.0.0"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Supported extensions for the files in the input directory. +// clang-format off +constexpr string_view SHADER_EXTENSIONS[] = +{ + ".vert", + ".frag", + ".def" +}; +// clang-format on + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Function & variable to retrieve the size of the extension with the largest string size. +constexpr auto GetShaderExtensionMaxSize() +{ + auto maxSize = 0u; + for(const auto& extension : SHADER_EXTENSIONS) + { + if(extension.size() > maxSize) + { + maxSize = extension.size(); + } + } + return maxSize; +} +constexpr const int SHADER_MAX_EXTENSION_SIZE(GetShaderExtensionMaxSize()); + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Prints out the Usage to standard output. +void Usage() +{ + cout << "Usage: " << PROGRAM_NAME << " [OPTIONS] [IN_DIR] [OUT_DIR]" << endl; + cout << " IN_DIR: Input Directory which has all the shader files." << endl; + cout << " Supported extensions:"; + string extensions; + for(const auto& extension : SHADER_EXTENSIONS) + { + extensions = extensions + " \"" + string(extension) + "\","; + } + extensions.pop_back(); // Remove the last comma. + cout << extensions << "." << endl; + cout << " OUT_DIR: Directory where the generated shader source code will be outputted to." << endl; + cout << " This directory will be created if it does not exist." << endl; + cout << " Any existing files of the same name in the directory will be overwritten." << endl; + cout << " Options: " << endl; + cout << " -s|--skip Skips the generation of the built-in header and source files" << endl; + cout << " -v|--version Prints out the version" << endl; + cout << " -h|--help Help" << endl; + cout << " NOTE: The options can be placed after the IN_DIR & OUT_DIR as well" << endl; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Uses the filename to generate the shader variable name to use in source code. +/// @param[in] filename The filename of the shader (including the extension) +/// @return The shader variable name +string GetShaderVariableName(const string& filename) +{ + string shaderVariableName("SHADER_" + filename); + for_each( + shaderVariableName.begin(), + shaderVariableName.end(), + [](char& character) { + switch(character) + { + case '-': + case '.': + { + character = '_'; + break; + } + + default: + { + character = ::toupper(character); + break; + } + } + }); + return shaderVariableName; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Uses the ourDir & filename to generate the path of the output header file for the shader. +/// @param[in] outDir The directory where the readable shaders will be outputted to +/// @param[in] filename The filename of the shader (including the extension) +/// @return The path to the output file +fs::path GetShaderOutputFilePath(fs::path& outDir, const string& filename) +{ + string outFilename(filename); + replace(outFilename.end() - SHADER_MAX_EXTENSION_SIZE, outFilename.end(), '.', '-'); + outFilename = outDir.string() + "/" + outFilename + ".h"; + return outFilename; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Generates the header file from the input shader file. +/// @param[in] shaderFile The full path of the input shader file +/// @param[in] shaderVariableName The variable name to use for the string_view +/// @param[in] outFilePath The full path to the output file +void GenerateHeaderFile( + ifstream& shaderFile, + const string& shaderVariableName, + const fs::path& outFilePath) +{ + cout << " Generating \"" << shaderVariableName << "\" in " << outFilePath.filename(); + ofstream outFile(outFilePath); + if(outFile.is_open()) + { + outFile << "#pragma once" << endl + << endl; + outFile << "const std::string_view " << shaderVariableName << endl; + outFile << "{" << endl; + string line; + while(getline(shaderFile, line)) + { + outFile << "\"" << line << "\\n\"" << endl; + } + outFile << "};" << endl; + cout << " [OK]" << endl; + } + else + { + cout << " [FAIL]" << endl; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// If required, this accumulates data about all the shaders & generates the built-in cpp & header +class BuiltInFilesGenerator +{ +public: + /// Constructor + /// @param[in] outDir The path to the output directory + BuiltInFilesGenerator(const fs::path& outDir) + : mHeaderFilePath(outDir.string() + "/../" + string(HEADER_FILE_NAME)), + mSourceFilePath(outDir.string() + "/" + string(SOURCE_FILE_NAME)) + { + } + + /// Default destructor + ~BuiltInFilesGenerator() = default; + + /// Adds the variable and the header file name to the appropriate vectors. + /// @param[in] variableName The string_view variable name used + /// @param[in] headerFileName The name of the header used + void Add(string&& variableName, const std::string& headerFilename) + { + mVariableNames.emplace_back(variableName); + mHeaderFileNames.emplace_back(headerFilename); + } + + // Generates the built in files. + void Generate() + { + GenerateFile( + mVariableNames, + mHeaderFilePath, + "#pragma once\n\n#include \n\n", + "extern const std::string_view ", + ";"); + + GenerateFile( + mHeaderFileNames, + mSourceFilePath, + "#include \"../" + string(HEADER_FILE_NAME) + "\"\n\n", + "#include \"", + "\""); + } + +private: + /// Generates the required file. + /// @param[in] strings A reference to the vector to parse + /// @param[in] filePath Outputs the data to this file + /// @param[in] header Puts this before parsing any of the vector + /// @param[in] before For each string, puts this string before it on every line + /// @param[in] after For each string, puts this string after it on every line + void GenerateFile( + vector& strings, + const string& filePath, + const string_view header, + const string_view before, + const string_view after) + { + sort(strings.begin(), strings.end()); + cout << " Generating \"" << filePath << "\""; + ofstream outFile(filePath); + if(outFile) + { + outFile << header; + for(auto& current : strings) + { + outFile << before << current << after << endl; + } + cout << " [OK]" << endl; + } + else + { + cout << " [FAIL]" << endl; + } + } + + constexpr static string_view HEADER_FILE_NAME = "builtin-shader-extern-gen.h"; + constexpr static string_view SOURCE_FILE_NAME = "builtin-shader-gen.cpp"; + + const string mHeaderFilePath; ///< Path to the header file to generate + const string mSourceFilePath; ///< Path to the source file to generate + vector mVariableNames; ///< Holds all the variable names added through Add + vector mHeaderFileNames; ///< Holds all the header file names added through Add +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// Generates the header files from the shaders in the input directory & built-in files if reqruied. +/// +/// @param[in] inDir The directory where all the input shader source is +/// @param[in] outDir The directory where the readable shaders will be outputted to +/// @param[in] generateBuiltInFiles If true, we generate the built-in files as well +/// @return 0 if successful, 1 if failure +int GenerateShaderSources(fs::path inDir, fs::path outDir, const bool generateBuiltInFiles) +{ + if(!fs::is_directory(inDir)) + { + cerr << "ERROR: " << inDir << " is not a valid directory" << endl; + Usage(); + return 1; + } + + try + { + fs::create_directories(outDir); + } + catch(...) + { + cerr << "ERROR: Unable to create directory " << outDir << endl; + return 1; + } + + cout << "====================================================================" << endl; + cout << "Shader Input Directory: " << inDir << endl; + cout << "Shader Output Directory: " << outDir << endl; + cout << "====================================================================" << endl; + + BuiltInFilesGenerator generator(outDir); + + for(auto& file : fs::directory_iterator(inDir)) + { + if(file.is_regular_file()) + { + for(const auto& extension : SHADER_EXTENSIONS) + { + if(file.path().extension() == extension) + { + const fs::path& path(file.path()); + const string filename(path.filename().string()); + string shaderVariableName(GetShaderVariableName(filename)); + ifstream shaderFile(path); + if(shaderFile.is_open()) + { + fs::path outFilePath(GetShaderOutputFilePath(outDir, filename)); + GenerateHeaderFile(shaderFile, shaderVariableName, outFilePath); + generator.Add(std::move(shaderVariableName), outFilePath.filename().string()); + } + break; + } + } + } + } + + if(generateBuiltInFiles) + { + generator.Generate(); + } + + cout << "====================================================================" << endl; + return 0; +} + +} // unnamed namespace + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// MAIN. +int main(int argc, char* argv[]) +{ + PROGRAM_NAME = argv[0]; + + bool generateBuiltInFiles = true; + + string inDir; + string outDir; + + for(auto i = 1; i < argc; ++i) + { + string option(argv[i]); + if(option == "--skip" || option == "-s") + { + generateBuiltInFiles = false; + } + else if(option == "--help" || option == "-h") + { + cout << "DALi Shader Generator v" << VERSION << endl + << endl; + Usage(); + return 0; + } + else if(option == "--version" || option == "-v") + { + cout << VERSION << endl; + return 0; + } + else if(*option.begin() == '-') + { + cerr << "ERROR: " << option << " is not a supported option" << endl; + Usage(); + return 1; + } + else if(inDir.empty()) + { + inDir = option; + } + else if(outDir.empty()) + { + outDir = option; + } + else if(inDir.size() && outDir.size()) + { + cerr << "ERROR: Too many options" << endl; + Usage(); + return 1; + } + } + + if(inDir.empty() || outDir.empty()) + { + cerr << "ERROR: Both IN_DIR & OUT_DIR not provided" << endl; + Usage(); + return 1; + } + + return GenerateShaderSources(inDir, outDir, generateBuiltInFiles); +} diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index 7d476a9..ba6c2b6 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -379,6 +379,7 @@ esac %defattr(-,root,root,-) %{dev_include_path}/dali-toolkit/* %{_libdir}/pkgconfig/dali2-toolkit.pc +%{_bindir}/dali-shader-generator %files resources_360x360 %manifest dali-toolkit-resources.manifest -- 2.7.4