aboutsummaryrefslogtreecommitdiff
path: root/dxg/shaders/CMakeLists.txt
blob: c6ec6870cb30cd2313c7d9c9bdd567bbabea793d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
set(SHADER_MODEL "6_5")
set(DXC ${PROJECT_SOURCE_DIR}/../contrib/dxc_2025_07_14/bin/x64/dxc.exe)
set(SHADERS_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")

# Compile HLSL to binary DXIL.
#
# This defines a custom command so that the shader is compiled at cmake build
# instead of configure.
#
# hlsl_file:   "foo.hlsl"; just the file name, not the path.
# shader_type: "vs", "ps", "cs", etc.
# entry_point: "main", etc.
function(compile_shader hlsl_file shader_type entry_point dxil_file)
    #string(REPLACE ".hlsl" ".dxil" dxil_file ${hlsl_file})
    set(hlsl_path "${SHADERS_PATH}/${hlsl_file}")
    set(dxil_path "${BUILD_DIR}/${dxil_file}")
    set(target_profile "${shader_type}_${SHADER_MODEL}")
    message("COMPILING ${dxil_path}")
    message("DXC = ${DXC}")
    add_custom_command(
        OUTPUT ${dxil_path}
        COMMAND ${DXC} -T ${target_profile} -E ${entry_point} ${hlsl_path} -Fo ${dxil_path}
        WORKING_DIRECTORY ${BUILD_DIR}
        DEPENDS ${hlsl_path}
        COMMENT "Generating ${dxil_path}")
endfunction()

# Inline a binary file into C code.
# This is a workaround for the lack of C23 #embed in MSVC.
#
# identifier: Identifier to use for the global array that will contain the file,
#             the generated file names, and the cmake target.
# file_path:  Path to the binary file to embed.
#
# Reference: https://github.com/andoalon/embed-binaries
function(generate_c file_path identifier out_header_path out_source_path)
	file(READ "${file_path}" file_contents HEX)
	string(LENGTH "${file_contents}" file_contents_length)
	math(EXPR file_bytes "${file_contents_length} / 2")

	set(bytes_per_line 32)
    string(REPEAT "[0-9a-f]" ${bytes_per_line} column_pattern)
    string(REGEX REPLACE "(${column_pattern})" "\\1\n" code "${file_contents}")
    string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," code "${code}")

	set(declaration "const uint8_t ${identifier}[${file_bytes}]")

    string(APPEND header "#pragma once\n\n#include <stdint.h>\n\nextern ${declaration}\;\n")
    string(APPEND implementation "#include \"${identifier}.h\"\n\n${declaration} = {\n${code}}\;\n")

    file(WRITE "${BUILD_DIR}/${identifier}.h" ${header})
    file(WRITE "${BUILD_DIR}/${identifier}.c" ${implementation})
endfunction()

# Create a target that embeds the given DXIL file in a C header/source.
# Like compile_shader, this just adds the target so that the embedding is done
# at cmake build and not configure.
function(create_c_target dxil_file identifier)
    set(dxil_path "${BUILD_DIR}/${dxil_file}")
    string(REPLACE ".dxil" ".h" header_path ${dxil_path})
    string(REPLACE ".dxil" ".c" source_path ${dxil_path})
    add_custom_command(
        OUTPUT "${header_path}" "${source_path}"
        COMMAND ${CMAKE_COMMAND} -D dxil_path=${dxil_path} -D identifier=${identifier} -D out_header_path=${header_path} -D out_source_path=${source_path} -P ${CMAKE_CURRENT_LIST_FILE}
        WORKING_DIRECTORY ${BUILD_DIR}
        DEPENDS ${dxil_path}
        COMMENT "Generating ${source_path}"
    )
endfunction()

# Running in script mode.
# https://stackoverflow.com/questions/51427538/cmake-test-if-i-am-in-scripting-mode
#
# When running in script mode, we embed the binary DXIL into a generated C file.
if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE)
    foreach(variable "dxil_path" "identifier" "out_header_path" "out_source_path")
        if (NOT DEFINED ${variable})
            message(FATAL_ERROR "'${variable}' is not defined")
        endif()
    endforeach()
    generate_c("${dxil_path}" ${identifier} "${out_header_path}" "${out_source_path}")
else()
    compile_shader("imm.hlsl" "vs" "vs" "imm_vs.dxil")
    compile_shader("imm.hlsl" "ps" "ps" "imm_ps.dxil")

    create_c_target("imm_vs.dxil" "imm_vs")
    create_c_target("imm_ps.dxil" "imm_ps")

    add_library(shaders
        "${BUILD_DIR}/imm_ps.c"
        "${BUILD_DIR}/imm_ps.h"
        "${BUILD_DIR}/imm_vs.c"
        "${BUILD_DIR}/imm_vs.h")

    target_include_directories(shaders PUBLIC
        ${BUILD_DIR})
endif()