Updated spirv-cross.

This commit is contained in:
Бранимир Караџић 2019-03-09 10:20:48 -08:00
parent 2044efc6ca
commit 1f69e5e5d9
31 changed files with 5005 additions and 623 deletions

View File

@ -13,168 +13,341 @@
# limitations under the License. # limitations under the License.
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
project(SPIRV-Cross) set(CMAKE_CXX_STANDARD 11)
project(SPIRV-Cross LANGUAGES CXX C)
enable_testing() enable_testing()
option(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS "Instead of throwing exceptions assert" OFF) option(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS "Instead of throwing exceptions assert" OFF)
option(SPIRV_CROSS_SHARED "Build the C API as a single shared library." OFF)
option(SPIRV_CROSS_STATIC "Build the C and C++ API as static libraries." ON)
option(SPIRV_CROSS_CLI "Build the CLI binary. Requires SPIRV_CROSS_STATIC." ON)
option(SPIRV_CROSS_ENABLE_TESTS "Enable SPIRV-Cross tests." ON)
option(SPIRV_CROSS_SANITIZE_ADDRESS "Sanitize address" OFF)
option(SPIRV_CROSS_SANITIZE_MEMORY "Sanitize memory" OFF)
option(SPIRV_CROSS_SANITIZE_THREADS "Sanitize threads" OFF)
option(SPIRV_CROSS_SANITIZE_UNDEFINED "Sanitize undefined" OFF)
if(${CMAKE_GENERATOR} MATCHES "Makefile") if(${CMAKE_GENERATOR} MATCHES "Makefile")
if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
message(FATAL_ERROR "Build out of tree to avoid overwriting Makefile") message(FATAL_ERROR "Build out of tree to avoid overwriting Makefile")
endif() endif()
endif() endif()
set(spirv-compiler-options "") set(spirv-compiler-options "")
set(spirv-compiler-defines "") set(spirv-compiler-defines "")
set(spirv-cross-link-flags "")
if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
endif() endif()
# To specify special debug or optimization options, use if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang"))
# -DCMAKE_CXX_COMPILE_FLAGS set(spirv-compiler-options ${spirv-compiler-options} -Wall -Wextra -Werror -Wshadow)
# However, we require the C++11 dialect.
if (NOT "${MSVC}")
set(spirv-compiler-options ${spirv-compiler-options} -std=c++11 -Wall -Wextra -Werror -Wshadow)
set(spirv-compiler-defines ${spirv-compiler-defines} __STDC_LIMIT_MACROS)
if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) if (SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
set(spirv-compiler-options ${spirv-compiler-options} -fno-exceptions) set(spirv-compiler-options ${spirv-compiler-options} -fno-exceptions)
endif() endif()
if (SPIRV_CROSS_SANITIZE_ADDRESS)
set(spirv-compiler-options ${spirv-compiler-options} -fsanitize=address)
set(spirv-cross-link-flags "${spirv-cross-link-flags} -fsanitize=address")
endif()
if (SPIRV_CROSS_SANITIZE_UNDEFINED)
set(spirv-compiler-options ${spirv-compiler-options} -fsanitize=undefined)
set(spirv-cross-link-flags "${spirv-cross-link-flags} -fsanitize=undefined")
endif()
if (SPIRV_CROSS_SANITIZE_MEMORY)
set(spirv-compiler-options ${spirv-compiler-options} -fsanitize=memory)
set(spirv-cross-link-flags "${spirv-cross-link-flags} -fsanitize=memory")
endif()
if (SPIRV_CROSS_SANITIZE_THREADS)
set(spirv-compiler-options ${spirv-compiler-options} -fsanitize=thread)
set(spirv-cross-link-flags "${spirv-cross-link-flags} -fsanitize=thread")
endif()
elseif (MSVC)
set(spirv-compiler-options ${spirv-compiler-options} /wd4267)
endif() endif()
macro(extract_headers out_abs file_list) macro(extract_headers out_abs file_list)
set(${out_abs}) # absolute paths set(${out_abs}) # absolute paths
foreach(_a ${file_list}) foreach(_a ${file_list})
# get_filename_component only returns the longest extension, so use a regex # get_filename_component only returns the longest extension, so use a regex
string(REGEX REPLACE ".*\\.(h|hpp)" "\\1" ext ${_a}) string(REGEX REPLACE ".*\\.(h|hpp)" "\\1" ext ${_a})
if(("${ext}" STREQUAL "h") OR ("${ext}" STREQUAL "hpp"))
list(APPEND ${out_abs} "${_a}") # For shared library, we are only interested in the C header.
endif() if (SPIRV_CROSS_STATIC)
endforeach() if(("${ext}" STREQUAL "h") OR ("${ext}" STREQUAL "hpp"))
list(APPEND ${out_abs} "${_a}")
endif()
else()
if("${ext}" STREQUAL "h")
list(APPEND ${out_abs} "${_a}")
endif()
endif()
endforeach()
endmacro() endmacro()
macro(spirv_cross_add_library name config_name) macro(spirv_cross_add_library name config_name)
add_library(${name} ${ARGN}) add_library(${name} ${ARGN})
extract_headers(hdrs "${ARGN}") extract_headers(hdrs "${ARGN}")
target_include_directories(${name} PUBLIC target_include_directories(${name} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/spirv_cross>) $<INSTALL_INTERFACE:include/spirv_cross>)
set_target_properties(${name} PROPERTIES set_target_properties(${name} PROPERTIES
PUBLIC_HEADERS "${hdrs}") PUBLIC_HEADERS "${hdrs}")
target_compile_options(${name} PRIVATE ${spirv-compiler-options}) target_compile_options(${name} PRIVATE ${spirv-compiler-options})
target_compile_definitions(${name} PRIVATE ${spirv-compiler-defines}) target_compile_definitions(${name} PRIVATE ${spirv-compiler-defines})
install(TARGETS ${name} install(TARGETS ${name}
EXPORT ${config_name}Config EXPORT ${config_name}Config
RUNTIME DESTINATION bin RUNTIME DESTINATION bin
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
PUBLIC_HEADER DESTINATION include/spirv_cross) PUBLIC_HEADER DESTINATION include/spirv_cross)
install(FILES ${hdrs} DESTINATION include/spirv_cross) install(FILES ${hdrs} DESTINATION include/spirv_cross)
install(EXPORT ${config_name}Config DESTINATION share/${config_name}/cmake) install(EXPORT ${config_name}Config DESTINATION share/${config_name}/cmake)
export(TARGETS ${name} FILE ${config_name}Config.cmake) export(TARGETS ${name} FILE ${config_name}Config.cmake)
endmacro() endmacro()
set(spirv-cross-core-sources
${CMAKE_CURRENT_SOURCE_DIR}/GLSL.std.450.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_common.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_parser.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_parser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_parsed_ir.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_parsed_ir.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cfg.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cfg.cpp)
spirv_cross_add_library(spirv-cross-core spirv_cross_core STATIC set(spirv-cross-c-sources
${CMAKE_CURRENT_SOURCE_DIR}/GLSL.std.450.h spirv.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_common.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_c.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_c.h)
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_parser.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_parser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_parsed_ir.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_parsed_ir.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cfg.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cfg.cpp)
spirv_cross_add_library(spirv-cross-glsl spirv_cross_glsl STATIC set(spirv-cross-glsl-sources
${CMAKE_CURRENT_SOURCE_DIR}/spirv_glsl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_glsl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_glsl.hpp) ${CMAKE_CURRENT_SOURCE_DIR}/spirv_glsl.hpp)
spirv_cross_add_library(spirv-cross-cpp spirv_cross_cpp STATIC set(spirv-cross-cpp-sources
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cpp.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cpp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cpp.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cpp.hpp)
spirv_cross_add_library(spirv-cross-reflect spirv_cross_reflect STATIC set(spirv-cross-msl-sources
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_msl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/spirv_msl.hpp)
spirv_cross_add_library(spirv-cross-msl spirv_cross_msl STATIC set(spirv-cross-hlsl-sources
${CMAKE_CURRENT_SOURCE_DIR}/spirv_msl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_hlsl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_msl.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/spirv_hlsl.hpp)
spirv_cross_add_library(spirv-cross-hlsl spirv_cross_hlsl STATIC set(spirv-cross-reflect-sources
${CMAKE_CURRENT_SOURCE_DIR}/spirv_hlsl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_hlsl.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.hpp)
spirv_cross_add_library(spirv-cross-util spirv_cross_util STATIC set(spirv-cross-util-sources
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_util.hpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_util.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_util.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_util.hpp)
add_executable(spirv-cross main.cpp) if (SPIRV_CROSS_STATIC)
target_compile_options(spirv-cross PRIVATE ${spirv-compiler-options}) spirv_cross_add_library(spirv-cross-core spirv_cross_core STATIC
target_compile_definitions(spirv-cross PRIVATE ${spirv-compiler-defines}) ${spirv-cross-core-sources})
install(TARGETS spirv-cross RUNTIME DESTINATION bin) spirv_cross_add_library(spirv-cross-c spirv_cross_c STATIC
target_link_libraries(spirv-cross spirv-cross-glsl spirv-cross-hlsl spirv-cross-cpp spirv-cross-reflect spirv-cross-msl spirv-cross-util spirv-cross-core) ${spirv-cross-c-sources})
target_link_libraries(spirv-cross-util spirv-cross-core)
target_link_libraries(spirv-cross-glsl spirv-cross-core)
target_link_libraries(spirv-cross-msl spirv-cross-glsl)
target_link_libraries(spirv-cross-hlsl spirv-cross-glsl)
target_link_libraries(spirv-cross-cpp spirv-cross-glsl)
# Set up tests, using only the simplest modes of the test_shaders spirv_cross_add_library(spirv-cross-glsl spirv_cross_glsl STATIC
# script. You have to invoke the script manually to: ${spirv-cross-glsl-sources})
# - Update the reference files
# - Get cycle counts from malisc spirv_cross_add_library(spirv-cross-cpp spirv_cross_cpp STATIC
# - Keep failing outputs ${spirv-cross-cpp-sources})
find_package(PythonInterp)
if (${PYTHONINTERP_FOUND}) spirv_cross_add_library(spirv-cross-reflect spirv_cross_reflect STATIC
if (${PYTHON_VERSION_MAJOR} GREATER 2) ${spirv-cross-reflect-sources})
add_test(NAME spirv-cross-test
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel spirv_cross_add_library(spirv-cross-msl spirv_cross_msl STATIC
${CMAKE_CURRENT_SOURCE_DIR}/shaders ${spirv-cross-msl-sources})
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-no-opt spirv_cross_add_library(spirv-cross-hlsl spirv_cross_hlsl STATIC
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel ${spirv-cross-hlsl-sources})
${CMAKE_CURRENT_SOURCE_DIR}/shaders-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) spirv_cross_add_library(spirv-cross-util spirv_cross_util STATIC
add_test(NAME spirv-cross-test-metal ${spirv-cross-util-sources})
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --parallel
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl target_link_libraries(spirv-cross-util PRIVATE spirv-cross-core)
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) target_link_libraries(spirv-cross-glsl PRIVATE spirv-cross-core)
add_test(NAME spirv-cross-test-metal-no-opt target_link_libraries(spirv-cross-msl PRIVATE spirv-cross-glsl)
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --parallel target_link_libraries(spirv-cross-hlsl PRIVATE spirv-cross-glsl)
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl-no-opt target_link_libraries(spirv-cross-cpp PRIVATE spirv-cross-glsl)
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) target_link_libraries(spirv-cross-c PRIVATE
add_test(NAME spirv-cross-test-hlsl spirv-cross-core
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --parallel spirv-cross-glsl
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl spirv-cross-hlsl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) spirv-cross-msl
add_test(NAME spirv-cross-test-hlsl-no-opt spirv-cross-cpp
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --parallel spirv-cross-reflect)
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl-no-opt endif()
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-opt if (SPIRV_CROSS_SHARED)
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --opt --parallel set(spirv-cross-abi-major 0)
${CMAKE_CURRENT_SOURCE_DIR}/shaders set(spirv-cross-abi-minor 1)
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) set(spirv-cross-abi-patch 0)
add_test(NAME spirv-cross-test-metal-opt set(SPIRV_CROSS_VERSION ${spirv-cross-abi-major}.${spirv-cross-abi-minor}.${spirv-cross-abi-patch})
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --opt --parallel set(SPIRV_CROSS_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib)
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl set(SPIRV_CROSS_INSTALL_INC_DIR ${CMAKE_INSTALL_PREFIX}/include/spirv_cross)
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) configure_file(
add_test(NAME spirv-cross-test-hlsl-opt ${CMAKE_CURRENT_SOURCE_DIR}/pkg-config/spirv-cross-c-shared.pc.in
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --opt --parallel ${CMAKE_CURRENT_BINARY_DIR}/spirv-cross-c-shared.pc @ONLY)
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl install(FILES ${CMAKE_CURRENT_BINARY_DIR}/spirv-cross-c-shared.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pkgconfig)
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-reflection spirv_cross_add_library(spirv-cross-c-shared spirv_cross_c_shared SHARED
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --reflect --parallel ${spirv-cross-core-sources}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-reflection ${spirv-cross-glsl-sources}
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>) ${spirv-cross-cpp-sources}
endif() ${spirv-cross-reflect-sources}
else() ${spirv-cross-msl-sources}
message(WARNING "Testing disabled. Could not find python3. If you have python3 installed try running " ${spirv-cross-hlsl-sources}
"cmake with -DPYTHON_EXECUTABLE:FILEPATH=/path/to/python3 to help it find the executable") ${spirv-cross-c-sources})
if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang"))
# Only export the C API.
target_compile_options(spirv-cross-c-shared PRIVATE -fvisibility=hidden)
if (NOT APPLE)
set_target_properties(spirv-cross-c-shared PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}")
endif()
endif()
target_compile_definitions(spirv-cross-c-shared PRIVATE SPVC_EXPORT_SYMBOLS)
set_target_properties(spirv-cross-c-shared PROPERTIES
VERSION ${SPIRV_CROSS_VERSION}
SOVERSION ${spirv-cross-abi-major})
endif()
if (SPIRV_CROSS_CLI)
if (NOT SPIRV_CROSS_STATIC)
message(FATAL_ERROR "Must build static libraries if building CLI.")
endif()
add_executable(spirv-cross main.cpp)
target_compile_options(spirv-cross PRIVATE ${spirv-compiler-options})
target_compile_definitions(spirv-cross PRIVATE ${spirv-compiler-defines})
set_target_properties(spirv-cross PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}")
install(TARGETS spirv-cross RUNTIME DESTINATION bin)
target_link_libraries(spirv-cross PRIVATE
spirv-cross-glsl
spirv-cross-hlsl
spirv-cross-cpp
spirv-cross-reflect
spirv-cross-msl
spirv-cross-util
spirv-cross-core)
if (SPIRV_CROSS_ENABLE_TESTS)
# Set up tests, using only the simplest modes of the test_shaders
# script. You have to invoke the script manually to:
# - Update the reference files
# - Get cycle counts from malisc
# - Keep failing outputs
find_package(PythonInterp)
find_program(spirv-cross-glslang NAMES glslangValidator
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external/glslang-build/output/bin
NO_DEFAULT_PATH)
find_program(spirv-cross-spirv-as NAMES spirv-as
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external/spirv-tools-build/output/bin
NO_DEFAULT_PATH)
find_program(spirv-cross-spirv-val NAMES spirv-val
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external/spirv-tools-build/output/bin
NO_DEFAULT_PATH)
find_program(spirv-cross-spirv-opt NAMES spirv-opt
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/external/spirv-tools-build/output/bin
NO_DEFAULT_PATH)
if ((${spirv-cross-glslang} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-as} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-val} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-opt} MATCHES "NOTFOUND"))
set(SPIRV_CROSS_ENABLE_TESTS OFF)
message("Could not find glslang or SPIRV-Tools build under external/. Run ./checkout_glslang_spirv_tools.sh and ./build_glslang_spirv_tools.sh. Testing will be disabled.")
else()
set(SPIRV_CROSS_ENABLE_TESTS ON)
message("Found glslang and SPIRV-Tools. Enabling test suite.")
message("Found glslangValidator in: ${spirv-cross-glslang}.")
message("Found spirv-as in: ${spirv-cross-spirv-as}.")
message("Found spirv-val in: ${spirv-cross-spirv-val}.")
message("Found spirv-opt in: ${spirv-cross-spirv-opt}.")
endif()
set(spirv-cross-externals
--glslang "${spirv-cross-glslang}"
--spirv-as "${spirv-cross-spirv-as}"
--spirv-opt "${spirv-cross-spirv-opt}"
--spirv-val "${spirv-cross-spirv-val}")
if (${PYTHONINTERP_FOUND} AND SPIRV_CROSS_ENABLE_TESTS)
if (${PYTHON_VERSION_MAJOR} GREATER 2)
add_executable(spirv-cross-c-api-test tests-other/c_api_test.c)
target_link_libraries(spirv-cross-c-api-test spirv-cross-c)
set_target_properties(spirv-cross-c-api-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}")
if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang"))
target_compile_options(spirv-cross-c-api-test PRIVATE -std=c89 -Wall -Wextra)
endif()
add_test(NAME spirv-cross-c-api-test
COMMAND $<TARGET_FILE:spirv-cross-c-api-test> ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/c_api_test.spv)
add_test(NAME spirv-cross-test
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-no-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-metal
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-metal-no-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-hlsl
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-hlsl-no-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl-no-opt
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --opt --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-metal-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --metal --opt --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-msl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-hlsl-opt
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --hlsl --opt --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-hlsl
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
add_test(NAME spirv-cross-test-reflection
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --reflect --parallel
${spirv-cross-externals}
${CMAKE_CURRENT_SOURCE_DIR}/shaders-reflection
WORKING_DIRECTORY $<TARGET_FILE_DIR:spirv-cross>)
endif()
elseif(NOT ${PYTHONINTERP_FOUND})
message(WARNING "Testing disabled. Could not find python3. If you have python3 installed try running "
"cmake with -DPYTHON_EXECUTABLE:FILEPATH=/path/to/python3 to help it find the executable")
endif()
endif()
endif() endif()

View File

@ -10,7 +10,7 @@ STATIC_LIB := lib$(TARGET).a
DEPS := $(OBJECTS:.o=.d) $(CLI_OBJECTS:.o=.d) DEPS := $(OBJECTS:.o=.d) $(CLI_OBJECTS:.o=.d)
CXXFLAGS += -std=c++11 -Wall -Wextra -Wshadow -D__STDC_LIMIT_MACROS CXXFLAGS += -std=c++11 -Wall -Wextra -Wshadow
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
CXXFLAGS += -O0 -g CXXFLAGS += -O0 -g

View File

@ -10,7 +10,7 @@ SPIRV-Cross is a tool designed for parsing and converting SPIR-V to other shader
- Convert SPIR-V to readable, usable and efficient GLSL - Convert SPIR-V to readable, usable and efficient GLSL
- Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL) - Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL)
- Convert SPIR-V to readable, usable and efficient HLSL - Convert SPIR-V to readable, usable and efficient HLSL
- Convert SPIR-V to debuggable C++ [EXPERIMENTAL] - Convert SPIR-V to debuggable C++ [DEPRECATED]
- Convert SPIR-V to a JSON reflection format [EXPERIMENTAL] - Convert SPIR-V to a JSON reflection format [EXPERIMENTAL]
- Reflection API to simplify the creation of Vulkan pipeline layouts - Reflection API to simplify the creation of Vulkan pipeline layouts
- Reflection API to modify and tweak OpDecorations - Reflection API to modify and tweak OpDecorations
@ -48,11 +48,18 @@ SPIRV-Cross is only useful as a library here. Use the CMake build to link SPIRV-
The make and CMake build flavors offer the option to treat exceptions as assertions. To disable exceptions for make just append `SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=1` to the command line. For CMake append `-DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=ON`. By default exceptions are enabled. The make and CMake build flavors offer the option to treat exceptions as assertions. To disable exceptions for make just append `SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=1` to the command line. For CMake append `-DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=ON`. By default exceptions are enabled.
### Static, shared and CLI
You can use `-DSPIRV_CROSS_STATIC=ON/OFF` `-DSPIRV_CROSS_SHARED=ON/OFF` `-DSPIRV_CROSS_CLI=ON/OFF` to control which modules are built (and installed).
## Usage ## Usage
### Using the C++ API ### Using the C++ API
For more in-depth documentation than what's provided in this README, please have a look at the [Wiki](https://github.com/KhronosGroup/SPIRV-Cross/wiki). The C++ API is the main API for SPIRV-Cross. For more in-depth documentation than what's provided in this README,
please have a look at the [Wiki](https://github.com/KhronosGroup/SPIRV-Cross/wiki).
**NOTE**: This API is not guaranteed to be ABI-stable, and it is highly recommended to link against this API statically.
The API is generally quite stable, but it can change over time, see the C API for more stability.
To perform reflection and convert to other shader languages you can use the SPIRV-Cross API. To perform reflection and convert to other shader languages you can use the SPIRV-Cross API.
For example: For example:
@ -99,19 +106,143 @@ int main()
} }
``` ```
### Using the C API wrapper
To facilitate C compatibility and compatibility with foreign programming languages, a C89-compatible API wrapper is provided. Unlike the C++ API,
the goal of this wrapper is to be fully stable, both API and ABI-wise.
This is the only interface which is supported when building SPIRV-Cross as a shared library.
An important point of the wrapper is that all memory allocations are contained in the `spvc_context`.
This simplifies the use of the API greatly. However, you should destroy the context as soon as reasonable,
or use `spvc_context_release_allocations()` if you intend to reuse the `spvc_context` object again soon.
Most functions return a `spvc_result`, where `SPVC_SUCCESS` is the only success code.
For brevity, the code below does not do any error checking.
```c
#include <spirv_cross_c.h>
const SpvId *spirv = get_spirv_data();
size_t word_count = get_spirv_word_count();
spvc_context context = NULL;
spvc_parsed_ir ir = NULL;
spvc_compiler compiler_glsl = NULL;
spvc_compiler_options options = NULL;
spvc_resources resources = NULL;
const spvc_reflected_resource *list = NULL;
const char *result = NULL;
size_t count;
size_t i;
// Create context.
spvc_context_create(&context);
// Set debug callback.
spvc_context_set_error_callback(context, error_callback, userdata);
// Parse the SPIR-V.
spvc_context_parse_spirv(context, spirv, word_count, &ir);
// Hand it off to a compiler instance and give it ownership of the IR.
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_glsl);
// Do some basic reflection.
spvc_compiler_create_shader_resources(compiler_glsl, &resources);
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
for (i = 0; i < count; i++)
{
printf("ID: %u, BaseTypeID: %u, TypeID: %u, Name: %s\n", list[i].id, list[i].base_type_id, list[i].type_id,
list[i].name);
printf(" Set: %u, Binding: %u\n",
spvc_compiler_get_decoration(compiler_glsl, list[i].id, SpvDecorationDescriptorSet),
spvc_compiler_get_decoration(compiler_glsl, list[i].id, SpvDecorationBinding));
}
// Modify options.
spvc_compiler_create_compiler_options(context, &options);
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 330);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE);
spvc_compiler_install_compiler_options(compiler_glsl, options);
spvc_compiler_compile(compiler, &result);
printf("Cross-compiled source: %s\n", result);
// Frees all memory we allocated so far.
spvc_context_destroy(context);
```
### Linking
#### CMake add_subdirectory()
This is the recommended way if you are using CMake and want to link against SPIRV-Cross statically.
#### Integrating SPIRV-Cross in a custom build system #### Integrating SPIRV-Cross in a custom build system
To add SPIRV-Cross to your own codebase, just copy the source and header files from root directory To add SPIRV-Cross to your own codebase, just copy the source and header files from root directory
and build the relevant .cpp files you need. Make sure to build with C++11 support, e.g. `-std=c++11` in GCC and Clang. and build the relevant .cpp files you need. Make sure to build with C++11 support, e.g. `-std=c++11` in GCC and Clang.
Alternatively, the Makefile generates a libspirv-cross.a static library during build that can be linked in. Alternatively, the Makefile generates a libspirv-cross.a static library during build that can be linked in.
### Creating a SPIR-V file from GLSL with glslang #### Linking against SPIRV-Cross as a system library
It is possible to link against SPIRV-Cross when it is installed as a system library,
which would be mostly relevant for Unix-like platforms.
##### pkg-config
For Unix-based systems, a pkg-config is installed for the C API, e.g.:
```
$ pkg-config spirv-cross-c-shared --libs --cflags
-I/usr/local/include/spirv_cross -L/usr/local/lib -lspirv-cross-c-shared
```
##### CMake
If the project is installed, it can be found with `find_package()`, e.g.:
```
cmake_minimum_required(VERSION 3.5)
set(CMAKE_C_STANDARD 99)
project(Test LANGUAGES C)
find_package(spirv_cross_c_shared)
if (spirv_cross_c_shared_FOUND)
message(STATUS "Found SPIRV-Cross C API! :)")
else()
message(STATUS "Could not find SPIRV-Cross C API! :(")
endif()
add_executable(test test.c)
target_link_libraries(test spirv-cross-c-shared)
```
test.c:
```c
#include <spirv_cross_c.h>
int main(void)
{
spvc_context context;
spvc_context_create(&context);
spvc_context_destroy(context);
}
```
### CLI
The CLI is suitable for basic cross-compilation tasks, but it cannot support the full flexibility that the API can.
Some examples below.
#### Creating a SPIR-V file from GLSL with glslang
``` ```
glslangValidator -H -V -o test.spv test.frag glslangValidator -H -V -o test.spv test.frag
``` ```
### Converting a SPIR-V file to GLSL ES #### Converting a SPIR-V file to GLSL ES
``` ```
glslangValidator -H -V -o test.spv shaders/comp/basic.comp glslangValidator -H -V -o test.spv shaders/comp/basic.comp
@ -122,7 +253,7 @@ glslangValidator -H -V -o test.spv shaders/comp/basic.comp
``` ```
glslangValidator -H -V -o test.spv shaders/comp/basic.comp glslangValidator -H -V -o test.spv shaders/comp/basic.comp
./spirv-cross --version 330 test.spv --output test.comp ./spirv-cross --version 330 --no-es test.spv --output test.comp
``` ```
#### Disable prettifying optimizations #### Disable prettifying optimizations
@ -278,17 +409,22 @@ Contributions to SPIRV-Cross are welcome. See Testing and Licensing sections for
### Testing ### Testing
SPIRV-Cross maintains a test suite of shaders with reference output of how the output looks after going through a roundtrip through SPIRV-Cross maintains a test suite of shaders with reference output of how the output looks after going through a roundtrip through
glslangValidator then back through SPIRV-Cross again. The reference files are stored inside the repository in order to be able to track regressions. glslangValidator/spirv-as then back through SPIRV-Cross again.
The reference files are stored inside the repository in order to be able to track regressions.
All pull requests should ensure that test output does not change unexpectedly. This can be tested with: All pull requests should ensure that test output does not change unexpectedly. This can be tested with:
``` ```
./test_shaders.py shaders ./test_shaders.py shaders || exit 1
./test_shaders.py shaders --opt ./test_shaders.py shaders --opt || exit 1
./test_shaders.py shaders-hlsl --hlsl ./test_shaders.py shaders-no-opt || exit 1
./test_shaders.py shaders-hlsl --hlsl --opt ./test_shaders.py shaders-msl --msl || exit 1
./test_shaders.py shaders-msl --msl ./test_shaders.py shaders-msl --msl --opt || exit 1
./test_shaders.py shaders-msl --msl --opt ./test_shaders.py shaders-msl-no-opt --msl || exit 1
./test_shaders.py shaders-hlsl --hlsl || exit 1
./test_shaders.py shaders-hlsl --hlsl --opt || exit 1
./test_shaders.py shaders-hlsl-no-opt --hlsl || exit 1
./test_shaders.py shaders-reflection --reflect || exit 1
``` ```
although there are a couple of convenience script for doing this: although there are a couple of convenience script for doing this:
@ -316,6 +452,8 @@ A pull request which does not pass testing on Travis will not be accepted howeve
When adding support for new features to SPIRV-Cross, a new shader and reference file should be added which covers usage of the new shader features in question. When adding support for new features to SPIRV-Cross, a new shader and reference file should be added which covers usage of the new shader features in question.
Travis CI runs the test suite with the CMake, by running `ctest`. This method is compatible with MSVC.
### Licensing ### Licensing
Contributors of new files should add a copyright header at the top of every new source code file with their copyright Contributors of new files should add a copyright header at the top of every new source code file with their copyright
@ -332,13 +470,6 @@ command line:
./format_all.sh ./format_all.sh
## ABI concerns
### SPIR-V headers
The current repository uses the latest SPIR-V and GLSL.std.450 headers.
SPIR-V files created from older headers could have ABI issues.
## Regression testing ## Regression testing
In shaders/ a collection of shaders are maintained for purposes of regression testing. In shaders/ a collection of shaders are maintained for purposes of regression testing.

View File

@ -1109,9 +1109,12 @@ static int main_inner(int argc, char *argv[])
for (uint32_t i = 0; i < args.iterations; i++) for (uint32_t i = 0; i < args.iterations; i++)
{ {
if (args.hlsl) if (args.hlsl)
glsl = static_cast<CompilerHLSL *>(compiler.get())->compile(move(args.hlsl_attr_remap)); {
else for (auto &remap : args.hlsl_attr_remap)
glsl = compiler->compile(); static_cast<CompilerHLSL *>(compiler.get())->add_vertex_attribute_remap(remap);
}
glsl = compiler->compile();
} }
if (args.output) if (args.output)

View File

@ -0,0 +1,13 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=@SPIRV_CROSS_INSTALL_LIB_DIR@
sharedlibdir=@SPIRV_CROSS_INSTALL_LIB_DIR@
includedir=@SPIRV_CROSS_INSTALL_INC_DIR@
Name: spirv-cross-c-shared
Description: C API for SPIRV-Cross
Version: @SPIRV_CROSS_VERSION@
Requires:
Libs: -L${libdir} -L${sharedlibdir} -lspirv-cross-c-shared
Cflags: -I${includedir}

View File

@ -0,0 +1,13 @@
#version 450
void main()
{
int j = 0;
int i = 0;
do
{
j = ((j + i) + 1) * j;
i++;
} while (!(i == 20));
}

View File

@ -0,0 +1,11 @@
#version 450
void main()
{
int _13;
for (int _12 = 0; !(_12 == 16); _12 = _13)
{
_13 = _12 + 1;
}
}

View File

@ -0,0 +1,11 @@
#version 450
void main()
{
int _13;
for (int _12 = 0; _12 != 16; _12 = _13)
{
_13 = _12 + 1;
}
}

View File

@ -0,0 +1,11 @@
#version 450
void main()
{
int _13;
for (int _12 = 0; !(_12 == 16); _12 = _13)
{
_13 = _12 + 1;
}
}

View File

@ -0,0 +1,13 @@
#version 450
void main()
{
int i = 0;
int j = 0;
while (!(i == 20))
{
j = ((j + i) + 1) * j;
i++;
}
}

View File

@ -0,0 +1,51 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 28
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %i "i"
OpName %j "j"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_1 = OpConstant %int 1
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%main = OpFunction %void None %3
%5 = OpLabel
%i = OpVariable %_ptr_Function_int Function
%j = OpVariable %_ptr_Function_int Function
OpStore %i %int_0
OpStore %j %int_0
OpBranch %11
%11 = OpLabel
OpLoopMerge %13 %14 None
OpBranch %12
%12 = OpLabel
%15 = OpLoad %int %j
%16 = OpLoad %int %i
%17 = OpIAdd %int %15 %16
%19 = OpIAdd %int %17 %int_1
%20 = OpLoad %int %j
%21 = OpIMul %int %19 %20
OpStore %j %21
%22 = OpLoad %int %i
%23 = OpIAdd %int %22 %int_1
OpStore %i %23
OpBranch %14
%14 = OpLabel
%24 = OpLoad %int %i
%27 = OpIEqual %bool %24 %int_20
OpBranchConditional %27 %13 %11
%13 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,37 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %8
%8 = OpLabel
%10 = OpPhi %int %12 %7 %int_0 %5
OpLoopMerge %6 %7 None
OpBranch %11
%11 = OpLabel
%16 = OpIEqual %bool %10 %int_16
OpBranchConditional %16 %18 %19
%18 = OpLabel
OpBranch %6
%19 = OpLabel
OpBranch %17
%17 = OpLabel
%21 = OpIAdd %int %10 %int_1
OpBranch %7
%7 = OpLabel
%12 = OpPhi %int %21 %17
OpBranch %8
%6 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,37 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %8
%8 = OpLabel
%10 = OpPhi %int %12 %7 %int_0 %5
OpLoopMerge %6 %7 None
OpBranch %11
%11 = OpLabel
%16 = OpINotEqual %bool %10 %int_16
OpBranchConditional %16 %19 %18
%18 = OpLabel
OpBranch %6
%19 = OpLabel
OpBranch %17
%17 = OpLabel
%21 = OpIAdd %int %10 %int_1
OpBranch %7
%7 = OpLabel
%12 = OpPhi %int %21 %17
OpBranch %8
%6 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,35 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
OpBranch %8
%8 = OpLabel
%10 = OpPhi %int %12 %7 %int_0 %5
OpLoopMerge %6 %7 None
OpBranch %11
%11 = OpLabel
%16 = OpIEqual %bool %10 %int_16
OpBranchConditional %16 %6 %19
%19 = OpLabel
OpBranch %17
%17 = OpLabel
%21 = OpIAdd %int %10 %int_1
OpBranch %7
%7 = OpLabel
%12 = OpPhi %int %21 %17
OpBranch %8
%6 = OpLabel
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,53 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 7
; Bound: 29
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %i "i"
OpName %j "j"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_20 = OpConstant %int 20
%bool = OpTypeBool
%int_1 = OpConstant %int 1
%main = OpFunction %void None %3
%5 = OpLabel
%i = OpVariable %_ptr_Function_int Function
%j = OpVariable %_ptr_Function_int Function
OpStore %i %int_0
OpStore %j %int_0
OpBranch %11
%11 = OpLabel
OpLoopMerge %13 %14 None
OpBranch %15
%15 = OpLabel
%16 = OpLoad %int %i
%19 = OpIEqual %bool %16 %int_20
OpBranchConditional %19 %13 %12
%12 = OpLabel
%20 = OpLoad %int %j
%21 = OpLoad %int %i
%22 = OpIAdd %int %20 %21
%24 = OpIAdd %int %22 %int_1
%25 = OpLoad %int %j
%26 = OpIMul %int %24 %25
OpStore %j %26
%27 = OpLoad %int %i
%28 = OpIAdd %int %27 %int_1
OpStore %i %28
OpBranch %14
%14 = OpLabel
OpBranch %11
%13 = OpLabel
OpReturn
OpFunctionEnd

1213
3rdparty/spirv-cross/spirv.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 The Khronos Group Inc. // Copyright (c) 2014-2019 The Khronos Group Inc.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and/or associated documentation files (the "Materials"), // of this software and/or associated documentation files (the "Materials"),
@ -26,13 +26,16 @@
// the Binary Section of the SPIR-V specification. // the Binary Section of the SPIR-V specification.
// Enumeration tokens for SPIR-V, in various styles: // Enumeration tokens for SPIR-V, in various styles:
// C, C++, C++11, JSON, Lua, Python // C, C++, C++11, JSON, Lua, Python, C#, D
// //
// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL // - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL // - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL // - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL // - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] // - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
// - C# will use enum classes in the Specification class located in the "Spv" namespace,
// e.g.: Spv.Specification.SourceLanguage.GLSL
// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL
// //
// Some tokens act like mask values, which can be OR'd together, // Some tokens act like mask values, which can be OR'd together,
// while others are mutually exclusive. The mask-like ones have // while others are mutually exclusive. The mask-like ones have
@ -47,11 +50,11 @@ namespace spv {
typedef unsigned int Id; typedef unsigned int Id;
#define SPV_VERSION 0x10300 #define SPV_VERSION 0x10300
#define SPV_REVISION 1 #define SPV_REVISION 6
static const unsigned int MagicNumber = 0x07230203; static const unsigned int MagicNumber = 0x07230203;
static const unsigned int Version = 0x00010300; static const unsigned int Version = 0x00010300;
static const unsigned int Revision = 1; static const unsigned int Revision = 6;
static const unsigned int OpCodeMask = 0xffff; static const unsigned int OpCodeMask = 0xffff;
static const unsigned int WordCountShift = 16; static const unsigned int WordCountShift = 16;
@ -73,6 +76,14 @@ enum ExecutionModel {
ExecutionModelFragment = 4, ExecutionModelFragment = 4,
ExecutionModelGLCompute = 5, ExecutionModelGLCompute = 5,
ExecutionModelKernel = 6, ExecutionModelKernel = 6,
ExecutionModelTaskNV = 5267,
ExecutionModelMeshNV = 5268,
ExecutionModelRayGenerationNV = 5313,
ExecutionModelIntersectionNV = 5314,
ExecutionModelAnyHitNV = 5315,
ExecutionModelClosestHitNV = 5316,
ExecutionModelMissNV = 5317,
ExecutionModelCallableNV = 5318,
ExecutionModelMax = 0x7fffffff, ExecutionModelMax = 0x7fffffff,
}; };
@ -80,6 +91,7 @@ enum AddressingModel {
AddressingModelLogical = 0, AddressingModelLogical = 0,
AddressingModelPhysical32 = 1, AddressingModelPhysical32 = 1,
AddressingModelPhysical64 = 2, AddressingModelPhysical64 = 2,
AddressingModelPhysicalStorageBuffer64EXT = 5348,
AddressingModelMax = 0x7fffffff, AddressingModelMax = 0x7fffffff,
}; };
@ -87,6 +99,7 @@ enum MemoryModel {
MemoryModelSimple = 0, MemoryModelSimple = 0,
MemoryModelGLSL450 = 1, MemoryModelGLSL450 = 1,
MemoryModelOpenCL = 2, MemoryModelOpenCL = 2,
MemoryModelVulkanKHR = 3,
MemoryModelMax = 0x7fffffff, MemoryModelMax = 0x7fffffff,
}; };
@ -130,7 +143,17 @@ enum ExecutionMode {
ExecutionModeLocalSizeId = 38, ExecutionModeLocalSizeId = 38,
ExecutionModeLocalSizeHintId = 39, ExecutionModeLocalSizeHintId = 39,
ExecutionModePostDepthCoverage = 4446, ExecutionModePostDepthCoverage = 4446,
ExecutionModeDenormPreserve = 4459,
ExecutionModeDenormFlushToZero = 4460,
ExecutionModeSignedZeroInfNanPreserve = 4461,
ExecutionModeRoundingModeRTE = 4462,
ExecutionModeRoundingModeRTZ = 4463,
ExecutionModeStencilRefReplacingEXT = 5027, ExecutionModeStencilRefReplacingEXT = 5027,
ExecutionModeOutputLinesNV = 5269,
ExecutionModeOutputPrimitivesNV = 5270,
ExecutionModeDerivativeGroupQuadsNV = 5289,
ExecutionModeDerivativeGroupLinearNV = 5290,
ExecutionModeOutputTrianglesNV = 5298,
ExecutionModeMax = 0x7fffffff, ExecutionModeMax = 0x7fffffff,
}; };
@ -148,6 +171,13 @@ enum StorageClass {
StorageClassAtomicCounter = 10, StorageClassAtomicCounter = 10,
StorageClassImage = 11, StorageClassImage = 11,
StorageClassStorageBuffer = 12, StorageClassStorageBuffer = 12,
StorageClassCallableDataNV = 5328,
StorageClassIncomingCallableDataNV = 5329,
StorageClassRayPayloadNV = 5338,
StorageClassHitAttributeNV = 5339,
StorageClassIncomingRayPayloadNV = 5342,
StorageClassShaderRecordBufferNV = 5343,
StorageClassPhysicalStorageBufferEXT = 5349,
StorageClassMax = 0x7fffffff, StorageClassMax = 0x7fffffff,
}; };
@ -275,6 +305,10 @@ enum ImageOperandsShift {
ImageOperandsConstOffsetsShift = 5, ImageOperandsConstOffsetsShift = 5,
ImageOperandsSampleShift = 6, ImageOperandsSampleShift = 6,
ImageOperandsMinLodShift = 7, ImageOperandsMinLodShift = 7,
ImageOperandsMakeTexelAvailableKHRShift = 8,
ImageOperandsMakeTexelVisibleKHRShift = 9,
ImageOperandsNonPrivateTexelKHRShift = 10,
ImageOperandsVolatileTexelKHRShift = 11,
ImageOperandsMax = 0x7fffffff, ImageOperandsMax = 0x7fffffff,
}; };
@ -288,6 +322,10 @@ enum ImageOperandsMask {
ImageOperandsConstOffsetsMask = 0x00000020, ImageOperandsConstOffsetsMask = 0x00000020,
ImageOperandsSampleMask = 0x00000040, ImageOperandsSampleMask = 0x00000040,
ImageOperandsMinLodMask = 0x00000080, ImageOperandsMinLodMask = 0x00000080,
ImageOperandsMakeTexelAvailableKHRMask = 0x00000100,
ImageOperandsMakeTexelVisibleKHRMask = 0x00000200,
ImageOperandsNonPrivateTexelKHRMask = 0x00000400,
ImageOperandsVolatileTexelKHRMask = 0x00000800,
}; };
enum FPFastMathModeShift { enum FPFastMathModeShift {
@ -388,11 +426,20 @@ enum Decoration {
DecorationMaxByteOffset = 45, DecorationMaxByteOffset = 45,
DecorationAlignmentId = 46, DecorationAlignmentId = 46,
DecorationMaxByteOffsetId = 47, DecorationMaxByteOffsetId = 47,
DecorationNoSignedWrap = 4469,
DecorationNoUnsignedWrap = 4470,
DecorationExplicitInterpAMD = 4999, DecorationExplicitInterpAMD = 4999,
DecorationOverrideCoverageNV = 5248, DecorationOverrideCoverageNV = 5248,
DecorationPassthroughNV = 5250, DecorationPassthroughNV = 5250,
DecorationViewportRelativeNV = 5252, DecorationViewportRelativeNV = 5252,
DecorationSecondaryViewportRelativeNV = 5256, DecorationSecondaryViewportRelativeNV = 5256,
DecorationPerPrimitiveNV = 5271,
DecorationPerViewNV = 5272,
DecorationPerTaskNV = 5273,
DecorationPerVertexNV = 5285,
DecorationNonUniformEXT = 5300,
DecorationRestrictPointerEXT = 5355,
DecorationAliasedPointerEXT = 5356,
DecorationHlslCounterBufferGOOGLE = 5634, DecorationHlslCounterBufferGOOGLE = 5634,
DecorationHlslSemanticGOOGLE = 5635, DecorationHlslSemanticGOOGLE = 5635,
DecorationMax = 0x7fffffff, DecorationMax = 0x7fffffff,
@ -469,6 +516,34 @@ enum BuiltIn {
BuiltInPositionPerViewNV = 5261, BuiltInPositionPerViewNV = 5261,
BuiltInViewportMaskPerViewNV = 5262, BuiltInViewportMaskPerViewNV = 5262,
BuiltInFullyCoveredEXT = 5264, BuiltInFullyCoveredEXT = 5264,
BuiltInTaskCountNV = 5274,
BuiltInPrimitiveCountNV = 5275,
BuiltInPrimitiveIndicesNV = 5276,
BuiltInClipDistancePerViewNV = 5277,
BuiltInCullDistancePerViewNV = 5278,
BuiltInLayerPerViewNV = 5279,
BuiltInMeshViewCountNV = 5280,
BuiltInMeshViewIndicesNV = 5281,
BuiltInBaryCoordNV = 5286,
BuiltInBaryCoordNoPerspNV = 5287,
BuiltInFragSizeEXT = 5292,
BuiltInFragmentSizeNV = 5292,
BuiltInFragInvocationCountEXT = 5293,
BuiltInInvocationsPerPixelNV = 5293,
BuiltInLaunchIdNV = 5319,
BuiltInLaunchSizeNV = 5320,
BuiltInWorldRayOriginNV = 5321,
BuiltInWorldRayDirectionNV = 5322,
BuiltInObjectRayOriginNV = 5323,
BuiltInObjectRayDirectionNV = 5324,
BuiltInRayTminNV = 5325,
BuiltInRayTmaxNV = 5326,
BuiltInInstanceCustomIndexNV = 5327,
BuiltInObjectToWorldNV = 5330,
BuiltInWorldToObjectNV = 5331,
BuiltInHitTNV = 5332,
BuiltInHitKindNV = 5333,
BuiltInIncomingRayFlagsNV = 5351,
BuiltInMax = 0x7fffffff, BuiltInMax = 0x7fffffff,
}; };
@ -527,6 +602,9 @@ enum MemorySemanticsShift {
MemorySemanticsCrossWorkgroupMemoryShift = 9, MemorySemanticsCrossWorkgroupMemoryShift = 9,
MemorySemanticsAtomicCounterMemoryShift = 10, MemorySemanticsAtomicCounterMemoryShift = 10,
MemorySemanticsImageMemoryShift = 11, MemorySemanticsImageMemoryShift = 11,
MemorySemanticsOutputMemoryKHRShift = 12,
MemorySemanticsMakeAvailableKHRShift = 13,
MemorySemanticsMakeVisibleKHRShift = 14,
MemorySemanticsMax = 0x7fffffff, MemorySemanticsMax = 0x7fffffff,
}; };
@ -542,12 +620,18 @@ enum MemorySemanticsMask {
MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,
MemorySemanticsAtomicCounterMemoryMask = 0x00000400, MemorySemanticsAtomicCounterMemoryMask = 0x00000400,
MemorySemanticsImageMemoryMask = 0x00000800, MemorySemanticsImageMemoryMask = 0x00000800,
MemorySemanticsOutputMemoryKHRMask = 0x00001000,
MemorySemanticsMakeAvailableKHRMask = 0x00002000,
MemorySemanticsMakeVisibleKHRMask = 0x00004000,
}; };
enum MemoryAccessShift { enum MemoryAccessShift {
MemoryAccessVolatileShift = 0, MemoryAccessVolatileShift = 0,
MemoryAccessAlignedShift = 1, MemoryAccessAlignedShift = 1,
MemoryAccessNontemporalShift = 2, MemoryAccessNontemporalShift = 2,
MemoryAccessMakePointerAvailableKHRShift = 3,
MemoryAccessMakePointerVisibleKHRShift = 4,
MemoryAccessNonPrivatePointerKHRShift = 5,
MemoryAccessMax = 0x7fffffff, MemoryAccessMax = 0x7fffffff,
}; };
@ -556,6 +640,9 @@ enum MemoryAccessMask {
MemoryAccessVolatileMask = 0x00000001, MemoryAccessVolatileMask = 0x00000001,
MemoryAccessAlignedMask = 0x00000002, MemoryAccessAlignedMask = 0x00000002,
MemoryAccessNontemporalMask = 0x00000004, MemoryAccessNontemporalMask = 0x00000004,
MemoryAccessMakePointerAvailableKHRMask = 0x00000008,
MemoryAccessMakePointerVisibleKHRMask = 0x00000010,
MemoryAccessNonPrivatePointerKHRMask = 0x00000020,
}; };
enum Scope { enum Scope {
@ -564,6 +651,7 @@ enum Scope {
ScopeWorkgroup = 2, ScopeWorkgroup = 2,
ScopeSubgroup = 3, ScopeSubgroup = 3,
ScopeInvocation = 4, ScopeInvocation = 4,
ScopeQueueFamilyKHR = 5,
ScopeMax = 0x7fffffff, ScopeMax = 0x7fffffff,
}; };
@ -572,6 +660,9 @@ enum GroupOperation {
GroupOperationInclusiveScan = 1, GroupOperationInclusiveScan = 1,
GroupOperationExclusiveScan = 2, GroupOperationExclusiveScan = 2,
GroupOperationClusteredReduce = 3, GroupOperationClusteredReduce = 3,
GroupOperationPartitionedReduceNV = 6,
GroupOperationPartitionedInclusiveScanNV = 7,
GroupOperationPartitionedExclusiveScanNV = 8,
GroupOperationMax = 0x7fffffff, GroupOperationMax = 0x7fffffff,
}; };
@ -675,6 +766,14 @@ enum Capability {
CapabilityVariablePointers = 4442, CapabilityVariablePointers = 4442,
CapabilityAtomicStorageOps = 4445, CapabilityAtomicStorageOps = 4445,
CapabilitySampleMaskPostDepthCoverage = 4447, CapabilitySampleMaskPostDepthCoverage = 4447,
CapabilityStorageBuffer8BitAccess = 4448,
CapabilityUniformAndStorageBuffer8BitAccess = 4449,
CapabilityStoragePushConstant8 = 4450,
CapabilityDenormPreserve = 4464,
CapabilityDenormFlushToZero = 4465,
CapabilitySignedZeroInfNanPreserve = 4466,
CapabilityRoundingModeRTE = 4467,
CapabilityRoundingModeRTZ = 4468,
CapabilityFloat16ImageAMD = 5008, CapabilityFloat16ImageAMD = 5008,
CapabilityImageGatherBiasLodAMD = 5009, CapabilityImageGatherBiasLodAMD = 5009,
CapabilityFragmentMaskAMD = 5010, CapabilityFragmentMaskAMD = 5010,
@ -688,9 +787,34 @@ enum Capability {
CapabilityShaderStereoViewNV = 5259, CapabilityShaderStereoViewNV = 5259,
CapabilityPerViewAttributesNV = 5260, CapabilityPerViewAttributesNV = 5260,
CapabilityFragmentFullyCoveredEXT = 5265, CapabilityFragmentFullyCoveredEXT = 5265,
CapabilityMeshShadingNV = 5266,
CapabilityImageFootprintNV = 5282,
CapabilityFragmentBarycentricNV = 5284,
CapabilityComputeDerivativeGroupQuadsNV = 5288,
CapabilityFragmentDensityEXT = 5291,
CapabilityShadingRateNV = 5291,
CapabilityGroupNonUniformPartitionedNV = 5297,
CapabilityShaderNonUniformEXT = 5301,
CapabilityRuntimeDescriptorArrayEXT = 5302,
CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303,
CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304,
CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305,
CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306,
CapabilitySampledImageArrayNonUniformIndexingEXT = 5307,
CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308,
CapabilityStorageImageArrayNonUniformIndexingEXT = 5309,
CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310,
CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311,
CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312,
CapabilityRayTracingNV = 5340,
CapabilityVulkanMemoryModelKHR = 5345,
CapabilityVulkanMemoryModelDeviceScopeKHR = 5346,
CapabilityPhysicalStorageBufferAddressesEXT = 5347,
CapabilityComputeDerivativeGroupLinearNV = 5350,
CapabilitySubgroupShuffleINTEL = 5568, CapabilitySubgroupShuffleINTEL = 5568,
CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupBufferBlockIOINTEL = 5569,
CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilitySubgroupImageBlockIOINTEL = 5570,
CapabilitySubgroupImageMediaBlockIOINTEL = 5579,
CapabilityMax = 0x7fffffff, CapabilityMax = 0x7fffffff,
}; };
@ -1051,6 +1175,15 @@ enum Op {
OpGroupSMaxNonUniformAMD = 5007, OpGroupSMaxNonUniformAMD = 5007,
OpFragmentMaskFetchAMD = 5011, OpFragmentMaskFetchAMD = 5011,
OpFragmentFetchAMD = 5012, OpFragmentFetchAMD = 5012,
OpImageSampleFootprintNV = 5283,
OpGroupNonUniformPartitionNV = 5296,
OpWritePackedPrimitiveIndices4x8NV = 5299,
OpReportIntersectionNV = 5334,
OpIgnoreIntersectionNV = 5335,
OpTerminateRayNV = 5336,
OpTraceNV = 5337,
OpTypeAccelerationStructureNV = 5341,
OpExecuteCallableNV = 5344,
OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleINTEL = 5571,
OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleDownINTEL = 5572,
OpSubgroupShuffleUpINTEL = 5573, OpSubgroupShuffleUpINTEL = 5573,
@ -1059,6 +1192,8 @@ enum Op {
OpSubgroupBlockWriteINTEL = 5576, OpSubgroupBlockWriteINTEL = 5576,
OpSubgroupImageBlockReadINTEL = 5577, OpSubgroupImageBlockReadINTEL = 5577,
OpSubgroupImageBlockWriteINTEL = 5578, OpSubgroupImageBlockWriteINTEL = 5578,
OpSubgroupImageMediaBlockReadINTEL = 5580,
OpSubgroupImageMediaBlockWriteINTEL = 5581,
OpDecorateStringGOOGLE = 5632, OpDecorateStringGOOGLE = 5632,
OpMemberDecorateStringGOOGLE = 5633, OpMemberDecorateStringGOOGLE = 5633,
OpMax = 0x7fffffff, OpMax = 0x7fffffff,

View File

@ -59,7 +59,7 @@ report_and_abort(const std::string &msg)
class CompilerError : public std::runtime_error class CompilerError : public std::runtime_error
{ {
public: public:
CompilerError(const std::string &str) explicit CompilerError(const std::string &str)
: std::runtime_error(str) : std::runtime_error(str)
{ {
} }
@ -359,7 +359,8 @@ struct SPIRUndef : IVariant
{ {
type = TypeUndef type = TypeUndef
}; };
SPIRUndef(uint32_t basetype_)
explicit SPIRUndef(uint32_t basetype_)
: basetype(basetype_) : basetype(basetype_)
{ {
} }
@ -511,7 +512,7 @@ struct SPIRExtension : IVariant
SPV_AMD_gcn_shader SPV_AMD_gcn_shader
}; };
SPIRExtension(Extension ext_) explicit SPIRExtension(Extension ext_)
: ext(ext_) : ext(ext_)
{ {
} }
@ -546,7 +547,7 @@ struct SPIREntryPoint
} workgroup_size; } workgroup_size;
uint32_t invocations = 0; uint32_t invocations = 0;
uint32_t output_vertices = 0; uint32_t output_vertices = 0;
spv::ExecutionModel model; spv::ExecutionModel model = spv::ExecutionModelMax;
}; };
struct SPIRExpression : IVariant struct SPIRExpression : IVariant
@ -606,7 +607,7 @@ struct SPIRFunctionPrototype : IVariant
type = TypeFunctionPrototype type = TypeFunctionPrototype
}; };
SPIRFunctionPrototype(uint32_t return_type_) explicit SPIRFunctionPrototype(uint32_t return_type_)
: return_type(return_type_) : return_type(return_type_)
{ {
} }
@ -857,7 +858,7 @@ struct SPIRAccessChain : IVariant
int32_t static_index_) int32_t static_index_)
: basetype(basetype_) : basetype(basetype_)
, storage(storage_) , storage(storage_)
, base(base_) , base(std::move(base_))
, dynamic_index(std::move(dynamic_index_)) , dynamic_index(std::move(dynamic_index_))
, static_index(static_index_) , static_index(static_index_)
{ {
@ -1215,7 +1216,7 @@ struct SPIRConstant : IVariant
} }
} }
uint32_t constant_type; uint32_t constant_type = 0;
ConstantMatrix m; ConstantMatrix m;
// If this constant is a specialization constant (i.e. created with OpSpecConstant*). // If this constant is a specialization constant (i.e. created with OpSpecConstant*).

View File

@ -931,50 +931,6 @@ void Compiler::parse_fixup()
fixup_type_alias(); fixup_type_alias();
} }
void Compiler::flatten_interface_block(uint32_t id)
{
auto &var = get<SPIRVariable>(id);
auto &type = get<SPIRType>(var.basetype);
auto &flags = ir.meta[type.self].decoration.decoration_flags;
if (!type.array.empty())
SPIRV_CROSS_THROW("Type is array of UBOs.");
if (type.basetype != SPIRType::Struct)
SPIRV_CROSS_THROW("Type is not a struct.");
if (!flags.get(DecorationBlock))
SPIRV_CROSS_THROW("Type is not a block.");
if (type.member_types.empty())
SPIRV_CROSS_THROW("Member list of struct is empty.");
uint32_t t = type.member_types[0];
for (auto &m : type.member_types)
if (t != m)
SPIRV_CROSS_THROW("Types in block differ.");
auto &mtype = get<SPIRType>(t);
if (!mtype.array.empty())
SPIRV_CROSS_THROW("Member type cannot be arrays.");
if (mtype.basetype == SPIRType::Struct)
SPIRV_CROSS_THROW("Member type cannot be struct.");
// Inherit variable name from interface block name.
ir.meta[var.self].decoration.alias = ir.meta[type.self].decoration.alias;
auto storage = var.storage;
if (storage == StorageClassUniform)
storage = StorageClassUniformConstant;
// Change type definition in-place into an array instead.
// Access chains will still work as-is.
uint32_t array_size = uint32_t(type.member_types.size());
type = mtype;
type.array.push_back(array_size);
type.pointer = true;
type.storage = storage;
type.parent_type = t;
var.storage = storage;
}
void Compiler::update_name_cache(unordered_set<string> &cache_primary, const unordered_set<string> &cache_secondary, void Compiler::update_name_cache(unordered_set<string> &cache_primary, const unordered_set<string> &cache_secondary,
string &name) string &name)
{ {
@ -1155,11 +1111,6 @@ uint32_t Compiler::get_member_decoration(uint32_t id, uint32_t index, Decoration
return ir.get_member_decoration(id, index, decoration); return ir.get_member_decoration(id, index, decoration);
} }
uint64_t Compiler::get_member_decoration_mask(uint32_t id, uint32_t index) const
{
return get_member_decoration_bitset(id, index).get_lower();
}
const Bitset &Compiler::get_member_decoration_bitset(uint32_t id, uint32_t index) const const Bitset &Compiler::get_member_decoration_bitset(uint32_t id, uint32_t index) const
{ {
return ir.get_member_decoration_bitset(id, index); return ir.get_member_decoration_bitset(id, index);
@ -1412,11 +1363,6 @@ const std::string Compiler::get_block_fallback_name(uint32_t id) const
return get_name(id); return get_name(id);
} }
uint64_t Compiler::get_decoration_mask(uint32_t id) const
{
return get_decoration_bitset(id).get_lower();
}
const Bitset &Compiler::get_decoration_bitset(uint32_t id) const const Bitset &Compiler::get_decoration_bitset(uint32_t id) const
{ {
return ir.get_decoration_bitset(id); return ir.get_decoration_bitset(id);
@ -1474,12 +1420,29 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method
// which the code backend can use to create cleaner code. // which the code backend can use to create cleaner code.
// for(;;) { if (cond) { some_body; } else { break; } } // for(;;) { if (cond) { some_body; } else { break; } }
// is the pattern we're looking for. // is the pattern we're looking for.
bool ret = block.terminator == SPIRBlock::Select && block.merge == SPIRBlock::MergeLoop && const auto *false_block = maybe_get<SPIRBlock>(block.false_block);
block.true_block != block.merge_block && block.true_block != block.self && const auto *true_block = maybe_get<SPIRBlock>(block.true_block);
block.false_block == block.merge_block; const auto *merge_block = maybe_get<SPIRBlock>(block.merge_block);
if (ret && method == SPIRBlock::MergeToSelectContinueForLoop) bool false_block_is_merge = block.false_block == block.merge_block ||
(false_block && merge_block && execution_is_noop(*false_block, *merge_block));
bool true_block_is_merge = block.true_block == block.merge_block ||
(true_block && merge_block && execution_is_noop(*true_block, *merge_block));
bool positive_candidate =
block.true_block != block.merge_block && block.true_block != block.self && false_block_is_merge;
bool negative_candidate =
block.false_block != block.merge_block && block.false_block != block.self && true_block_is_merge;
bool ret = block.terminator == SPIRBlock::Select && block.merge == SPIRBlock::MergeLoop &&
(positive_candidate || negative_candidate);
if (ret && positive_candidate && method == SPIRBlock::MergeToSelectContinueForLoop)
ret = block.true_block == block.continue_block; ret = block.true_block == block.continue_block;
else if (ret && negative_candidate && method == SPIRBlock::MergeToSelectContinueForLoop)
ret = block.false_block == block.continue_block;
// If we have OpPhi which depends on branches which came from our own block, // If we have OpPhi which depends on branches which came from our own block,
// we need to flush phi variables in else block instead of a trivial break, // we need to flush phi variables in else block instead of a trivial break,
@ -1508,9 +1471,25 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method
return false; return false;
auto &child = get<SPIRBlock>(block.next_block); auto &child = get<SPIRBlock>(block.next_block);
const auto *false_block = maybe_get<SPIRBlock>(child.false_block);
const auto *true_block = maybe_get<SPIRBlock>(child.true_block);
const auto *merge_block = maybe_get<SPIRBlock>(block.merge_block);
bool false_block_is_merge = child.false_block == block.merge_block ||
(false_block && merge_block && execution_is_noop(*false_block, *merge_block));
bool true_block_is_merge = child.true_block == block.merge_block ||
(true_block && merge_block && execution_is_noop(*true_block, *merge_block));
bool positive_candidate =
child.true_block != block.merge_block && child.true_block != block.self && false_block_is_merge;
bool negative_candidate =
child.false_block != block.merge_block && child.false_block != block.self && true_block_is_merge;
ret = child.terminator == SPIRBlock::Select && child.merge == SPIRBlock::MergeNone && ret = child.terminator == SPIRBlock::Select && child.merge == SPIRBlock::MergeNone &&
child.false_block == block.merge_block && child.true_block != block.merge_block && (positive_candidate || negative_candidate);
child.true_block != block.self;
// If we have OpPhi which depends on branches which came from our own block, // If we have OpPhi which depends on branches which came from our own block,
// we need to flush phi variables in else block instead of a trivial break, // we need to flush phi variables in else block instead of a trivial break,
@ -1628,8 +1607,20 @@ SPIRBlock::ContinueBlockType Compiler::continue_block_type(const SPIRBlock &bloc
return SPIRBlock::ForLoop; return SPIRBlock::ForLoop;
else else
{ {
const auto *false_block = maybe_get<SPIRBlock>(block.false_block);
const auto *true_block = maybe_get<SPIRBlock>(block.true_block);
const auto *merge_block = maybe_get<SPIRBlock>(dominator.merge_block);
bool positive_do_while = block.true_block == dominator.self &&
(block.false_block == dominator.merge_block ||
(false_block && merge_block && execution_is_noop(*false_block, *merge_block)));
bool negative_do_while = block.false_block == dominator.self &&
(block.true_block == dominator.merge_block ||
(true_block && merge_block && execution_is_noop(*true_block, *merge_block)));
if (block.merge == SPIRBlock::MergeNone && block.terminator == SPIRBlock::Select && if (block.merge == SPIRBlock::MergeNone && block.terminator == SPIRBlock::Select &&
block.true_block == dominator.self && block.false_block == dominator.merge_block) (positive_do_while || negative_do_while))
{ {
return SPIRBlock::DoWhileLoop; return SPIRBlock::DoWhileLoop;
} }
@ -1904,11 +1895,6 @@ bool Compiler::types_are_logically_equivalent(const SPIRType &a, const SPIRType
return true; return true;
} }
uint64_t Compiler::get_execution_mode_mask() const
{
return get_entry_point().flags.get_lower();
}
const Bitset &Compiler::get_execution_mode_bitset() const const Bitset &Compiler::get_execution_mode_bitset() const
{ {
return get_entry_point().flags; return get_entry_point().flags;
@ -2094,14 +2080,6 @@ void Compiler::inherit_expression_dependencies(uint32_t dst, uint32_t source_exp
e_deps.erase(unique(begin(e_deps), end(e_deps)), end(e_deps)); e_deps.erase(unique(begin(e_deps), end(e_deps)), end(e_deps));
} }
vector<string> Compiler::get_entry_points() const
{
vector<string> entries;
for (auto &entry : ir.entry_points)
entries.push_back(entry.second.orig_name);
return entries;
}
vector<EntryPoint> Compiler::get_entry_points_and_stages() const vector<EntryPoint> Compiler::get_entry_points_and_stages() const
{ {
vector<EntryPoint> entries; vector<EntryPoint> entries;
@ -2110,13 +2088,6 @@ vector<EntryPoint> Compiler::get_entry_points_and_stages() const
return entries; return entries;
} }
void Compiler::rename_entry_point(const std::string &old_name, const std::string &new_name)
{
auto &entry = get_first_entry_point(old_name);
entry.orig_name = new_name;
entry.name = new_name;
}
void Compiler::rename_entry_point(const std::string &old_name, const std::string &new_name, spv::ExecutionModel model) void Compiler::rename_entry_point(const std::string &old_name, const std::string &new_name, spv::ExecutionModel model)
{ {
auto &entry = get_entry_point(old_name, model); auto &entry = get_entry_point(old_name, model);
@ -2124,28 +2095,12 @@ void Compiler::rename_entry_point(const std::string &old_name, const std::string
entry.name = new_name; entry.name = new_name;
} }
void Compiler::set_entry_point(const std::string &name)
{
auto &entry = get_first_entry_point(name);
ir.default_entry_point = entry.self;
}
void Compiler::set_entry_point(const std::string &name, spv::ExecutionModel model) void Compiler::set_entry_point(const std::string &name, spv::ExecutionModel model)
{ {
auto &entry = get_entry_point(name, model); auto &entry = get_entry_point(name, model);
ir.default_entry_point = entry.self; ir.default_entry_point = entry.self;
} }
SPIREntryPoint &Compiler::get_entry_point(const std::string &name)
{
return get_first_entry_point(name);
}
const SPIREntryPoint &Compiler::get_entry_point(const std::string &name) const
{
return get_first_entry_point(name);
}
SPIREntryPoint &Compiler::get_first_entry_point(const std::string &name) SPIREntryPoint &Compiler::get_first_entry_point(const std::string &name)
{ {
auto itr = find_if( auto itr = find_if(
@ -2196,11 +2151,6 @@ const SPIREntryPoint &Compiler::get_entry_point(const std::string &name, Executi
return itr->second; return itr->second;
} }
const string &Compiler::get_cleansed_entry_point_name(const std::string &name) const
{
return get_first_entry_point(name).name;
}
const string &Compiler::get_cleansed_entry_point_name(const std::string &name, ExecutionModel model) const const string &Compiler::get_cleansed_entry_point_name(const std::string &name, ExecutionModel model) const
{ {
return get_entry_point(name, model).name; return get_entry_point(name, model).name;

View File

@ -160,8 +160,6 @@ public:
// Gets a bitmask for the decorations which are applied to ID. // Gets a bitmask for the decorations which are applied to ID.
// I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar) // I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar)
SPIRV_CROSS_DEPRECATED("Please use get_decoration_bitset instead.")
uint64_t get_decoration_mask(uint32_t id) const;
const Bitset &get_decoration_bitset(uint32_t id) const; const Bitset &get_decoration_bitset(uint32_t id) const;
// Returns whether the decoration has been applied to the ID. // Returns whether the decoration has been applied to the ID.
@ -215,8 +213,6 @@ public:
void set_member_qualified_name(uint32_t type_id, uint32_t index, const std::string &name); void set_member_qualified_name(uint32_t type_id, uint32_t index, const std::string &name);
// Gets the decoration mask for a member of a struct, similar to get_decoration_mask. // Gets the decoration mask for a member of a struct, similar to get_decoration_mask.
SPIRV_CROSS_DEPRECATED("Please use get_member_decoration_bitset instead.")
uint64_t get_member_decoration_mask(uint32_t id, uint32_t index) const;
const Bitset &get_member_decoration_bitset(uint32_t id, uint32_t index) const; const Bitset &get_member_decoration_bitset(uint32_t id, uint32_t index) const;
// Returns whether the decoration has been applied to a member of a struct. // Returns whether the decoration has been applied to a member of a struct.
@ -260,9 +256,6 @@ public:
// Returns the effective size of a buffer block struct member. // Returns the effective size of a buffer block struct member.
virtual size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const; virtual size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
// Legacy GLSL compatibility method. Deprecated in favor of CompilerGLSL::flatten_buffer_block
SPIRV_CROSS_DEPRECATED("Please use flatten_buffer_block instead.") void flatten_interface_block(uint32_t id);
// Returns a set of all global variables which are statically accessed // Returns a set of all global variables which are statically accessed
// by the control flow graph from the current entry point. // by the control flow graph from the current entry point.
// Only variables which change the interface for a shader are returned, that is, // Only variables which change the interface for a shader are returned, that is,
@ -303,24 +296,6 @@ public:
// Entry points should be set right after the constructor completes as some reflection functions traverse the graph from the entry point. // Entry points should be set right after the constructor completes as some reflection functions traverse the graph from the entry point.
// Resource reflection also depends on the entry point. // Resource reflection also depends on the entry point.
// By default, the current entry point is set to the first OpEntryPoint which appears in the SPIR-V module. // By default, the current entry point is set to the first OpEntryPoint which appears in the SPIR-V module.
SPIRV_CROSS_DEPRECATED("Please use get_entry_points_and_stages instead.")
std::vector<std::string> get_entry_points() const;
SPIRV_CROSS_DEPRECATED("Please use set_entry_point(const std::string &, spv::ExecutionModel) instead.")
void set_entry_point(const std::string &name);
// Renames an entry point from old_name to new_name.
// If old_name is currently selected as the current entry point, it will continue to be the current entry point,
// albeit with a new name.
// get_entry_points() is essentially invalidated at this point.
SPIRV_CROSS_DEPRECATED(
"Please use rename_entry_point(const std::string&, const std::string&, spv::ExecutionModel) instead.")
void rename_entry_point(const std::string &old_name, const std::string &new_name);
// Returns the internal data structure for entry points to allow poking around.
SPIRV_CROSS_DEPRECATED("Please use get_entry_point(const std::string &, spv::ExecutionModel instead.")
const SPIREntryPoint &get_entry_point(const std::string &name) const;
SPIRV_CROSS_DEPRECATED("Please use get_entry_point(const std::string &, spv::ExecutionModel instead.")
SPIREntryPoint &get_entry_point(const std::string &name);
// Some shader languages restrict the names that can be given to entry points, and the // Some shader languages restrict the names that can be given to entry points, and the
// corresponding backend will automatically rename an entry point name, during the call // corresponding backend will automatically rename an entry point name, during the call
@ -330,15 +305,17 @@ public:
// the name, as updated by the backend during the call to compile(). If the name is not // the name, as updated by the backend during the call to compile(). If the name is not
// illegal, and has not been renamed, or if this function is called before compile(), // illegal, and has not been renamed, or if this function is called before compile(),
// this function will simply return the same name. // this function will simply return the same name.
SPIRV_CROSS_DEPRECATED(
"Please use get_cleansed_entry_point_name(const std::string &, spv::ExecutionModel) instead.")
const std::string &get_cleansed_entry_point_name(const std::string &name) const;
// New variants of entry point query and reflection. // New variants of entry point query and reflection.
// Names for entry points in the SPIR-V module may alias if they belong to different execution models. // Names for entry points in the SPIR-V module may alias if they belong to different execution models.
// To disambiguate, we must pass along with the entry point names the execution model. // To disambiguate, we must pass along with the entry point names the execution model.
std::vector<EntryPoint> get_entry_points_and_stages() const; std::vector<EntryPoint> get_entry_points_and_stages() const;
void set_entry_point(const std::string &entry, spv::ExecutionModel execution_model); void set_entry_point(const std::string &entry, spv::ExecutionModel execution_model);
// Renames an entry point from old_name to new_name.
// If old_name is currently selected as the current entry point, it will continue to be the current entry point,
// albeit with a new name.
// get_entry_points() is essentially invalidated at this point.
void rename_entry_point(const std::string &old_name, const std::string &new_name, void rename_entry_point(const std::string &old_name, const std::string &new_name,
spv::ExecutionModel execution_model); spv::ExecutionModel execution_model);
const SPIREntryPoint &get_entry_point(const std::string &name, spv::ExecutionModel execution_model) const; const SPIREntryPoint &get_entry_point(const std::string &name, spv::ExecutionModel execution_model) const;
@ -347,8 +324,6 @@ public:
spv::ExecutionModel execution_model) const; spv::ExecutionModel execution_model) const;
// Query and modify OpExecutionMode. // Query and modify OpExecutionMode.
SPIRV_CROSS_DEPRECATED("Please use get_execution_mode_bitset instead.")
uint64_t get_execution_mode_mask() const;
const Bitset &get_execution_mode_bitset() const; const Bitset &get_execution_mode_bitset() const;
void unset_execution_mode(spv::ExecutionMode mode); void unset_execution_mode(spv::ExecutionMode mode);

1657
3rdparty/spirv-cross/spirv_cross_c.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

697
3rdparty/spirv-cross/spirv_cross_c.h vendored Normal file
View File

@ -0,0 +1,697 @@
/*
* Copyright 2019 Hans-Kristian Arntzen
*
* 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.
*/
#ifndef SPIRV_CROSS_C_API_H
#define SPIRV_CROSS_C_API_H
#include <stddef.h>
#include "spirv.h"
/*
* C89-compatible wrapper for SPIRV-Cross' API.
* Documentation here is sparse unless the behavior does not map 1:1 with C++ API.
* It is recommended to look at the canonical C++ API for more detailed information.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
#define SPVC_C_API_VERSION_MINOR 1
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
#if !defined(SPVC_PUBLIC_API)
#if defined(SPVC_EXPORT_SYMBOLS)
/* Exports symbols. Standard C calling convention is used. */
#if defined(__GNUC__)
#define SPVC_PUBLIC_API __attribute__((visibility("default")))
#elif defined(_MSC_VER)
#define SPVC_PUBLIC_API __declspec(dllexport)
#else
#define SPVC_PUBLIC_API
#endif
#else
#define SPVC_PUBLIC_API
#endif
#endif
/*
* Gets the SPVC_C_API_VERSION_* used to build this library.
* Can be used to check for ABI mismatch if so-versioning did not catch it.
*/
SPVC_PUBLIC_API void spvc_get_version(unsigned *major, unsigned *minor, unsigned *patch);
/* These types are opaque to the user. */
typedef struct spvc_context_s *spvc_context;
typedef struct spvc_parsed_ir_s *spvc_parsed_ir;
typedef struct spvc_compiler_s *spvc_compiler;
typedef struct spvc_compiler_options_s *spvc_compiler_options;
typedef struct spvc_resources_s *spvc_resources;
struct spvc_type_s;
typedef const struct spvc_type_s *spvc_type;
typedef struct spvc_constant_s *spvc_constant;
struct spvc_set_s;
typedef const struct spvc_set_s *spvc_set;
/*
* Shallow typedefs. All SPIR-V IDs are plain 32-bit numbers, but this helps communicate which data is used.
* Maps to a SPIRType.
*/
typedef SpvId spvc_type_id;
/* Maps to a SPIRVariable. */
typedef SpvId spvc_variable_id;
/* Maps to a SPIRConstant. */
typedef SpvId spvc_constant_id;
/* See C++ API. */
typedef struct spvc_reflected_resource
{
spvc_variable_id id;
spvc_type_id base_type_id;
spvc_type_id type_id;
const char *name;
} spvc_reflected_resource;
/* See C++ API. */
typedef struct spvc_entry_point
{
SpvExecutionModel execution_model;
const char *name;
} spvc_entry_point;
/* See C++ API. */
typedef struct spvc_combined_image_sampler
{
spvc_variable_id combined_id;
spvc_variable_id image_id;
spvc_variable_id sampler_id;
} spvc_combined_image_sampler;
/* See C++ API. */
typedef struct spvc_specialization_constant
{
spvc_constant_id id;
unsigned constant_id;
} spvc_specialization_constant;
/* See C++ API. */
typedef struct spvc_hlsl_root_constants
{
unsigned start;
unsigned end;
unsigned binding;
unsigned space;
} spvc_hlsl_root_constants;
/* See C++ API. */
typedef struct spvc_hlsl_vertex_attribute_remap
{
unsigned location;
const char *semantic;
} spvc_hlsl_vertex_attribute_remap;
/*
* Be compatible with non-C99 compilers, which do not have stdbool.
* Only recent MSVC compilers supports this for example, and ideally SPIRV-Cross should be linkable
* from a wide range of compilers in its C wrapper.
*/
typedef unsigned char spvc_bool;
#define SPVC_TRUE ((spvc_bool)1)
#define SPVC_FALSE ((spvc_bool)0)
typedef enum spvc_result
{
/* Success. */
SPVC_SUCCESS = 0,
/* The SPIR-V is invalid. Should have been caught by validation ideally. */
SPVC_ERROR_INVALID_SPIRV = -1,
/* The SPIR-V might be valid or invalid, but SPIRV-Cross currently cannot correctly translate this to your target language. */
SPVC_ERROR_UNSUPPORTED_SPIRV = -2,
/* If for some reason we hit this, new or malloc failed. */
SPVC_ERROR_OUT_OF_MEMORY = -3,
/* Invalid API argument. */
SPVC_ERROR_INVALID_ARGUMENT = -4,
SPVC_ERROR_INT_MAX = 0x7fffffff
} spvc_result;
typedef enum spvc_capture_mode
{
/* The Parsed IR payload will be copied, and the handle can be reused to create other compiler instances. */
SPVC_CAPTURE_MODE_COPY = 0,
/*
* The payload will now be owned by the compiler.
* parsed_ir should now be considered a dead blob and must not be used further.
* This is optimal for performance and should be the go-to option.
*/
SPVC_CAPTURE_MODE_TAKE_OWNERSHIP = 1,
SPVC_CAPTURE_MODE_INT_MAX = 0x7fffffff
} spvc_capture_mode;
typedef enum spvc_backend
{
/* This backend can only perform reflection, no compiler options are supported. Maps to spirv_cross::Compiler. */
SPVC_BACKEND_NONE = 0,
SPVC_BACKEND_GLSL = 1, /* spirv_cross::CompilerGLSL */
SPVC_BACKEND_HLSL = 2, /* CompilerHLSL */
SPVC_BACKEND_MSL = 3, /* CompilerMSL */
SPVC_BACKEND_CPP = 4, /* CompilerCPP */
SPVC_BACKEND_JSON = 5, /* CompilerReflection w/ JSON backend */
SPVC_BACKEND_INT_MAX = 0x7fffffff
} spvc_backend;
/* Maps to C++ API. */
typedef enum spvc_resource_type
{
SPVC_RESOURCE_TYPE_UNKNOWN = 0,
SPVC_RESOURCE_TYPE_UNIFORM_BUFFER = 1,
SPVC_RESOURCE_TYPE_STORAGE_BUFFER = 2,
SPVC_RESOURCE_TYPE_STAGE_INPUT = 3,
SPVC_RESOURCE_TYPE_STAGE_OUTPUT = 4,
SPVC_RESOURCE_TYPE_SUBPASS_INPUT = 5,
SPVC_RESOURCE_TYPE_STORAGE_IMAGE = 6,
SPVC_RESOURCE_TYPE_SAMPLED_IMAGE = 7,
SPVC_RESOURCE_TYPE_ATOMIC_COUNTER = 8,
SPVC_RESOURCE_TYPE_PUSH_CONSTANT = 9,
SPVC_RESOURCE_TYPE_SEPARATE_IMAGE = 10,
SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS = 11,
SPVC_RESOURCE_TYPE_INT_MAX = 0x7fffffff
} spvc_resource_type;
/* Maps to spirv_cross::SPIRType::BaseType. */
typedef enum spvc_basetype
{
SPVC_BASETYPE_UNKNOWN = 0,
SPVC_BASETYPE_VOID = 1,
SPVC_BASETYPE_BOOLEAN = 2,
SPVC_BASETYPE_INT8 = 3,
SPVC_BASETYPE_UINT8 = 4,
SPVC_BASETYPE_INT16 = 5,
SPVC_BASETYPE_UINT16 = 6,
SPVC_BASETYPE_INT32 = 7,
SPVC_BASETYPE_UINT32 = 8,
SPVC_BASETYPE_INT64 = 9,
SPVC_BASETYPE_UINT64 = 10,
SPVC_BASETYPE_ATOMIC_COUNTER = 11,
SPVC_BASETYPE_FP16 = 12,
SPVC_BASETYPE_FP32 = 13,
SPVC_BASETYPE_FP64 = 14,
SPVC_BASETYPE_STRUCT = 15,
SPVC_BASETYPE_IMAGE = 16,
SPVC_BASETYPE_SAMPLED_IMAGE = 17,
SPVC_BASETYPE_SAMPLER = 18,
SPVC_BASETYPE_INT_MAX = 0x7fffffff
} spvc_basetype;
#define SPVC_COMPILER_OPTION_COMMON_BIT 0x1000000
#define SPVC_COMPILER_OPTION_GLSL_BIT 0x2000000
#define SPVC_COMPILER_OPTION_HLSL_BIT 0x4000000
#define SPVC_COMPILER_OPTION_MSL_BIT 0x8000000
#define SPVC_COMPILER_OPTION_LANG_BITS 0x0f000000
#define SPVC_COMPILER_OPTION_ENUM_BITS 0xffffff
#define SPVC_MAKE_MSL_VERSION(major, minor, patch) ((major) * 10000 + (minor) * 100 + (patch))
/* Maps to C++ API. */
typedef enum spvc_msl_platform
{
SPVC_MSL_PLATFORM_IOS = 0,
SPVC_MSL_PLATFORM_MACOS = 1,
SPVC_MSL_PLATFORM_MAX_INT = 0x7fffffff
} spvc_msl_platform;
/* Maps to C++ API. */
typedef enum spvc_msl_vertex_format
{
SPVC_MSL_VERTEX_FORMAT_OTHER = 0,
SPVC_MSL_VERTEX_FORMAT_UINT8 = 1,
SPVC_MSL_VERTEX_FORMAT_UINT16 = 2
} spvc_msl_vertex_format;
/* Maps to C++ API. */
typedef struct spvc_msl_vertex_attribute
{
unsigned location;
unsigned msl_buffer;
unsigned msl_offset;
unsigned msl_stride;
spvc_bool per_instance;
spvc_msl_vertex_format format;
SpvBuiltIn builtin;
} spvc_msl_vertex_attribute;
/*
* Initializes the vertex attribute struct.
*/
SPVC_PUBLIC_API void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr);
/* Maps to C++ API. */
typedef struct spvc_msl_resource_binding
{
SpvExecutionModel stage;
unsigned desc_set;
unsigned binding;
unsigned msl_buffer;
unsigned msl_texture;
unsigned msl_sampler;
} spvc_msl_resource_binding;
/*
* Initializes the resource binding struct.
* The defaults are non-zero.
*/
SPVC_PUBLIC_API void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding);
#define SPVC_MSL_PUSH_CONSTANT_DESC_SET (~(0u))
#define SPVC_MSL_PUSH_CONSTANT_BINDING (0)
#define SPVC_MSL_AUX_BUFFER_STRUCT_VERSION 1
/* Runtime check for incompatibility. */
SPVC_PUBLIC_API unsigned spvc_msl_get_aux_buffer_struct_version(void);
/* Maps to C++ API. */
typedef enum spvc_msl_sampler_coord
{
SPVC_MSL_SAMPLER_COORD_NORMALIZED = 0,
SPVC_MSL_SAMPLER_COORD_PIXEL = 1,
SPVC_MSL_SAMPLER_INT_MAX = 0x7fffffff
} spvc_msl_sampler_coord;
/* Maps to C++ API. */
typedef enum spvc_msl_sampler_filter
{
SPVC_MSL_SAMPLER_FILTER_NEAREST = 0,
SPVC_MSL_SAMPLER_FILTER_LINEAR = 1,
SPVC_MSL_SAMPLER_FILTER_INT_MAX = 0x7fffffff
} spvc_msl_sampler_filter;
/* Maps to C++ API. */
typedef enum spvc_msl_sampler_mip_filter
{
SPVC_MSL_SAMPLER_MIP_FILTER_NONE = 0,
SPVC_MSL_SAMPLER_MIP_FILTER_NEAREST = 1,
SPVC_MSL_SAMPLER_MIP_FILTER_LINEAR = 2,
SPVC_MSL_SAMPLER_MIP_FILTER_INT_MAX = 0x7fffffff
} spvc_msl_sampler_mip_filter;
/* Maps to C++ API. */
typedef enum spvc_msl_sampler_address
{
SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_ZERO = 0,
SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE = 1,
SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_BORDER = 2,
SPVC_MSL_SAMPLER_ADDRESS_REPEAT = 3,
SPVC_MSL_SAMPLER_ADDRESS_MIRRORED_REPEAT = 4,
SPVC_MSL_SAMPLER_ADDRESS_INT_MAX = 0x7fffffff
} spvc_msl_sampler_address;
/* Maps to C++ API. */
typedef enum spvc_msl_sampler_compare_func
{
SPVC_MSL_SAMPLER_COMPARE_FUNC_NEVER = 0,
SPVC_MSL_SAMPLER_COMPARE_FUNC_LESS = 1,
SPVC_MSL_SAMPLER_COMPARE_FUNC_LESS_EQUAL = 2,
SPVC_MSL_SAMPLER_COMPARE_FUNC_GREATER = 3,
SPVC_MSL_SAMPLER_COMPARE_FUNC_GREATER_EQUAL = 4,
SPVC_MSL_SAMPLER_COMPARE_FUNC_EQUAL = 5,
SPVC_MSL_SAMPLER_COMPARE_FUNC_NOT_EQUAL = 6,
SPVC_MSL_SAMPLER_COMPARE_FUNC_ALWAYS = 7,
SPVC_MSL_SAMPLER_COMPARE_FUNC_INT_MAX = 0x7fffffff
} spvc_msl_sampler_compare_func;
/* Maps to C++ API. */
typedef enum spvc_msl_sampler_border_color
{
SPVC_MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK = 0,
SPVC_MSL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK = 1,
SPVC_MSL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE = 2,
SPVC_MSL_SAMPLER_BORDER_COLOR_INT_MAX = 0x7fffffff
} spvc_msl_sampler_border_color;
/* Maps to C++ API. */
typedef struct spvc_msl_constexpr_sampler
{
spvc_msl_sampler_coord coord;
spvc_msl_sampler_filter min_filter;
spvc_msl_sampler_filter mag_filter;
spvc_msl_sampler_mip_filter mip_filter;
spvc_msl_sampler_address s_address;
spvc_msl_sampler_address t_address;
spvc_msl_sampler_address r_address;
spvc_msl_sampler_compare_func compare_func;
spvc_msl_sampler_border_color border_color;
float lod_clamp_min;
float lod_clamp_max;
int max_anisotropy;
spvc_bool compare_enable;
spvc_bool lod_clamp_enable;
spvc_bool anisotropy_enable;
} spvc_msl_constexpr_sampler;
/*
* Initializes the constexpr sampler struct.
* The defaults are non-zero.
*/
SPVC_PUBLIC_API void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler);
/* Maps to the various spirv_cross::Compiler*::Option structures. See C++ API for defaults and details. */
typedef enum spvc_compiler_option
{
SPVC_COMPILER_OPTION_UNKNOWN = 0,
SPVC_COMPILER_OPTION_FORCE_TEMPORARY = 1 | SPVC_COMPILER_OPTION_COMMON_BIT,
SPVC_COMPILER_OPTION_FLATTEN_MULTIDIMENSIONAL_ARRAYS = 2 | SPVC_COMPILER_OPTION_COMMON_BIT,
SPVC_COMPILER_OPTION_FIXUP_DEPTH_CONVENTION = 3 | SPVC_COMPILER_OPTION_COMMON_BIT,
SPVC_COMPILER_OPTION_FLIP_VERTEX_Y = 4 | SPVC_COMPILER_OPTION_COMMON_BIT,
SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE = 5 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_SEPARATE_SHADER_OBJECTS = 6 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION = 7 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_VERSION = 8 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_ES = 9 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS = 10 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_FLOAT_PRECISION_HIGHP = 11 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_INT_PRECISION_HIGHP = 12 | SPVC_COMPILER_OPTION_GLSL_BIT,
SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL = 13 | SPVC_COMPILER_OPTION_HLSL_BIT,
SPVC_COMPILER_OPTION_HLSL_POINT_SIZE_COMPAT = 14 | SPVC_COMPILER_OPTION_HLSL_BIT,
SPVC_COMPILER_OPTION_HLSL_POINT_COORD_COMPAT = 15 | SPVC_COMPILER_OPTION_HLSL_BIT,
SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE = 16 | SPVC_COMPILER_OPTION_HLSL_BIT,
SPVC_COMPILER_OPTION_MSL_VERSION = 17 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_TEXEL_BUFFER_TEXTURE_WIDTH = 18 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_AUX_BUFFER_INDEX = 19 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_INDIRECT_PARAMS_BUFFER_INDEX = 20 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_SHADER_OUTPUT_BUFFER_INDEX = 21 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_OUTPUT_BUFFER_INDEX = 22 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_SHADER_TESS_FACTOR_OUTPUT_BUFFER_INDEX = 23 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_WORKGROUP_INDEX = 24 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_BUILTIN = 25 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_DISABLE_RASTERIZATION = 26 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_CAPTURE_OUTPUT_TO_BUFFER = 27 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_SWIZZLE_TEXTURE_SAMPLES = 28 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS = 29 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_TESS_DOMAIN_ORIGIN_LOWER_LEFT = 30 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_PLATFORM = 31 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
} spvc_compiler_option;
/*
* Context is the highest-level API construct.
* The context owns all memory allocations made by its child object hierarchy, including various non-opaque structs and strings.
* This means that the API user only has to care about one "destroy" call ever when using the C API.
* All pointers handed out by the APIs are only valid as long as the context
* is alive and spvc_context_release_allocations has not been called.
*/
SPVC_PUBLIC_API spvc_result spvc_context_create(spvc_context *context);
/* Frees all memory allocations and objects associated with the context and its child objects. */
SPVC_PUBLIC_API void spvc_context_destroy(spvc_context context);
/* Frees all memory allocations and objects associated with the context and its child objects, but keeps the context alive. */
SPVC_PUBLIC_API void spvc_context_release_allocations(spvc_context context);
/* Get the string for the last error which was logged. */
SPVC_PUBLIC_API const char *spvc_context_get_last_error_string(spvc_context context);
/* Get notified in a callback when an error triggers. Useful for debugging. */
typedef void (*spvc_error_callback)(void *userdata, const char *error);
SPVC_PUBLIC_API void spvc_context_set_error_callback(spvc_context context, spvc_error_callback cb, void *userdata);
/* SPIR-V parsing interface. Maps to Parser which then creates a ParsedIR, and that IR is extracted into the handle. */
SPVC_PUBLIC_API spvc_result spvc_context_parse_spirv(spvc_context context, const SpvId *spirv, size_t word_count,
spvc_parsed_ir *parsed_ir);
/*
* Create a compiler backend. Capture mode controls if we construct by copy or move semantics.
* It is always recommended to use SPVC_CAPTURE_MODE_TAKE_OWNERSHIP if you only intend to cross-compile the IR once.
*/
SPVC_PUBLIC_API spvc_result spvc_context_create_compiler(spvc_context context, spvc_backend backend,
spvc_parsed_ir parsed_ir, spvc_capture_mode mode,
spvc_compiler *compiler);
/* Maps directly to C++ API. */
SPVC_PUBLIC_API unsigned spvc_compiler_get_current_id_bound(spvc_compiler compiler);
/* Create compiler options, which will initialize defaults. */
SPVC_PUBLIC_API spvc_result spvc_compiler_create_compiler_options(spvc_compiler compiler,
spvc_compiler_options *options);
/* Override options. Will return error if e.g. MSL options are used for the HLSL backend, etc. */
SPVC_PUBLIC_API spvc_result spvc_compiler_options_set_bool(spvc_compiler_options options,
spvc_compiler_option option, spvc_bool value);
SPVC_PUBLIC_API spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options,
spvc_compiler_option option, unsigned value);
/* Set compiler options. */
SPVC_PUBLIC_API spvc_result spvc_compiler_install_compiler_options(spvc_compiler compiler,
spvc_compiler_options options);
/* Compile IR into a string. *source is owned by the context, and caller must not free it themselves. */
SPVC_PUBLIC_API spvc_result spvc_compiler_compile(spvc_compiler compiler, const char **source);
/* Maps to C++ API. */
SPVC_PUBLIC_API spvc_result spvc_compiler_add_header_line(spvc_compiler compiler, const char *line);
SPVC_PUBLIC_API spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *ext);
SPVC_PUBLIC_API spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id);
/*
* HLSL specifics.
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_set_root_constants_layout(spvc_compiler compiler,
const spvc_hlsl_root_constants *constant_info,
size_t count);
SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_vertex_attribute_remap(spvc_compiler compiler,
const spvc_hlsl_vertex_attribute_remap *remap,
size_t remaps);
SPVC_PUBLIC_API spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin(spvc_compiler compiler);
/*
* MSL specifics.
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler);
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_aux_buffer(spvc_compiler compiler);
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_output_buffer(spvc_compiler compiler);
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_patch_output_buffer(spvc_compiler compiler);
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_input_threadgroup_mem(spvc_compiler compiler);
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler,
const spvc_msl_vertex_attribute *attrs);
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler,
const spvc_msl_resource_binding *binding);
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location);
SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler,
SpvExecutionModel model,
unsigned set,
unsigned binding);
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler(spvc_compiler compiler, spvc_variable_id id, const spvc_msl_constexpr_sampler *sampler);
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_fragment_output_components(spvc_compiler compiler, unsigned location, unsigned components);
/*
* Reflect resources.
* Maps almost 1:1 to C++ API.
*/
SPVC_PUBLIC_API spvc_result spvc_compiler_get_active_interface_variables(spvc_compiler compiler, spvc_set *set);
SPVC_PUBLIC_API spvc_result spvc_compiler_set_enabled_interface_variables(spvc_compiler compiler, spvc_set set);
SPVC_PUBLIC_API spvc_result spvc_compiler_create_shader_resources(spvc_compiler compiler, spvc_resources *resources);
SPVC_PUBLIC_API spvc_result spvc_compiler_create_shader_resources_for_active_variables(spvc_compiler compiler,
spvc_resources *resources,
spvc_set active);
SPVC_PUBLIC_API spvc_result spvc_resources_get_resource_list_for_type(spvc_resources resources, spvc_resource_type type,
const spvc_reflected_resource **resource_list,
size_t *resource_size);
/*
* Decorations.
* Maps to C++ API.
*/
SPVC_PUBLIC_API void spvc_compiler_set_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration,
unsigned argument);
SPVC_PUBLIC_API void spvc_compiler_set_decoration_string(spvc_compiler compiler, SpvId id, SpvDecoration decoration,
const char *argument);
SPVC_PUBLIC_API void spvc_compiler_set_name(spvc_compiler compiler, SpvId id, const char *argument);
SPVC_PUBLIC_API void spvc_compiler_set_member_decoration(spvc_compiler compiler, spvc_type_id id, unsigned member_index,
SpvDecoration decoration, unsigned argument);
SPVC_PUBLIC_API void spvc_compiler_set_member_decoration_string(spvc_compiler compiler, spvc_type_id id,
unsigned member_index, SpvDecoration decoration,
const char *argument);
SPVC_PUBLIC_API void spvc_compiler_set_member_name(spvc_compiler compiler, spvc_type_id id, unsigned member_index,
const char *argument);
SPVC_PUBLIC_API void spvc_compiler_unset_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration);
SPVC_PUBLIC_API void spvc_compiler_unset_member_decoration(spvc_compiler compiler, spvc_type_id id,
unsigned member_index, SpvDecoration decoration);
SPVC_PUBLIC_API spvc_bool spvc_compiler_has_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration);
SPVC_PUBLIC_API spvc_bool spvc_compiler_has_member_decoration(spvc_compiler compiler, spvc_type_id id,
unsigned member_index, SpvDecoration decoration);
SPVC_PUBLIC_API const char *spvc_compiler_get_name(spvc_compiler compiler, SpvId id);
SPVC_PUBLIC_API unsigned spvc_compiler_get_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration);
SPVC_PUBLIC_API const char *spvc_compiler_get_decoration_string(spvc_compiler compiler, SpvId id,
SpvDecoration decoration);
SPVC_PUBLIC_API unsigned spvc_compiler_get_member_decoration(spvc_compiler compiler, spvc_type_id id,
unsigned member_index, SpvDecoration decoration);
SPVC_PUBLIC_API const char *spvc_compiler_get_member_decoration_string(spvc_compiler compiler, spvc_type_id id,
unsigned member_index, SpvDecoration decoration);
/*
* Entry points.
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_result spvc_compiler_get_entry_points(spvc_compiler compiler,
const spvc_entry_point **entry_points,
size_t *num_entry_points);
SPVC_PUBLIC_API spvc_result spvc_compiler_set_entry_point(spvc_compiler compiler, const char *name,
SpvExecutionModel model);
SPVC_PUBLIC_API spvc_result spvc_compiler_rename_entry_point(spvc_compiler compiler, const char *old_name,
const char *new_name, SpvExecutionModel model);
SPVC_PUBLIC_API const char *spvc_compiler_get_cleansed_entry_point_name(spvc_compiler compiler, const char *name,
SpvExecutionModel model);
SPVC_PUBLIC_API void spvc_compiler_set_execution_mode(spvc_compiler compiler, SpvExecutionMode mode);
SPVC_PUBLIC_API void spvc_compiler_unset_execution_mode(spvc_compiler compiler, SpvExecutionMode mode);
SPVC_PUBLIC_API void spvc_compiler_set_execution_mode_with_arguments(spvc_compiler compiler, SpvExecutionMode mode,
unsigned arg0, unsigned arg1, unsigned arg2);
SPVC_PUBLIC_API spvc_result spvc_compiler_get_execution_modes(spvc_compiler compiler, const SpvExecutionMode **modes,
size_t *num_modes);
SPVC_PUBLIC_API unsigned spvc_compiler_get_execution_mode_argument(spvc_compiler compiler, SpvExecutionMode mode);
SPVC_PUBLIC_API unsigned spvc_compiler_get_execution_mode_argument_by_index(spvc_compiler compiler,
SpvExecutionMode mode, unsigned index);
SPVC_PUBLIC_API SpvExecutionModel spvc_compiler_get_execution_model(spvc_compiler compiler);
/*
* Type query interface.
* Maps to C++ API, except it's read-only.
*/
SPVC_PUBLIC_API spvc_type spvc_compiler_get_type_handle(spvc_compiler compiler, spvc_type_id id);
SPVC_PUBLIC_API spvc_basetype spvc_type_get_basetype(spvc_type type);
SPVC_PUBLIC_API unsigned spvc_type_get_bit_width(spvc_type type);
SPVC_PUBLIC_API unsigned spvc_type_get_vector_size(spvc_type type);
SPVC_PUBLIC_API unsigned spvc_type_get_columns(spvc_type type);
SPVC_PUBLIC_API unsigned spvc_type_get_num_array_dimensions(spvc_type type);
SPVC_PUBLIC_API spvc_bool spvc_type_array_dimension_is_literal(spvc_type type, unsigned dimension);
SPVC_PUBLIC_API SpvId spvc_type_get_array_dimension(spvc_type type, unsigned dimension);
SPVC_PUBLIC_API unsigned spvc_type_get_num_member_types(spvc_type type);
SPVC_PUBLIC_API spvc_type_id spvc_type_get_member_type(spvc_type type, unsigned index);
SPVC_PUBLIC_API SpvStorageClass spvc_type_get_storage_class(spvc_type type);
/* Image type query. */
SPVC_PUBLIC_API spvc_type_id spvc_type_get_image_sampled_type(spvc_type type);
SPVC_PUBLIC_API SpvDim spvc_type_get_image_dimension(spvc_type type);
SPVC_PUBLIC_API spvc_bool spvc_type_get_image_is_depth(spvc_type type);
SPVC_PUBLIC_API spvc_bool spvc_type_get_image_arrayed(spvc_type type);
SPVC_PUBLIC_API spvc_bool spvc_type_get_image_multisampled(spvc_type type);
SPVC_PUBLIC_API spvc_bool spvc_type_get_image_is_storage(spvc_type type);
SPVC_PUBLIC_API SpvImageFormat spvc_type_get_image_storage_format(spvc_type type);
SPVC_PUBLIC_API SpvAccessQualifier spvc_type_get_image_access_qualifier(spvc_type type);
/*
* Buffer layout query.
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_struct_size(spvc_compiler compiler, spvc_type struct_type, size_t *size);
SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_struct_size_runtime_array(spvc_compiler compiler,
spvc_type struct_type, size_t array_size, size_t *size);
SPVC_PUBLIC_API spvc_result spvc_compiler_type_struct_member_offset(spvc_compiler compiler,
spvc_type type, unsigned index, unsigned *offset);
SPVC_PUBLIC_API spvc_result spvc_compiler_type_struct_member_array_stride(spvc_compiler compiler,
spvc_type type, unsigned index, unsigned *stride);
SPVC_PUBLIC_API spvc_result spvc_compiler_type_struct_member_matrix_stride(spvc_compiler compiler,
spvc_type type, unsigned index, unsigned *stride);
/*
* Workaround helper functions.
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_result spvc_compiler_build_dummy_sampler_for_combined_images(spvc_compiler compiler, spvc_variable_id *id);
SPVC_PUBLIC_API spvc_result spvc_compiler_build_combined_image_samplers(spvc_compiler compiler);
SPVC_PUBLIC_API spvc_result spvc_compiler_get_combined_image_samplers(spvc_compiler compiler,
const spvc_combined_image_sampler **samplers,
size_t *num_samplers);
/*
* Constants
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_result spvc_compiler_get_specialization_constants(spvc_compiler compiler,
const spvc_specialization_constant **constants,
size_t *num_constants);
SPVC_PUBLIC_API spvc_constant spvc_compiler_get_constant_handle(spvc_compiler compiler,
spvc_constant_id id);
SPVC_PUBLIC_API spvc_constant_id spvc_compiler_get_work_group_size_specialization_constants(spvc_compiler compiler,
spvc_specialization_constant *x,
spvc_specialization_constant *y,
spvc_specialization_constant *z);
/*
* No stdint.h until C99, sigh :(
* For smaller types, the result is sign or zero-extended as appropriate.
* Maps to C++ API.
* TODO: The SPIRConstant query interface and modification interface is not quite complete.
*/
SPVC_PUBLIC_API float spvc_constant_get_scalar_fp16(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API float spvc_constant_get_scalar_fp32(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API double spvc_constant_get_scalar_fp64(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API unsigned spvc_constant_get_scalar_u32(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API int spvc_constant_get_scalar_i32(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API unsigned spvc_constant_get_scalar_u16(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API int spvc_constant_get_scalar_i16(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API unsigned spvc_constant_get_scalar_u8(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API int spvc_constant_get_scalar_i8(spvc_constant constant, unsigned column, unsigned row);
SPVC_PUBLIC_API void spvc_constant_get_subconstants(spvc_constant constant, const spvc_constant_id **constituents, size_t *count);
SPVC_PUBLIC_API spvc_type_id spvc_constant_get_type(spvc_constant constant);
/*
* Misc reflection
* Maps to C++ API.
*/
SPVC_PUBLIC_API spvc_bool spvc_compiler_get_binary_offset_for_decoration(spvc_compiler compiler,
spvc_variable_id id,
SpvDecoration decoration,
unsigned *word_offset);
SPVC_PUBLIC_API spvc_bool spvc_compiler_buffer_is_hlsl_counter_buffer(spvc_compiler compiler, spvc_variable_id id);
SPVC_PUBLIC_API spvc_bool spvc_compiler_buffer_get_hlsl_counter_buffer(spvc_compiler compiler, spvc_variable_id id,
spvc_variable_id *counter_id);
SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_capabilities(spvc_compiler compiler,
const SpvCapability **capabilities,
size_t *num_capabilities);
SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_extensions(spvc_compiler compiler, const char ***extensions,
size_t *num_extensions);
SPVC_PUBLIC_API const char *spvc_compiler_get_remapped_declared_block_name(spvc_compiler compiler, spvc_variable_id id);
SPVC_PUBLIC_API spvc_result spvc_compiler_get_buffer_block_decorations(spvc_compiler compiler, spvc_variable_id id,
const SpvDecoration **decorations,
size_t *num_decorations);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -10205,7 +10205,7 @@ void CompilerGLSL::propagate_loop_dominators(const SPIRBlock &block)
// FIXME: This currently cannot handle complex continue blocks // FIXME: This currently cannot handle complex continue blocks
// as in do-while. // as in do-while.
// This should be seen as a "trivial" continue block. // This should be seen as a "trivial" continue block.
string CompilerGLSL::emit_continue_block(uint32_t continue_block) string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block)
{ {
auto *block = &get<SPIRBlock>(continue_block); auto *block = &get<SPIRBlock>(continue_block);
@ -10233,11 +10233,20 @@ string CompilerGLSL::emit_continue_block(uint32_t continue_block)
block = &get<SPIRBlock>(block->next_block); block = &get<SPIRBlock>(block->next_block);
} }
// For do while blocks. The last block will be a select block. // For do while blocks. The last block will be a select block.
else if (block->true_block) else if (block->true_block && follow_true_block)
{ {
flush_phi(continue_block, block->true_block); flush_phi(continue_block, block->true_block);
block = &get<SPIRBlock>(block->true_block); block = &get<SPIRBlock>(block->true_block);
} }
else if (block->false_block && follow_false_block)
{
flush_phi(continue_block, block->false_block);
block = &get<SPIRBlock>(block->false_block);
}
else
{
SPIRV_CROSS_THROW("Invalid continue block detected!");
}
} }
// Restore old pointer. // Restore old pointer.
@ -10392,10 +10401,15 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
// emitting the continue block can invalidate the condition expression. // emitting the continue block can invalidate the condition expression.
auto initializer = emit_for_loop_initializers(block); auto initializer = emit_for_loop_initializers(block);
auto condition = to_expression(block.condition); auto condition = to_expression(block.condition);
// Condition might have to be inverted.
if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
condition = join("!", enclose_expression(condition));
emit_block_hints(block); emit_block_hints(block);
if (method != SPIRBlock::MergeToSelectContinueForLoop) if (method != SPIRBlock::MergeToSelectContinueForLoop)
{ {
auto continue_block = emit_continue_block(block.continue_block); auto continue_block = emit_continue_block(block.continue_block, false, false);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")"); statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
} }
else else
@ -10404,12 +10418,20 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
} }
case SPIRBlock::WhileLoop: case SPIRBlock::WhileLoop:
{
// This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header. // This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
flush_undeclared_variables(block); flush_undeclared_variables(block);
emit_while_loop_initializers(block); emit_while_loop_initializers(block);
emit_block_hints(block); emit_block_hints(block);
statement("while (", to_expression(block.condition), ")");
auto condition = to_expression(block.condition);
// Condition might have to be inverted.
if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
condition = join("!", enclose_expression(condition));
statement("while (", condition, ")");
break; break;
}
default: default:
SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics."); SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
@ -10445,6 +10467,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
if (current_count == statement_count && condition_is_temporary) if (current_count == statement_count && condition_is_temporary)
{ {
propagate_loop_dominators(child); propagate_loop_dominators(child);
uint32_t target_block = child.true_block;
switch (continue_type) switch (continue_type)
{ {
@ -10454,24 +10477,43 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
// emitting the continue block can invalidate the condition expression. // emitting the continue block can invalidate the condition expression.
auto initializer = emit_for_loop_initializers(block); auto initializer = emit_for_loop_initializers(block);
auto condition = to_expression(child.condition); auto condition = to_expression(child.condition);
auto continue_block = emit_continue_block(block.continue_block);
// Condition might have to be inverted.
if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
{
condition = join("!", enclose_expression(condition));
target_block = child.false_block;
}
auto continue_block = emit_continue_block(block.continue_block, false, false);
emit_block_hints(block); emit_block_hints(block);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")"); statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
break; break;
} }
case SPIRBlock::WhileLoop: case SPIRBlock::WhileLoop:
{
emit_while_loop_initializers(block); emit_while_loop_initializers(block);
emit_block_hints(block); emit_block_hints(block);
statement("while (", to_expression(child.condition), ")");
auto condition = to_expression(child.condition);
// Condition might have to be inverted.
if (execution_is_noop(get<SPIRBlock>(child.true_block), get<SPIRBlock>(block.merge_block)))
{
condition = join("!", enclose_expression(condition));
target_block = child.false_block;
}
statement("while (", condition, ")");
break; break;
}
default: default:
SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics."); SPIRV_CROSS_THROW("For/while loop detected, but need while/for loop semantics.");
} }
begin_scope(); begin_scope();
branch(child.self, child.true_block); branch(child.self, target_block);
return true; return true;
} }
else else
@ -10521,8 +10563,9 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
propagate_loop_dominators(block); propagate_loop_dominators(block);
bool select_branch_to_true_block = false; bool select_branch_to_true_block = false;
bool select_branch_to_false_block = false;
bool skip_direct_branch = false; bool skip_direct_branch = false;
bool emitted_for_loop_header = false; bool emitted_loop_header_variables = false;
bool force_complex_continue_block = false; bool force_complex_continue_block = false;
emit_hoisted_temporaries(block.declare_temporary); emit_hoisted_temporaries(block.declare_temporary);
@ -10544,8 +10587,12 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
flush_undeclared_variables(block); flush_undeclared_variables(block);
if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop)) if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
{ {
select_branch_to_true_block = true; if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
emitted_for_loop_header = true; select_branch_to_false_block = true;
else
select_branch_to_true_block = true;
emitted_loop_header_variables = true;
force_complex_continue_block = true; force_complex_continue_block = true;
} }
} }
@ -10555,9 +10602,13 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
flush_undeclared_variables(block); flush_undeclared_variables(block);
if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop)) if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
{ {
// The body of while, is actually just the true block, so always branch there unconditionally. // The body of while, is actually just the true (or false) block, so always branch there unconditionally.
select_branch_to_true_block = true; if (execution_is_noop(get<SPIRBlock>(block.true_block), get<SPIRBlock>(block.merge_block)))
emitted_for_loop_header = true; select_branch_to_false_block = true;
else
select_branch_to_true_block = true;
emitted_loop_header_variables = true;
} }
} }
// This is the newer loop behavior in glslang which branches from Loop header directly to // This is the newer loop behavior in glslang which branches from Loop header directly to
@ -10568,13 +10619,14 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop)) if (attempt_emit_loop_header(block, SPIRBlock::MergeToDirectForLoop))
{ {
skip_direct_branch = true; skip_direct_branch = true;
emitted_for_loop_header = true; emitted_loop_header_variables = true;
} }
} }
else if (continue_type == SPIRBlock::DoWhileLoop) else if (continue_type == SPIRBlock::DoWhileLoop)
{ {
flush_undeclared_variables(block); flush_undeclared_variables(block);
emit_while_loop_initializers(block); emit_while_loop_initializers(block);
emitted_loop_header_variables = true;
// We have some temporaries where the loop header is the dominator. // We have some temporaries where the loop header is the dominator.
// We risk a case where we have code like: // We risk a case where we have code like:
// for (;;) { create-temporary; break; } consume-temporary; // for (;;) { create-temporary; break; } consume-temporary;
@ -10589,6 +10641,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
{ {
flush_undeclared_variables(block); flush_undeclared_variables(block);
emit_while_loop_initializers(block); emit_while_loop_initializers(block);
emitted_loop_header_variables = true;
// We have a generic loop without any distinguishable pattern like for, while or do while. // We have a generic loop without any distinguishable pattern like for, while or do while.
get<SPIRBlock>(block.continue_block).complex_continue = true; get<SPIRBlock>(block.continue_block).complex_continue = true;
@ -10611,7 +10664,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem // If we didn't successfully emit a loop header and we had loop variable candidates, we have a problem
// as writes to said loop variables might have been masked out, we need a recompile. // as writes to said loop variables might have been masked out, we need a recompile.
if (!emitted_for_loop_header && !block.loop_variables.empty()) if (!emitted_loop_header_variables && !block.loop_variables.empty())
{ {
force_recompile = true; force_recompile = true;
for (auto var : block.loop_variables) for (auto var : block.loop_variables)
@ -10660,6 +10713,22 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
else else
branch(block.self, block.true_block); branch(block.self, block.true_block);
} }
else if (select_branch_to_false_block)
{
if (force_complex_continue_block)
{
assert(block.false_block == block.continue_block);
// We're going to emit a continue block directly here, so make sure it's marked as complex.
auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
bool old_complex = complex_continue;
complex_continue = true;
branch(block.self, block.false_block);
complex_continue = old_complex;
}
else
branch(block.self, block.false_block);
}
else else
branch(block.self, block.condition, block.true_block, block.false_block); branch(block.self, block.condition, block.true_block, block.false_block);
break; break;
@ -10850,7 +10919,11 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// Make sure that we run the continue block to get the expressions set, but this // Make sure that we run the continue block to get the expressions set, but this
// should become an empty string. // should become an empty string.
// We have no fallbacks if we cannot forward everything to temporaries ... // We have no fallbacks if we cannot forward everything to temporaries ...
auto statements = emit_continue_block(block.continue_block); const auto &continue_block = get<SPIRBlock>(block.continue_block);
bool positive_test = execution_is_noop(get<SPIRBlock>(continue_block.true_block),
get<SPIRBlock>(continue_block.loop_dominator));
auto statements = emit_continue_block(block.continue_block, positive_test, !positive_test);
if (!statements.empty()) if (!statements.empty())
{ {
// The DoWhile block has side effects, force ComplexLoop pattern next pass. // The DoWhile block has side effects, force ComplexLoop pattern next pass.
@ -10858,7 +10931,12 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
force_recompile = true; force_recompile = true;
} }
end_scope_decl(join("while (", to_expression(get<SPIRBlock>(block.continue_block).condition), ")")); // Might have to invert the do-while test here.
auto condition = to_expression(continue_block.condition);
if (!positive_test)
condition = join("!", enclose_expression(condition));
end_scope_decl(join("while (", condition, ")"));
} }
else else
end_scope(); end_scope();

View File

@ -161,27 +161,11 @@ public:
init(); init();
} }
// Deprecate this interface because it doesn't overload properly with subclasses.
// Requires awkward static casting, which was a mistake.
SPIRV_CROSS_DEPRECATED("get_options() is obsolete, use get_common_options() instead.")
const Options &get_options() const
{
return options;
}
const Options &get_common_options() const const Options &get_common_options() const
{ {
return options; return options;
} }
// Deprecate this interface because it doesn't overload properly with subclasses.
// Requires awkward static casting, which was a mistake.
SPIRV_CROSS_DEPRECATED("set_options() is obsolete, use set_common_options() instead.")
void set_options(Options &opts)
{
options = opts;
}
void set_common_options(const Options &opts) void set_common_options(const Options &opts)
{ {
options = opts; options = opts;
@ -419,7 +403,7 @@ protected:
std::string constant_value_macro_name(uint32_t id); std::string constant_value_macro_name(uint32_t id);
void emit_constant(const SPIRConstant &constant); void emit_constant(const SPIRConstant &constant);
void emit_specialization_constant_op(const SPIRConstantOp &constant); void emit_specialization_constant_op(const SPIRConstantOp &constant);
std::string emit_continue_block(uint32_t continue_block); std::string emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block);
bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method); bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method);
void propagate_loop_dominators(const SPIRBlock &block); void propagate_loop_dominators(const SPIRBlock &block);

View File

@ -4558,10 +4558,14 @@ void CompilerHLSL::require_texture_query_variant(const SPIRType &type)
} }
} }
string CompilerHLSL::compile(std::vector<HLSLVertexAttributeRemap> vertex_attributes) void CompilerHLSL::set_root_constant_layouts(vector<RootConstants> layout)
{ {
remap_vertex_attributes = move(vertex_attributes); root_constants_layout = move(layout);
return compile(); }
void CompilerHLSL::add_vertex_attribute_remap(const HLSLVertexAttributeRemap &vertex_attributes)
{
remap_vertex_attributes.push_back(vertex_attributes);
} }
uint32_t CompilerHLSL::remap_num_workgroups_builtin() uint32_t CompilerHLSL::remap_num_workgroups_builtin()

View File

@ -82,23 +82,11 @@ public:
{ {
} }
SPIRV_CROSS_DEPRECATED("CompilerHLSL::get_options() is obsolete, use get_hlsl_options() instead.")
const Options &get_options() const
{
return hlsl_options;
}
const Options &get_hlsl_options() const const Options &get_hlsl_options() const
{ {
return hlsl_options; return hlsl_options;
} }
SPIRV_CROSS_DEPRECATED("CompilerHLSL::get_options() is obsolete, use set_hlsl_options() instead.")
void set_options(Options &opts)
{
hlsl_options = opts;
}
void set_hlsl_options(const Options &opts) void set_hlsl_options(const Options &opts)
{ {
hlsl_options = opts; hlsl_options = opts;
@ -108,16 +96,13 @@ public:
// //
// Push constants ranges will be split up according to the // Push constants ranges will be split up according to the
// layout specified. // layout specified.
void set_root_constant_layouts(std::vector<RootConstants> layout) void set_root_constant_layouts(std::vector<RootConstants> layout);
{
root_constants_layout = std::move(layout);
}
// Compiles and remaps vertex attributes at specific locations to a fixed semantic. // Compiles and remaps vertex attributes at specific locations to a fixed semantic.
// The default is TEXCOORD# where # denotes location. // The default is TEXCOORD# where # denotes location.
// Matrices are unrolled to vectors with notation ${SEMANTIC}_#, where # denotes row. // Matrices are unrolled to vectors with notation ${SEMANTIC}_#, where # denotes row.
// $SEMANTIC is either TEXCOORD# or a semantic name specified here. // $SEMANTIC is either TEXCOORD# or a semantic name specified here.
std::string compile(std::vector<HLSLVertexAttributeRemap> vertex_attributes); void add_vertex_attribute_remap(const HLSLVertexAttributeRemap &vertex_attributes);
std::string compile() override; std::string compile() override;
// This is a special HLSL workaround for the NumWorkGroups builtin. // This is a special HLSL workaround for the NumWorkGroups builtin.

View File

@ -30,75 +30,51 @@ static const uint32_t k_unknown_component = ~0u;
static const uint32_t k_aux_mbr_idx_swizzle_const = 0u; static const uint32_t k_aux_mbr_idx_swizzle_const = 0u;
CompilerMSL::CompilerMSL(vector<uint32_t> spirv_, vector<MSLVertexAttr> *p_vtx_attrs, CompilerMSL::CompilerMSL(vector<uint32_t> spirv_)
vector<MSLResourceBinding> *p_res_bindings)
: CompilerGLSL(move(spirv_)) : CompilerGLSL(move(spirv_))
{ {
if (p_vtx_attrs)
for (auto &va : *p_vtx_attrs)
{
vtx_attrs_by_location[va.location] = &va;
if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin))
vtx_attrs_by_builtin[va.builtin] = &va;
}
if (p_res_bindings)
for (auto &rb : *p_res_bindings)
resource_bindings.push_back(&rb);
} }
CompilerMSL::CompilerMSL(const uint32_t *ir_, size_t word_count, MSLVertexAttr *p_vtx_attrs, size_t vtx_attrs_count, CompilerMSL::CompilerMSL(const uint32_t *ir_, size_t word_count)
MSLResourceBinding *p_res_bindings, size_t res_bindings_count)
: CompilerGLSL(ir_, word_count) : CompilerGLSL(ir_, word_count)
{ {
if (p_vtx_attrs)
for (size_t i = 0; i < vtx_attrs_count; i++)
{
auto &va = p_vtx_attrs[i];
vtx_attrs_by_location[va.location] = &va;
if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin))
vtx_attrs_by_builtin[va.builtin] = &va;
}
if (p_res_bindings)
for (size_t i = 0; i < res_bindings_count; i++)
resource_bindings.push_back(&p_res_bindings[i]);
} }
CompilerMSL::CompilerMSL(const ParsedIR &ir_, MSLVertexAttr *p_vtx_attrs, size_t vtx_attrs_count, CompilerMSL::CompilerMSL(const ParsedIR &ir_)
MSLResourceBinding *p_res_bindings, size_t res_bindings_count)
: CompilerGLSL(ir_) : CompilerGLSL(ir_)
{ {
if (p_vtx_attrs)
for (size_t i = 0; i < vtx_attrs_count; i++)
{
auto &va = p_vtx_attrs[i];
vtx_attrs_by_location[va.location] = &va;
if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin))
vtx_attrs_by_builtin[va.builtin] = &va;
}
if (p_res_bindings)
for (size_t i = 0; i < res_bindings_count; i++)
resource_bindings.push_back(&p_res_bindings[i]);
} }
CompilerMSL::CompilerMSL(ParsedIR &&ir_, MSLVertexAttr *p_vtx_attrs, size_t vtx_attrs_count, CompilerMSL::CompilerMSL(ParsedIR &&ir_)
MSLResourceBinding *p_res_bindings, size_t res_bindings_count)
: CompilerGLSL(std::move(ir_)) : CompilerGLSL(std::move(ir_))
{ {
if (p_vtx_attrs) }
for (size_t i = 0; i < vtx_attrs_count; i++)
{
auto &va = p_vtx_attrs[i];
vtx_attrs_by_location[va.location] = &va;
if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin))
vtx_attrs_by_builtin[va.builtin] = &va;
}
if (p_res_bindings) void CompilerMSL::add_msl_vertex_attribute(const MSLVertexAttr &va)
for (size_t i = 0; i < res_bindings_count; i++) {
resource_bindings.push_back(&p_res_bindings[i]); vtx_attrs_by_location[va.location] = va;
if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin))
vtx_attrs_by_builtin[va.builtin] = va;
}
void CompilerMSL::add_msl_resource_binding(const MSLResourceBinding &binding)
{
resource_bindings.push_back({ binding, false });
}
bool CompilerMSL::is_msl_vertex_attribute_used(uint32_t location)
{
return vtx_attrs_in_use.count(location) != 0;
}
bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding)
{
auto itr = find_if(begin(resource_bindings), end(resource_bindings),
[&](const std::pair<MSLResourceBinding, bool> &resource) -> bool {
return model == resource.first.stage && desc_set == resource.first.desc_set &&
binding == resource.first.binding;
});
return itr != end(resource_bindings) && itr->second;
} }
void CompilerMSL::set_fragment_output_components(uint32_t location, uint32_t components) void CompilerMSL::set_fragment_output_components(uint32_t location, uint32_t components)
@ -662,7 +638,10 @@ string CompilerMSL::compile()
reset(); reset();
next_metal_resource_index = MSLResourceBinding(); // Start bindings at zero // Start bindings at zero.
next_metal_resource_index_buffer = 0;
next_metal_resource_index_texture = 0;
next_metal_resource_index_sampler = 0;
// Move constructor for this type is broken on GCC 4.9 ... // Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream()); buffer = unique_ptr<ostringstream>(new ostringstream());
@ -679,36 +658,6 @@ string CompilerMSL::compile()
return buffer->str(); return buffer->str();
} }
string CompilerMSL::compile(vector<MSLVertexAttr> *p_vtx_attrs, vector<MSLResourceBinding> *p_res_bindings)
{
if (p_vtx_attrs)
{
vtx_attrs_by_location.clear();
for (auto &va : *p_vtx_attrs)
{
vtx_attrs_by_location[va.location] = &va;
if (va.builtin != BuiltInMax && !vtx_attrs_by_builtin.count(va.builtin))
vtx_attrs_by_builtin[va.builtin] = &va;
}
}
if (p_res_bindings)
{
resource_bindings.clear();
for (auto &rb : *p_res_bindings)
resource_bindings.push_back(&rb);
}
return compile();
}
string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_vtx_attrs,
vector<MSLResourceBinding> *p_res_bindings)
{
msl_options = msl_cfg;
return compile(p_vtx_attrs, p_res_bindings);
}
// Register the need to output any custom functions. // Register the need to output any custom functions.
void CompilerMSL::preprocess_op_codes() void CompilerMSL::preprocess_op_codes()
{ {
@ -1030,10 +979,8 @@ void CompilerMSL::mark_as_packable(SPIRType &type)
// If a vertex attribute exists at the location, it is marked as being used by this shader // If a vertex attribute exists at the location, it is marked as being used by this shader
void CompilerMSL::mark_location_as_used_by_shader(uint32_t location, StorageClass storage) void CompilerMSL::mark_location_as_used_by_shader(uint32_t location, StorageClass storage)
{ {
MSLVertexAttr *p_va; if ((get_execution_model() == ExecutionModelVertex || is_tessellation_shader()) && (storage == StorageClassInput))
if ((get_execution_model() == ExecutionModelVertex || is_tessellation_shader()) && (storage == StorageClassInput) && vtx_attrs_in_use.insert(location);
(p_va = vtx_attrs_by_location[location]))
p_va->used_by_shader = true;
} }
uint32_t CompilerMSL::get_target_components_for_fragment_location(uint32_t location) const uint32_t CompilerMSL::get_target_components_for_fragment_location(uint32_t location) const
@ -1141,7 +1088,7 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
} }
else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin))
{ {
uint32_t locn = vtx_attrs_by_builtin[builtin]->location; uint32_t locn = vtx_attrs_by_builtin[builtin].location;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, storage); mark_location_as_used_by_shader(locn, storage);
} }
@ -1268,7 +1215,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
} }
else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin))
{ {
uint32_t locn = vtx_attrs_by_builtin[builtin]->location + i; uint32_t locn = vtx_attrs_by_builtin[builtin].location + i;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, storage); mark_location_as_used_by_shader(locn, storage);
} }
@ -1417,7 +1364,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
} }
else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin))
{ {
uint32_t locn = vtx_attrs_by_builtin[builtin]->location + i; uint32_t locn = vtx_attrs_by_builtin[builtin].location + i;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, storage); mark_location_as_used_by_shader(locn, storage);
} }
@ -1553,7 +1500,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
} }
else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin)) else if (is_builtin && is_tessellation_shader() && vtx_attrs_by_builtin.count(builtin))
{ {
uint32_t locn = vtx_attrs_by_builtin[builtin]->location; uint32_t locn = 0;
auto builtin_itr = vtx_attrs_by_builtin.find(builtin);
if (builtin_itr != end(vtx_attrs_by_builtin))
locn = builtin_itr->second.location;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, storage); mark_location_as_used_by_shader(locn, storage);
} }
@ -1635,7 +1585,7 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_
} }
else if (vtx_attrs_by_builtin.count(builtin)) else if (vtx_attrs_by_builtin.count(builtin))
{ {
uint32_t locn = vtx_attrs_by_builtin[builtin]->location; uint32_t locn = vtx_attrs_by_builtin[builtin].location;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, StorageClassInput); mark_location_as_used_by_shader(locn, StorageClassInput);
} }
@ -1696,7 +1646,7 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_
} }
else if (vtx_attrs_by_builtin.count(builtin)) else if (vtx_attrs_by_builtin.count(builtin))
{ {
uint32_t locn = vtx_attrs_by_builtin[builtin]->location; uint32_t locn = vtx_attrs_by_builtin[builtin].location;
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, StorageClassInput); mark_location_as_used_by_shader(locn, StorageClassInput);
} }
@ -2119,11 +2069,11 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
{ {
auto &type = get<SPIRType>(type_id); auto &type = get<SPIRType>(type_id);
MSLVertexAttr *p_va = vtx_attrs_by_location[location]; auto p_va = vtx_attrs_by_location.find(location);
if (!p_va) if (p_va == end(vtx_attrs_by_location))
return type_id; return type_id;
switch (p_va->format) switch (p_va->second.format)
{ {
case MSL_VERTEX_FORMAT_UINT8: case MSL_VERTEX_FORMAT_UINT8:
{ {
@ -2157,6 +2107,7 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
ptr_type.parent_type = base_type_id; ptr_type.parent_type = base_type_id;
return ptr_type_id; return ptr_type_id;
} }
case MSL_VERTEX_FORMAT_UINT16: case MSL_VERTEX_FORMAT_UINT16:
{ {
switch (type.basetype) switch (type.basetype)
@ -2188,6 +2139,7 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l
return ptr_type_id; return ptr_type_id;
} }
default:
case MSL_VERTEX_FORMAT_OTHER: case MSL_VERTEX_FORMAT_OTHER:
break; break;
} }
@ -5792,24 +5744,25 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
uint32_t var_binding = (var.storage == StorageClassPushConstant) ? kPushConstBinding : var_dec.binding; uint32_t var_binding = (var.storage == StorageClassPushConstant) ? kPushConstBinding : var_dec.binding;
// If a matching binding has been specified, find and use it // If a matching binding has been specified, find and use it
for (auto p_res_bind : resource_bindings) auto itr = find_if(begin(resource_bindings), end(resource_bindings),
{ [&](const pair<MSLResourceBinding, bool> &resource) -> bool {
if (p_res_bind->stage == execution.model && p_res_bind->desc_set == var_desc_set && return var_desc_set == resource.first.desc_set && var_binding == resource.first.binding &&
p_res_bind->binding == var_binding) execution.model == resource.first.stage;
{ });
p_res_bind->used_by_shader = true; if (itr != end(resource_bindings))
switch (basetype) {
{ itr->second = true;
case SPIRType::Struct: switch (basetype)
return p_res_bind->msl_buffer; {
case SPIRType::Image: case SPIRType::Struct:
return p_res_bind->msl_texture; return itr->first.msl_buffer;
case SPIRType::Sampler: case SPIRType::Image:
return p_res_bind->msl_sampler; return itr->first.msl_texture;
default: case SPIRType::Sampler:
return 0; return itr->first.msl_sampler;
} default:
return 0;
} }
} }
@ -5827,16 +5780,16 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
switch (basetype) switch (basetype)
{ {
case SPIRType::Struct: case SPIRType::Struct:
resource_index = next_metal_resource_index.msl_buffer; resource_index = next_metal_resource_index_buffer;
next_metal_resource_index.msl_buffer += binding_stride; next_metal_resource_index_buffer += binding_stride;
break; break;
case SPIRType::Image: case SPIRType::Image:
resource_index = next_metal_resource_index.msl_texture; resource_index = next_metal_resource_index_texture;
next_metal_resource_index.msl_texture += binding_stride; next_metal_resource_index_texture += binding_stride;
break; break;
case SPIRType::Sampler: case SPIRType::Sampler:
resource_index = next_metal_resource_index.msl_sampler; resource_index = next_metal_resource_index_sampler;
next_metal_resource_index.msl_sampler += binding_stride; next_metal_resource_index_sampler += binding_stride;
break; break;
default: default:
resource_index = 0; resource_index = 0;

View File

@ -32,14 +32,14 @@ namespace spirv_cross
// some other format. // some other format.
enum MSLVertexFormat enum MSLVertexFormat
{ {
MSL_VERTEX_FORMAT_OTHER, MSL_VERTEX_FORMAT_OTHER = 0,
MSL_VERTEX_FORMAT_UINT8, MSL_VERTEX_FORMAT_UINT8 = 1,
MSL_VERTEX_FORMAT_UINT16 MSL_VERTEX_FORMAT_UINT16 = 2,
MSL_VERTEX_FORMAT_INT_MAX = 0x7fffffff
}; };
// Defines MSL characteristics of a vertex attribute at a particular location. // Defines MSL characteristics of a vertex attribute at a particular location.
// The used_by_shader flag is set to true during compilation of SPIR-V to MSL // After compilation, it is possible to query whether or not this location was used.
// if the shader makes use of this vertex attribute.
struct MSLVertexAttr struct MSLVertexAttr
{ {
uint32_t location = 0; uint32_t location = 0;
@ -49,72 +49,72 @@ struct MSLVertexAttr
bool per_instance = false; bool per_instance = false;
MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER; MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER;
spv::BuiltIn builtin = spv::BuiltInMax; spv::BuiltIn builtin = spv::BuiltInMax;
bool used_by_shader = false;
}; };
// Matches the binding index of a MSL resource for a binding within a descriptor set. // Matches the binding index of a MSL resource for a binding within a descriptor set.
// Taken together, the stage, desc_set and binding combine to form a reference to a resource // Taken together, the stage, desc_set and binding combine to form a reference to a resource
// descriptor used in a particular shading stage. Generally, only one of the buffer, texture, // descriptor used in a particular shading stage.
// or sampler elements will be populated. The used_by_shader flag is set to true during
// compilation of SPIR-V to MSL if the shader makes use of this vertex attribute.
struct MSLResourceBinding struct MSLResourceBinding
{ {
spv::ExecutionModel stage; spv::ExecutionModel stage = spv::ExecutionModelMax;
uint32_t desc_set = 0; uint32_t desc_set = 0;
uint32_t binding = 0; uint32_t binding = 0;
uint32_t msl_buffer = 0; uint32_t msl_buffer = 0;
uint32_t msl_texture = 0; uint32_t msl_texture = 0;
uint32_t msl_sampler = 0; uint32_t msl_sampler = 0;
bool used_by_shader = false;
}; };
enum MSLSamplerCoord enum MSLSamplerCoord
{ {
MSL_SAMPLER_COORD_NORMALIZED, MSL_SAMPLER_COORD_NORMALIZED = 0,
MSL_SAMPLER_COORD_PIXEL MSL_SAMPLER_COORD_PIXEL = 1,
MSL_SAMPLER_INT_MAX = 0x7fffffff
}; };
enum MSLSamplerFilter enum MSLSamplerFilter
{ {
MSL_SAMPLER_FILTER_NEAREST, MSL_SAMPLER_FILTER_NEAREST = 0,
MSL_SAMPLER_FILTER_LINEAR MSL_SAMPLER_FILTER_LINEAR = 1,
MSL_SAMPLER_FILTER_INT_MAX = 0x7fffffff
}; };
enum MSLSamplerMipFilter enum MSLSamplerMipFilter
{ {
MSL_SAMPLER_MIP_FILTER_NONE, MSL_SAMPLER_MIP_FILTER_NONE = 0,
MSL_SAMPLER_MIP_FILTER_NEAREST, MSL_SAMPLER_MIP_FILTER_NEAREST = 1,
MSL_SAMPLER_MIP_FILTER_LINEAR, MSL_SAMPLER_MIP_FILTER_LINEAR = 2,
MSL_SAMPLER_MIP_FILTER_INT_MAX = 0x7fffffff
}; };
enum MSLSamplerAddress enum MSLSamplerAddress
{ {
MSL_SAMPLER_ADDRESS_CLAMP_TO_ZERO, MSL_SAMPLER_ADDRESS_CLAMP_TO_ZERO = 0,
MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE, MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE = 1,
MSL_SAMPLER_ADDRESS_CLAMP_TO_BORDER, MSL_SAMPLER_ADDRESS_CLAMP_TO_BORDER = 2,
MSL_SAMPLER_ADDRESS_REPEAT, MSL_SAMPLER_ADDRESS_REPEAT = 3,
MSL_SAMPLER_ADDRESS_MIRRORED_REPEAT MSL_SAMPLER_ADDRESS_MIRRORED_REPEAT = 4,
MSL_SAMPLER_ADDRESS_INT_MAX = 0x7fffffff
}; };
enum MSLSamplerCompareFunc enum MSLSamplerCompareFunc
{ {
MSL_SAMPLER_COMPARE_FUNC_NEVER, MSL_SAMPLER_COMPARE_FUNC_NEVER = 0,
MSL_SAMPLER_COMPARE_FUNC_LESS, MSL_SAMPLER_COMPARE_FUNC_LESS = 1,
MSL_SAMPLER_COMPARE_FUNC_LESS_EQUAL, MSL_SAMPLER_COMPARE_FUNC_LESS_EQUAL = 2,
MSL_SAMPLER_COMPARE_FUNC_GREATER, MSL_SAMPLER_COMPARE_FUNC_GREATER = 3,
MSL_SAMPLER_COMPARE_FUNC_GREATER_EQUAL, MSL_SAMPLER_COMPARE_FUNC_GREATER_EQUAL = 4,
MSL_SAMPLER_COMPARE_FUNC_EQUAL, MSL_SAMPLER_COMPARE_FUNC_EQUAL = 5,
MSL_SAMPLER_COMPARE_FUNC_NOT_EQUAL, MSL_SAMPLER_COMPARE_FUNC_NOT_EQUAL = 6,
MSL_SAMPLER_COMPARE_FUNC_ALWAYS MSL_SAMPLER_COMPARE_FUNC_ALWAYS = 7,
MSL_SAMPLER_COMPARE_FUNC_INT_MAX = 0x7fffffff
}; };
enum MSLSamplerBorderColor enum MSLSamplerBorderColor
{ {
MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK, MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK = 0,
MSL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK, MSL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK = 1,
MSL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE MSL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE = 2,
MSL_SAMPLER_BORDER_COLOR_INT_MAX = 0x7fffffff
}; };
struct MSLConstexprSampler struct MSLConstexprSampler
@ -161,8 +161,8 @@ public:
{ {
typedef enum typedef enum
{ {
iOS, iOS = 0,
macOS, macOS = 1
} Platform; } Platform;
Platform platform = macOS; Platform platform = macOS;
@ -210,23 +210,11 @@ public:
} }
}; };
SPIRV_CROSS_DEPRECATED("CompilerMSL::get_options() is obsolete, use get_msl_options() instead.")
const Options &get_options() const
{
return msl_options;
}
const Options &get_msl_options() const const Options &get_msl_options() const
{ {
return msl_options; return msl_options;
} }
SPIRV_CROSS_DEPRECATED("CompilerMSL::set_options() is obsolete, use set_msl_options() instead.")
void set_options(Options &opts)
{
msl_options = opts;
}
void set_msl_options(const Options &opts) void set_msl_options(const Options &opts)
{ {
msl_options = opts; msl_options = opts;
@ -269,6 +257,44 @@ public:
return capture_output_to_buffer && stage_in_var_id != 0; return capture_output_to_buffer && stage_in_var_id != 0;
} }
explicit CompilerMSL(std::vector<uint32_t> spirv);
CompilerMSL(const uint32_t *ir, size_t word_count);
explicit CompilerMSL(const ParsedIR &ir);
explicit CompilerMSL(ParsedIR &&ir);
// attr is a vertex attribute binding used to match
// vertex content locations to MSL attributes. If vertex attributes are provided,
// is_msl_vertex_attribute_used() will return true after calling ::compile() if
// the location was used by the MSL code.
void add_msl_vertex_attribute(const MSLVertexAttr &attr);
// resource is a resource binding to indicate the MSL buffer,
// texture or sampler index to use for a particular SPIR-V description set
// and binding. If resource bindings are provided,
// is_msl_resource_binding_used() will return true after calling ::compile() if
// the set/binding combination was used by the MSL code.
void add_msl_resource_binding(const MSLResourceBinding &resource);
// Query after compilation is done. This allows you to check if a location or set/binding combination was used by the shader.
bool is_msl_vertex_attribute_used(uint32_t location);
bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding);
// Compiles the SPIR-V code into Metal Shading Language.
std::string compile() override;
// Remap a sampler with ID to a constexpr sampler.
// Older iOS targets must use constexpr samplers in certain cases (PCF),
// so a static sampler must be used.
// The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler.
// This can be used on both combined image/samplers (sampler2D) or standalone samplers.
// The remapped sampler must not be an array of samplers.
void remap_constexpr_sampler(uint32_t id, const MSLConstexprSampler &sampler);
// If using CompilerMSL::Options::pad_fragment_output_components, override the number of components we expect
// to use for a particular location. The default is 4 if number of components is not overridden.
void set_fragment_output_components(uint32_t location, uint32_t components);
protected:
// An enum of SPIR-V functions that are implemented in additional // An enum of SPIR-V functions that are implemented in additional
// source code that is added to the shader if necessary. // source code that is added to the shader if necessary.
enum SPVFuncImpl enum SPVFuncImpl
@ -304,58 +330,6 @@ public:
SPVFuncImplArrayCopyMultidimMax = 6 SPVFuncImplArrayCopyMultidimMax = 6
}; };
// Constructs an instance to compile the SPIR-V code into Metal Shading Language,
// using the configuration parameters, if provided:
// - p_vtx_attrs is an optional list of vertex attribute bindings used to match
// vertex content locations to MSL attributes. If vertex attributes are provided,
// the compiler will set the used_by_shader flag to true in any vertex attribute
// actually used by the MSL code.
// - p_res_bindings is a list of resource bindings to indicate the MSL buffer,
// texture or sampler index to use for a particular SPIR-V description set
// and binding. If resource bindings are provided, the compiler will set the
// used_by_shader flag to true in any resource binding actually used by the MSL code.
CompilerMSL(std::vector<uint32_t> spirv, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
std::vector<MSLResourceBinding> *p_res_bindings = nullptr);
// Alternate constructor avoiding use of std::vectors.
CompilerMSL(const uint32_t *ir, size_t word_count, MSLVertexAttr *p_vtx_attrs = nullptr, size_t vtx_attrs_count = 0,
MSLResourceBinding *p_res_bindings = nullptr, size_t res_bindings_count = 0);
// Alternate constructors taking pre-parsed IR directly.
CompilerMSL(const ParsedIR &ir, MSLVertexAttr *p_vtx_attrs = nullptr, size_t vtx_attrs_count = 0,
MSLResourceBinding *p_res_bindings = nullptr, size_t res_bindings_count = 0);
CompilerMSL(ParsedIR &&ir, MSLVertexAttr *p_vtx_attrs = nullptr, size_t vtx_attrs_count = 0,
MSLResourceBinding *p_res_bindings = nullptr, size_t res_bindings_count = 0);
// Compiles the SPIR-V code into Metal Shading Language.
std::string compile() override;
// Compiles the SPIR-V code into Metal Shading Language, overriding configuration parameters.
// Any of the parameters here may be null to indicate that the configuration provided in the
// constructor should be used. They are not declared as optional to avoid a conflict with the
// inherited and overridden zero-parameter compile() function.
std::string compile(std::vector<MSLVertexAttr> *p_vtx_attrs, std::vector<MSLResourceBinding> *p_res_bindings);
// This legacy method is deprecated.
typedef Options MSLConfiguration;
SPIRV_CROSS_DEPRECATED("Please use get_msl_options() and set_msl_options() instead.")
std::string compile(MSLConfiguration &msl_cfg, std::vector<MSLVertexAttr> *p_vtx_attrs = nullptr,
std::vector<MSLResourceBinding> *p_res_bindings = nullptr);
// Remap a sampler with ID to a constexpr sampler.
// Older iOS targets must use constexpr samplers in certain cases (PCF),
// so a static sampler must be used.
// The sampler will not consume a binding, but be declared in the entry point as a constexpr sampler.
// This can be used on both combined image/samplers (sampler2D) or standalone samplers.
// The remapped sampler must not be an array of samplers.
void remap_constexpr_sampler(uint32_t id, const MSLConstexprSampler &sampler);
// If using CompilerMSL::Options::pad_fragment_output_components, override the number of components we expect
// to use for a particular location. The default is 4 if number of components is not overridden.
void set_fragment_output_components(uint32_t location, uint32_t components);
protected:
void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_instruction(const Instruction &instr) override; void emit_instruction(const Instruction &instr) override;
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
@ -495,15 +469,20 @@ protected:
Options msl_options; Options msl_options;
std::set<SPVFuncImpl> spv_function_implementations; std::set<SPVFuncImpl> spv_function_implementations;
std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location; std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_location;
std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_builtin; std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_builtin;
std::unordered_set<uint32_t> vtx_attrs_in_use;
std::unordered_map<uint32_t, uint32_t> fragment_output_components; std::unordered_map<uint32_t, uint32_t> fragment_output_components;
std::unordered_map<MSLStructMemberKey, uint32_t> struct_member_padding; std::unordered_map<MSLStructMemberKey, uint32_t> struct_member_padding;
std::set<std::string> pragma_lines; std::set<std::string> pragma_lines;
std::set<std::string> typedef_lines; std::set<std::string> typedef_lines;
std::vector<uint32_t> vars_needing_early_declaration; std::vector<uint32_t> vars_needing_early_declaration;
std::vector<MSLResourceBinding *> resource_bindings;
MSLResourceBinding next_metal_resource_index; std::vector<std::pair<MSLResourceBinding, bool>> resource_bindings;
uint32_t next_metal_resource_index_buffer = 0;
uint32_t next_metal_resource_index_texture = 0;
uint32_t next_metal_resource_index_sampler = 0;
uint32_t stage_in_var_id = 0; uint32_t stage_in_var_id = 0;
uint32_t stage_out_var_id = 0; uint32_t stage_out_var_id = 0;
uint32_t patch_stage_in_var_id = 0; uint32_t patch_stage_in_var_id = 0;

View File

@ -16,6 +16,13 @@ import multiprocessing
import errno import errno
from functools import partial from functools import partial
class Paths():
def __init__(self, glslang, spirv_as, spirv_val, spirv_opt):
self.glslang = glslang
self.spirv_as = spirv_as
self.spirv_val = spirv_val
self.spirv_opt = spirv_opt
def remove_file(path): def remove_file(path):
#print('Removing file:', path) #print('Removing file:', path)
os.remove(path) os.remove(path)
@ -131,21 +138,21 @@ def validate_shader_msl(shader, opt):
print('Error compiling Metal shader: ' + msl_path) print('Error compiling Metal shader: ' + msl_path)
raise RuntimeError('Failed to compile Metal shader') raise RuntimeError('Failed to compile Metal shader')
def cross_compile_msl(shader, spirv, opt): def cross_compile_msl(shader, spirv, opt, paths):
spirv_path = create_temporary() spirv_path = create_temporary()
msl_path = create_temporary(os.path.basename(shader)) msl_path = create_temporary(os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader] spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader: if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids') spirv_cmd.append('--preserve-numeric-ids')
if spirv: if spirv:
subprocess.check_call(spirv_cmd) subprocess.check_call(spirv_cmd)
else: else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt: if opt:
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path]) subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross' spirv_cross_path = './spirv-cross'
@ -166,7 +173,7 @@ def cross_compile_msl(shader, spirv, opt):
subprocess.check_call(msl_args) subprocess.check_call(msl_args)
if not shader_is_invalid_spirv(msl_path): if not shader_is_invalid_spirv(msl_path):
subprocess.check_call(['spirv-val', '--target-env', 'vulkan1.1', spirv_path]) subprocess.check_call([paths.spirv_val, '--target-env', 'vulkan1.1', spirv_path])
return (spirv_path, msl_path) return (spirv_path, msl_path)
@ -201,8 +208,8 @@ def shader_to_win_path(shader):
return shader return shader
ignore_fxc = False ignore_fxc = False
def validate_shader_hlsl(shader, force_no_external_validation): def validate_shader_hlsl(shader, force_no_external_validation, paths):
subprocess.check_call(['glslangValidator', '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader]) subprocess.check_call([paths.glslang, '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader])
is_no_fxc = '.nofxc.' in shader is_no_fxc = '.nofxc.' in shader
global ignore_fxc global ignore_fxc
if (not ignore_fxc) and (not force_no_external_validation) and (not is_no_fxc): if (not ignore_fxc) and (not force_no_external_validation) and (not is_no_fxc):
@ -231,21 +238,21 @@ def shader_to_sm(shader):
else: else:
return '50' return '50'
def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation): def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, paths):
spirv_path = create_temporary() spirv_path = create_temporary()
hlsl_path = create_temporary(os.path.basename(shader)) hlsl_path = create_temporary(os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader] spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader: if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids') spirv_cmd.append('--preserve-numeric-ids')
if spirv: if spirv:
subprocess.check_call(spirv_cmd) subprocess.check_call(spirv_cmd)
else: else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt: if opt:
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path]) subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross' spirv_cross_path = './spirv-cross'
@ -253,27 +260,27 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation):
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', hlsl_path, spirv_path, '--hlsl-enable-compat', '--hlsl', '--shader-model', sm]) subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', hlsl_path, spirv_path, '--hlsl-enable-compat', '--hlsl', '--shader-model', sm])
if not shader_is_invalid_spirv(hlsl_path): if not shader_is_invalid_spirv(hlsl_path):
subprocess.check_call(['spirv-val', '--target-env', 'vulkan1.1', spirv_path]) subprocess.check_call([paths.spirv_val, '--target-env', 'vulkan1.1', spirv_path])
validate_shader_hlsl(hlsl_path, force_no_external_validation) validate_shader_hlsl(hlsl_path, force_no_external_validation, paths)
return (spirv_path, hlsl_path) return (spirv_path, hlsl_path)
def cross_compile_reflect(shader, spirv, opt): def cross_compile_reflect(shader, spirv, opt, paths):
spirv_path = create_temporary() spirv_path = create_temporary()
reflect_path = create_temporary(os.path.basename(shader)) reflect_path = create_temporary(os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader] spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader: if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids') spirv_cmd.append('--preserve-numeric-ids')
if spirv: if spirv:
subprocess.check_call(spirv_cmd) subprocess.check_call(spirv_cmd)
else: else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt: if opt:
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path]) subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross' spirv_cross_path = './spirv-cross'
@ -281,33 +288,33 @@ def cross_compile_reflect(shader, spirv, opt):
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', reflect_path, spirv_path, '--reflect']) subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', reflect_path, spirv_path, '--reflect'])
return (spirv_path, reflect_path) return (spirv_path, reflect_path)
def validate_shader(shader, vulkan): def validate_shader(shader, vulkan, paths):
if vulkan: if vulkan:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', shader]) subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', shader])
else: else:
subprocess.check_call(['glslangValidator', shader]) subprocess.check_call([paths.glslang, shader])
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt): def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt, paths):
spirv_path = create_temporary() spirv_path = create_temporary()
glsl_path = create_temporary(os.path.basename(shader)) glsl_path = create_temporary(os.path.basename(shader))
if vulkan or spirv: if vulkan or spirv:
vulkan_glsl_path = create_temporary('vk' + os.path.basename(shader)) vulkan_glsl_path = create_temporary('vk' + os.path.basename(shader))
spirv_cmd = ['spirv-as', '-o', spirv_path, shader] spirv_cmd = [paths.spirv_as, '-o', spirv_path, shader]
if '.preserve.' in shader: if '.preserve.' in shader:
spirv_cmd.append('--preserve-numeric-ids') spirv_cmd.append('--preserve-numeric-ids')
if spirv: if spirv:
subprocess.check_call(spirv_cmd) subprocess.check_call(spirv_cmd)
else: else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt and (not invalid_spirv): if opt and (not invalid_spirv):
subprocess.check_call(['spirv-opt', '--skip-validation', '-O', '-o', spirv_path, spirv_path]) subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path])
if not invalid_spirv: if not invalid_spirv:
subprocess.check_call(['spirv-val', '--target-env', 'vulkan1.1', spirv_path]) subprocess.check_call([paths.spirv_val, '--target-env', 'vulkan1.1', spirv_path])
extra_args = [] extra_args = []
if eliminate: if eliminate:
@ -326,14 +333,14 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
# A shader might not be possible to make valid GLSL from, skip validation for this case. # A shader might not be possible to make valid GLSL from, skip validation for this case.
if not ('nocompat' in glsl_path): if not ('nocompat' in glsl_path):
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path] + extra_args) subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', glsl_path, spirv_path] + extra_args)
validate_shader(glsl_path, False) validate_shader(glsl_path, False, paths)
else: else:
remove_file(glsl_path) remove_file(glsl_path)
glsl_path = None glsl_path = None
if vulkan or spirv: if vulkan or spirv:
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path] + extra_args) subprocess.check_call([spirv_cross_path, '--entry', 'main', '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path] + extra_args)
validate_shader(vulkan_glsl_path, True) validate_shader(vulkan_glsl_path, True, paths)
# SPIR-V shaders might just want to validate Vulkan GLSL output, we don't always care about the output. # SPIR-V shaders might just want to validate Vulkan GLSL output, we don't always care about the output.
if not vulkan: if not vulkan:
remove_file(vulkan_glsl_path) remove_file(vulkan_glsl_path)
@ -481,7 +488,7 @@ def shader_is_flatten_dimensions(shader):
def shader_is_noopt(shader): def shader_is_noopt(shader):
return '.noopt.' in shader return '.noopt.' in shader
def test_shader(stats, shader, update, keep, opt): def test_shader(stats, shader, update, keep, opt, paths):
joined_path = os.path.join(shader[0], shader[1]) joined_path = os.path.join(shader[0], shader[1])
vulkan = shader_is_vulkan(shader[1]) vulkan = shader_is_vulkan(shader[1])
desktop = shader_is_desktop(shader[1]) desktop = shader_is_desktop(shader[1])
@ -495,7 +502,7 @@ def test_shader(stats, shader, update, keep, opt):
noopt = shader_is_noopt(shader[1]) noopt = shader_is_noopt(shader[1])
print('Testing shader:', joined_path) print('Testing shader:', joined_path)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt and (not noopt)) spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt and (not noopt), paths)
# Only test GLSL stats if we have a shader following GL semantics. # Only test GLSL stats if we have a shader following GL semantics.
if stats and (not vulkan) and (not is_spirv) and (not desktop): if stats and (not vulkan) and (not is_spirv) and (not desktop):
@ -519,12 +526,12 @@ def test_shader(stats, shader, update, keep, opt):
a.append(str(i)) a.append(str(i))
print(','.join(a), file = stats) print(','.join(a), file = stats)
def test_shader_msl(stats, shader, update, keep, opt, force_no_external_validation): def test_shader_msl(stats, shader, update, keep, opt, force_no_external_validation, paths):
joined_path = os.path.join(shader[0], shader[1]) joined_path = os.path.join(shader[0], shader[1])
print('\nTesting MSL shader:', joined_path) print('\nTesting MSL shader:', joined_path)
is_spirv = shader_is_spirv(shader[1]) is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1]) noopt = shader_is_noopt(shader[1])
spirv, msl = cross_compile_msl(joined_path, is_spirv, opt and (not noopt)) spirv, msl = cross_compile_msl(joined_path, is_spirv, opt and (not noopt), paths)
regression_check(shader, msl, update, keep, opt) regression_check(shader, msl, update, keep, opt)
# Uncomment the following line to print the temp SPIR-V file path. # Uncomment the following line to print the temp SPIR-V file path.
@ -540,34 +547,35 @@ def test_shader_msl(stats, shader, update, keep, opt, force_no_external_validati
remove_file(spirv) remove_file(spirv)
def test_shader_hlsl(stats, shader, update, keep, opt, force_no_external_validation): def test_shader_hlsl(stats, shader, update, keep, opt, force_no_external_validation, paths):
joined_path = os.path.join(shader[0], shader[1]) joined_path = os.path.join(shader[0], shader[1])
print('Testing HLSL shader:', joined_path) print('Testing HLSL shader:', joined_path)
is_spirv = shader_is_spirv(shader[1]) is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1]) noopt = shader_is_noopt(shader[1])
spirv, hlsl = cross_compile_hlsl(joined_path, is_spirv, opt and (not noopt), force_no_external_validation) spirv, hlsl = cross_compile_hlsl(joined_path, is_spirv, opt and (not noopt), force_no_external_validation, paths)
regression_check(shader, hlsl, update, keep, opt) regression_check(shader, hlsl, update, keep, opt)
remove_file(spirv) remove_file(spirv)
def test_shader_reflect(stats, shader, update, keep, opt): def test_shader_reflect(stats, shader, update, keep, opt, paths):
joined_path = os.path.join(shader[0], shader[1]) joined_path = os.path.join(shader[0], shader[1])
print('Testing shader reflection:', joined_path) print('Testing shader reflection:', joined_path)
is_spirv = shader_is_spirv(shader[1]) is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1]) noopt = shader_is_noopt(shader[1])
spirv, reflect = cross_compile_reflect(joined_path, is_spirv, opt and (not noopt)) spirv, reflect = cross_compile_reflect(joined_path, is_spirv, opt and (not noopt), paths)
regression_check_reflect(shader, reflect, update, keep, opt) regression_check_reflect(shader, reflect, update, keep, opt)
remove_file(spirv) remove_file(spirv)
def test_shader_file(relpath, stats, shader_dir, update, keep, opt, force_no_external_validation, backend): def test_shader_file(relpath, stats, args, backend):
paths = Paths(args.glslang, args.spirv_as, args.spirv_val, args.spirv_opt)
try: try:
if backend == 'msl': if backend == 'msl':
test_shader_msl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation) test_shader_msl(stats, (args.folder, relpath), args.update, args.keep, args.opt, args.force_no_external_validation, paths)
elif backend == 'hlsl': elif backend == 'hlsl':
test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt, force_no_external_validation) test_shader_hlsl(stats, (args.folder, relpath), args.update, args.keep, args.opt, args.force_no_external_validation, paths)
elif backend == 'reflect': elif backend == 'reflect':
test_shader_reflect(stats, (shader_dir, relpath), update, keep, opt) test_shader_reflect(stats, (args.folder, relpath), args.update, args.keep, args.opt, paths)
else: else:
test_shader(stats, (shader_dir, relpath), update, keep, opt) test_shader(stats, (args.folder, relpath), args.update, args.keep, args.opt, paths)
return None return None
except Exception as e: except Exception as e:
return e return e
@ -589,9 +597,7 @@ def test_shaders_helper(stats, backend, args):
results = [] results = []
for f in all_files: for f in all_files:
results.append(pool.apply_async(test_shader_file, results.append(pool.apply_async(test_shader_file,
args = (f, stats, args = (f, stats, args, backend)))
args.folder, args.update, args.keep, args.opt, args.force_no_external_validation,
backend)))
for res in results: for res in results:
error = res.get() error = res.get()
@ -602,7 +608,7 @@ def test_shaders_helper(stats, backend, args):
sys.exit(1) sys.exit(1)
else: else:
for i in all_files: for i in all_files:
e = test_shader_file(i, stats, args.folder, args.update, args.keep, args.opt, args.force_no_external_validation, backend) e = test_shader_file(i, stats, args, backend)
if e is not None: if e is not None:
print('Error:', e) print('Error:', e)
sys.exit(1) sys.exit(1)
@ -649,6 +655,18 @@ def main():
parser.add_argument('--parallel', parser.add_argument('--parallel',
action = 'store_true', action = 'store_true',
help = 'Execute tests in parallel. Useful for doing regression quickly, but bad for debugging and stat output.') help = 'Execute tests in parallel. Useful for doing regression quickly, but bad for debugging and stat output.')
parser.add_argument('--glslang',
default = 'glslangValidator',
help = 'Explicit path to glslangValidator')
parser.add_argument('--spirv-as',
default = 'spirv-as',
help = 'Explicit path to spirv-as')
parser.add_argument('--spirv-val',
default = 'spirv-val',
help = 'Explicit path to spirv-val')
parser.add_argument('--spirv-opt',
default = 'spirv-opt',
help = 'Explicit path to spirv-opt')
args = parser.parse_args() args = parser.parse_args()
if not args.folder: if not args.folder:

View File

@ -0,0 +1,161 @@
/* Smoke test for the C API. */
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <spirv_cross_c.h>
#include <stdlib.h>
#include <stdio.h>
#define SPVC_CHECKED_CALL(x) do { \
if ((x) != SPVC_SUCCESS) { \
fprintf(stderr, "Failed at line %d.\n", __LINE__); \
exit(1); \
} \
} while(0)
#define SPVC_CHECKED_CALL_NEGATIVE(x) do { \
g_fail_on_error = SPVC_FALSE; \
if ((x) == SPVC_SUCCESS) { \
fprintf(stderr, "Failed at line %d.\n", __LINE__); \
exit(1); \
} \
g_fail_on_error = SPVC_TRUE; \
} while(0)
static int read_file(const char *path, SpvId **buffer, size_t *word_count)
{
long len;
FILE *file = fopen(path, "rb");
if (!file)
return -1;
fseek(file, 0, SEEK_END);
len = ftell(file);
rewind(file);
*buffer = malloc(len);
if (fread(*buffer, 1, len, file) != (size_t)len)
{
fclose(file);
free(*buffer);
return -1;
}
fclose(file);
*word_count = len / sizeof(SpvId);
return 0;
}
static spvc_bool g_fail_on_error = SPVC_TRUE;
static void error_callback(void *userdata, const char *error)
{
(void)userdata;
if (g_fail_on_error)
{
fprintf(stderr, "Error: %s\n", error);
exit(1);
}
else
printf("Expected error hit: %s.\n", error);
}
static void dump_resource_list(spvc_compiler compiler, spvc_resources resources, spvc_resource_type type, const char *tag)
{
const spvc_reflected_resource *list = NULL;
size_t count = 0;
size_t i;
SPVC_CHECKED_CALL(spvc_resources_get_resource_list_for_type(resources, type, &list, &count));
printf("%s\n", tag);
for (i = 0; i < count; i++)
{
printf("ID: %u, BaseTypeID: %u, TypeID: %u, Name: %s\n", list[i].id, list[i].base_type_id, list[i].type_id,
list[i].name);
printf(" Set: %u, Binding: %u\n",
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationDescriptorSet),
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding));
}
}
static void dump_resources(spvc_compiler compiler, spvc_resources resources)
{
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, "UBO");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_STORAGE_BUFFER, "SSBO");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_PUSH_CONSTANT, "Push");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS, "Samplers");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_SEPARATE_IMAGE, "Image");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, "Combined image samplers");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_STAGE_INPUT, "Stage input");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_STAGE_OUTPUT, "Stage output");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_STORAGE_IMAGE, "Storage image");
dump_resource_list(compiler, resources, SPVC_RESOURCE_TYPE_SUBPASS_INPUT, "Subpass input");
}
static void compile(spvc_compiler compiler, const char *tag)
{
const char *result = NULL;
SPVC_CHECKED_CALL(spvc_compiler_compile(compiler, &result));
printf("\n%s\n=======\n", tag);
printf("%s\n=======\n", result);
}
int main(int argc, char **argv)
{
spvc_context context = NULL;
spvc_parsed_ir ir = NULL;
spvc_compiler compiler_glsl = NULL;
spvc_compiler compiler_hlsl = NULL;
spvc_compiler compiler_msl = NULL;
spvc_compiler compiler_cpp = NULL;
spvc_compiler compiler_json = NULL;
spvc_compiler compiler_none = NULL;
spvc_compiler_options options = NULL;
spvc_resources resources = NULL;
SpvId *buffer = NULL;
size_t word_count = 0;
if (argc != 2)
return 1;
if (read_file(argv[1], &buffer, &word_count) < 0)
return 1;
SPVC_CHECKED_CALL(spvc_context_create(&context));
spvc_context_set_error_callback(context, error_callback, NULL);
SPVC_CHECKED_CALL(spvc_context_parse_spirv(context, buffer, word_count, &ir));
SPVC_CHECKED_CALL(spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_COPY, &compiler_glsl));
SPVC_CHECKED_CALL(spvc_context_create_compiler(context, SPVC_BACKEND_HLSL, ir, SPVC_CAPTURE_MODE_COPY, &compiler_hlsl));
SPVC_CHECKED_CALL(spvc_context_create_compiler(context, SPVC_BACKEND_MSL, ir, SPVC_CAPTURE_MODE_COPY, &compiler_msl));
SPVC_CHECKED_CALL(spvc_context_create_compiler(context, SPVC_BACKEND_CPP, ir, SPVC_CAPTURE_MODE_COPY, &compiler_cpp));
SPVC_CHECKED_CALL(spvc_context_create_compiler(context, SPVC_BACKEND_JSON, ir, SPVC_CAPTURE_MODE_COPY, &compiler_json));
SPVC_CHECKED_CALL(spvc_context_create_compiler(context, SPVC_BACKEND_NONE, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_none));
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler_none, &options));
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler_none, options));
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler_json, &options));
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler_json, options));
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler_cpp, &options));
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler_cpp, options));
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler_msl, &options));
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler_msl, options));
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler_hlsl, &options));
SPVC_CHECKED_CALL(spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, 50));
SPVC_CHECKED_CALL_NEGATIVE(spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_MSL_PLATFORM, 1));
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler_hlsl, options));
SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler_glsl, &options));
SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler_glsl, options));
SPVC_CHECKED_CALL(spvc_compiler_create_shader_resources(compiler_none, &resources));
dump_resources(compiler_none, resources);
compile(compiler_glsl, "GLSL");
compile(compiler_hlsl, "HLSL");
compile(compiler_msl, "MSL");
compile(compiler_json, "JSON");
compile(compiler_cpp, "CPP");
spvc_context_destroy(context);
free(buffer);
return 0;
}

Binary file not shown.