diff --git a/CMakeModules/BuildSteps/CreateShaderCpp.cmake b/CMakeModules/BuildSteps/CreateShaderCpp.cmake index 4db64bd84b..b8a22f0086 100644 --- a/CMakeModules/BuildSteps/CreateShaderCpp.cmake +++ b/CMakeModules/BuildSteps/CreateShaderCpp.cmake @@ -1,54 +1,83 @@ -file( READ ${SOURCE} SOURCE_TEXT ) -file( SIZE ${SOURCE} SOURCE_FILESIZE ) +# +# Converts provided shader files into the gal namespaced shaders +# +# The goal here is to convert the contents of shaders in the source tree +# into strings to embed into the binaries rather than loading from disk. +# +# We convert the shaders to binary form in the header due limitations of string literal +# lengths and also because future development options such as moving to bgfx +# results in precompiled binary shaders we need to store +# +# This file is structured to be invoked from add_custom_command in order +# to have GENERATED marked output files that can be rebuilt on change. +# +# Required Arguments: +# SOURCE_FILE - Path to source shader file +# OUT_CPP_DIR - Destination path for cpp file +# OUT_HEADER_DIR - Destination path for header file +# OUT_CPP_FILENAME - cpp filename +# OUT_HEADER_FILENAME - header filename +# OUT_VAR_NAME - Name of variable containing shader to be created +# +# Parts taken from https://github.com/sivachandran/cmake-bin2h +# Copyright 2020 Sivachandran Paramasivam +# -set( MAX_BYTES_PER_LITERAL 16000 ) +# Function to wrap a given string into multiple lines at the given column position. +# Parameters: +# VARIABLE - The name of the CMake variable holding the string. +# AT_COLUMN - The column position at which string will be wrapped. +function(WRAP_STRING) + set(oneValueArgs VARIABLE AT_COLUMN) + cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) -math(EXPR NUMBER_LITERALS "${SOURCE_FILESIZE}/${MAX_BYTES_PER_LITERAL}") + string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) + math(EXPR offset "0") + + while(stringLength GREATER 0) + + if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) + math(EXPR length "${WRAP_STRING_AT_COLUMN}") + else() + math(EXPR length "${stringLength}") + endif() + + string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) + set(lines "${lines}\n${line}") + + math(EXPR stringLength "${stringLength} - ${length}") + math(EXPR offset "${offset} + ${length}") + endwhile() + + set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) +endfunction() -set( outCppTextStdString "std::string ${OUTVARNAME} = ") +file( READ ${SOURCE_FILE} _SOURCE_BINARY HEX ) +string(LENGTH ${_SOURCE_BINARY} _SOURCE_BINARY_LENGTH) + +set(SOURCE_BINARY "${_SOURCE_BINARY}00") # null terminate for the sake of it + +wrap_string(VARIABLE _SOURCE_BINARY AT_COLUMN 32) +math(EXPR _ARRAY_SIZE "${_SOURCE_BINARY_LENGTH} / 2") + + +# adds '0x' prefix and comma suffix before and after every byte respectively +string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " _ARRAY_VALUES ${_SOURCE_BINARY}) +# removes trailing comma +string(REGEX REPLACE ", $" "" _ARRAY_VALUES ${_ARRAY_VALUES}) + +set( outCppTextByteArray "unsigned char ${OUT_VAR_NAME}_bytes[] = { ${_ARRAY_VALUES} };") +set( outCppTextStdString "std::string ${OUT_VAR_NAME} = std::string( reinterpret_cast(${OUT_VAR_NAME}_bytes), ${_ARRAY_SIZE} ) ;") set( outCppText " #include -#include <${OUTHEADERFILE}> +#include <${OUT_HEADER_FILENAME}> namespace KIGFX { namespace BUILTIN_SHADERS { -") - - -MATH(EXPR LAST_LITERAL_ITER "${NUMBER_LITERALS}-1") - -foreach(LITERAL_ITER RANGE 0 ${NUMBER_LITERALS} 1) - set( CHUNK_TEXT "" ) - - MATH(EXPR TEXT_OFFSET "${LITERAL_ITER}*${MAX_BYTES_PER_LITERAL}") - - string(SUBSTRING "${SOURCE_TEXT}" ${TEXT_OFFSET} ${MAX_BYTES_PER_LITERAL} CHUNK_TEXT) - - - set( outCppText - " -${outCppText} - -const char ${OUTVARNAME}_p${LITERAL_ITER}[] = R\"SHADER_SOURCE( -${CHUNK_TEXT} -)SHADER_SOURCE\"; - - " ) - - set( outCppTextStdString "${outCppTextStdString} std::string(${OUTVARNAME}_p${LITERAL_ITER})") - if( ${LITERAL_ITER} LESS_EQUAL ${LAST_LITERAL_ITER}) - set( outCppTextStdString " ${outCppTextStdString} +") - endif() -endforeach() - -set( outCppTextStdString "${outCppTextStdString};") - -set( outCppText -" -${outCppText} +${outCppTextByteArray} ${outCppTextStdString} } @@ -56,7 +85,7 @@ ${outCppTextStdString} " ) file( - WRITE ${DESTINATION_SOURCE_DIR}/${OUTCPPFILE} + WRITE ${OUT_CPP_DIR}/${OUT_CPP_FILENAME} "${outCppText}" ) @@ -64,14 +93,14 @@ file( set( outHeaderText "namespace KIGFX { namespace BUILTIN_SHADERS { - extern std::string ${OUTVARNAME}; + extern std::string ${OUT_VAR_NAME}; } }" ) file( - WRITE ${DESTINATION_HEADER_DIR}/${OUTHEADERFILE} + WRITE ${OUT_HEADER_DIR}/${OUT_HEADER_FILENAME} "${outHeaderText}" ) -message(STATUS "Shader ${SOURCE} converted to ${DESTINATION_SOURCE_DIR}/${OUTCPPFILE}") \ No newline at end of file +message(STATUS "Shader ${SOURCE_FILE} converted to ${OUT_CPP_DIR}/${OUT_CPP_FILENAME}") \ No newline at end of file diff --git a/common/gal/CMakeLists.txt b/common/gal/CMakeLists.txt index 5a607b54df..8c6a330124 100644 --- a/common/gal/CMakeLists.txt +++ b/common/gal/CMakeLists.txt @@ -65,12 +65,12 @@ function( add_shader outTarget inFile shaderName ) OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${outCppName} ${CMAKE_BINARY_DIR}/include/gal/shaders/${outHeaderName} COMMAND ${CMAKE_COMMAND} - -DSOURCE="${CMAKE_CURRENT_SOURCE_DIR}/shaders/${inFile}" - -DDESTINATION_SOURCE_DIR="${CMAKE_CURRENT_BINARY_DIR}/" - -DDESTINATION_HEADER_DIR="${CMAKE_BINARY_DIR}/include/gal/shaders/" - -DOUTCPPFILE="${outCppName}" - -DOUTHEADERFILE="${outHeaderName}" - -DOUTVARNAME="${shaderName}" + -DSOURCE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/shaders/${inFile}" + -DOUT_CPP_DIR="${CMAKE_CURRENT_BINARY_DIR}/" + -DOUT_HEADER_DIR="${CMAKE_BINARY_DIR}/include/gal/shaders/" + -DOUT_CPP_FILENAME="${outCppName}" + -DOUT_HEADER_FILENAME="${outHeaderName}" + -DOUT_VAR_NAME="${shaderName}" -P ${CMAKE_MODULE_PATH}/BuildSteps/CreateShaderCpp.cmake DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/shaders/${inFile} ${CMAKE_MODULE_PATH}/BuildSteps/CreateShaderCpp.cmake