vengi/cmake/genshader.cmake

133 lines
6.0 KiB
CMake

function(read_shader_includes shaderpath include_dirs includes_list_out)
file(READ "${shaderpath}" contents)
string(REGEX REPLACE ";" "\\\\;" contents "${contents}")
string(REGEX REPLACE "\r" "" contents "${contents}")
string(REGEX REPLACE "\n" ";" contents "${contents}")
set(_local_list "${${includes_list_out}}")
foreach (line ${contents})
string(FIND "${line}" "#include" out)
if("${out}" EQUAL 0)
string(SUBSTRING ${line} 8 -1 include_file)
string(REPLACE " " "" include_file ${include_file})
string(REPLACE "\"" "" include_file ${include_file})
foreach (dir ${include_dirs})
if (EXISTS "${dir}/${include_file}")
list(APPEND _local_list "${dir}/${include_file}")
break()
endif()
endforeach()
endif()
endforeach()
list(REMOVE_DUPLICATES _local_list)
set(${includes_list_out} ${_local_list} PARENT_SCOPE)
endfunction()
function(shader_include_dir TARGET DEPENDENCY)
set(GEN_DIR ${GENERATE_DIR}/shaders/${DEPENDENCY}/)
target_include_directories(${TARGET} PUBLIC ${GEN_DIR})
endfunction()
function(generate_shaders TARGET)
set(files ${ARGN})
set(GEN_DIR ${GENERATE_DIR}/shaders/${TARGET}/)
set(_template_header ${ROOT_DIR}/src/tools/shadertool/ShaderTemplate.h.in)
set(_template_cpp ${ROOT_DIR}/src/tools/shadertool/ShaderTemplate.cpp.in)
set(_template_constants_header ${ROOT_DIR}/src/tools/shadertool/ShaderConstantsTemplate.h.in)
set(_template_ub ${ROOT_DIR}/src/tools/shadertool/UniformBufferTemplate.h.in)
file(MAKE_DIRECTORY ${GEN_DIR})
target_include_directories(${TARGET} PUBLIC ${GEN_DIR})
set(_headers)
set(_sources)
set(_constantsheaders)
add_custom_target(UpdateShaders${TARGET})
file(WRITE ${CMAKE_BINARY_DIR}/UpdateShaderFile${TARGET}.cmake "configure_file(\${SRC} \${DST} @ONLY)")
if (NOT DEFINED video_SOURCE_DIR)
message(FATAL_ERROR "video project not found")
endif()
set(SHADERTOOL_INCLUDE_DIRS)
set(_dir ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
list(APPEND SHADERTOOL_INCLUDE_DIRS "${_dir}")
set(DEPENDENCIES)
engine_resolve_dependencies(${TARGET} DEPENDENCIES)
foreach (D ${DEPENDENCIES})
if (EXISTS ${${D}_SOURCE_DIR}/shaders)
list(APPEND SHADERTOOL_INCLUDE_DIRS "${${D}_SOURCE_DIR}/shaders")
endif()
endforeach()
list(REMOVE_DUPLICATES SHADERTOOL_INCLUDE_DIRS)
set(SHADERTOOL_INCLUDE_DIRS_PARAM)
foreach (IDIR ${SHADERTOOL_INCLUDE_DIRS})
list(APPEND SHADERTOOL_INCLUDE_DIRS_PARAM "-I")
list(APPEND SHADERTOOL_INCLUDE_DIRS_PARAM "${IDIR}")
endforeach()
foreach (_file ${files})
set(_shaders)
if (EXISTS ${_dir}/${_file}.frag AND EXISTS ${_dir}/${_file}.vert)
list(APPEND _shaders ${_dir}/${_file}.frag ${_dir}/${_file}.vert)
if (EXISTS ${_dir}/${_file}.geom)
list(APPEND _shaders ${_dir}/${_file}.geom)
endif()
endif()
if (EXISTS ${_dir}/${_file}.comp)
list(APPEND _shaders ${_dir}/${_file}.comp)
endif()
if (_shaders)
set(_shadersdeps)
foreach (s ${_shaders})
read_shader_includes(${s} "${SHADERTOOL_INCLUDE_DIRS}" _shadersdeps)
endforeach()
convert_to_camel_case(${_file} _f)
set(_shaderheaderpath "${GEN_DIR}${_f}Shader.h")
set(_shadersourcepath "${GEN_DIR}${_f}Shader.cpp")
set(_shaderconstantheaderpath "${GEN_DIR}${_f}ShaderConstants.h")
# TODO We have to add the shader/ dirs of all dependencies to the include path
add_custom_command(
OUTPUT ${_shaderheaderpath}.in ${_shadersourcepath}.in ${_shaderconstantheaderpath}.in
IMPLICIT_DEPENDS C ${_shaders}
COMMENT "Validate ${_file}"
COMMAND ${CMAKE_COMMAND} -E env "APP_HOMEPATH=${CMAKE_CURRENT_BINARY_DIR}/" $<TARGET_FILE:shadertool> --glslang $<TARGET_FILE:glslangValidator> ${SHADERTOOL_INCLUDE_DIRS_PARAM} --postfix .in --shader ${_dir}/${_file} --constantstemplate ${_template_constants_header} --headertemplate ${_template_header} --sourcetemplate ${_template_cpp} --buffertemplate ${_template_ub} --sourcedir ${GEN_DIR}
DEPENDS shadertool ${_shaders} ${_shadersdeps} ${_template_header} ${_template_cpp} ${_template_ub} ${_template_constants_header}
)
list(APPEND _headers ${_shaderheaderpath})
list(APPEND _sources ${_shadersourcepath})
add_custom_command(
OUTPUT ${_shaderheaderpath}
COMMAND ${CMAKE_COMMAND} -D SRC=${_shaderheaderpath}.in -D DST=${_shaderheaderpath} -P ${CMAKE_BINARY_DIR}/UpdateShaderFile${TARGET}.cmake
DEPENDS ${_shaderheaderpath}.in
)
add_custom_command(
OUTPUT ${_shadersourcepath}
COMMAND ${CMAKE_COMMAND} -D SRC=${_shadersourcepath}.in -D DST=${_shadersourcepath} -P ${CMAKE_BINARY_DIR}/UpdateShaderFile${TARGET}.cmake
DEPENDS ${_shadersourcepath}.in
)
add_custom_command(
OUTPUT ${_shaderconstantheaderpath}
COMMAND ${CMAKE_COMMAND} -D SRC=${_shaderconstantheaderpath}.in -D DST=${_shaderconstantheaderpath} -P ${CMAKE_BINARY_DIR}/UpdateShaderFile${TARGET}.cmake
DEPENDS ${_shaderconstantheaderpath}.in
)
list(APPEND _constantsheaders ${_shaderconstantheaderpath})
else()
message(FATAL_ERROR "Could not find any shader files for ${_file} and target '${TARGET}'")
endif()
endforeach()
convert_to_camel_case(${TARGET} _filetarget)
set(_shadersheader ${GEN_DIR}/${_filetarget}Shaders.h)
file(WRITE ${_shadersheader}.in "#pragma once\n")
foreach (header_path ${_headers})
string(REPLACE "${GEN_DIR}" "" header "${header_path}")
file(APPEND ${_shadersheader}.in "#include \"${header}\"\n")
endforeach()
add_custom_target(GenerateShaderBindings${TARGET}
DEPENDS ${_headers} ${_constantsheaders}
COMMENT "Generate shader bindings for ${TARGET} in ${GEN_DIR}"
)
engine_mark_as_generated(${_headers} ${_shaderconstantheaderpath} ${_sources} ${_shadersheader})
target_sources(${TARGET} PRIVATE ${_sources} ${_headers} ${_constantsheaders} ${_shadersheader})
add_custom_target(GenerateShaderHeader${TARGET} ${CMAKE_COMMAND} -D SRC=${_shadersheader}.in -D DST=${_shadersheader} -P ${CMAKE_BINARY_DIR}/UpdateShaderFile${TARGET}.cmake)
add_dependencies(${TARGET} GenerateShaderHeader${TARGET} UpdateShaders${TARGET})
add_dependencies(GenerateShaderHeader${TARGET} GenerateShaderBindings${TARGET})
add_dependencies(codegen GenerateShaderHeader${TARGET} UpdateShaders${TARGET})
endfunction()