diff --git a/BUILD.md b/BUILD.md index df3f18cf51..4198c39d1a 100644 --- a/BUILD.md +++ b/BUILD.md @@ -9,6 +9,7 @@ - [cmake](https://cmake.org/download/): 3.9 - [Qt](https://www.qt.io/download-open-source): 5.10.1 +- [Python](https://www.python.org/downloads/): 3.6 or higher - [OpenSSL](https://www.openssl.org/): Use the latest available 1.0 version (**NOT** 1.1) of OpenSSL to avoid security vulnerabilities. - [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 1ee3d2b7c8..15c5915c51 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -40,6 +40,11 @@ Install build tools: sudo apt-get install cmake ``` +Install Python 3: +```bash +sudo apt-get install python3.6 +``` + ### Get code and checkout the tag you need diff --git a/BUILD_OSX.md b/BUILD_OSX.md index 62102b3e18..488c38e909 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -6,6 +6,10 @@ Please read the [general build guide](BUILD.md) for information on dependencies brew install cmake openssl qt +### Python 3 + +Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/). Execute the `Update Shell Profile.command` script that is provided with the installer. + ### OpenSSL Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations. @@ -28,7 +32,9 @@ Note that this uses the version from the homebrew formula at the time of this wr If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. - cmake .. -GXcode + cmake .. -G Xcode + +If `cmake` complains about Python 3 being missing, you may need to update your CMake binary with command `brew upgrade cmake`, or by downloading and running the latest CMake installer, depending on how you originally instaled CMake After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run. diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 90d2995e7d..073b048911 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -5,11 +5,17 @@ Note: We are now using Visual Studio 2017 and Qt 5.10.1. If you are upgrading fr Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory. -### Step 1. Visual Studio 2017 +### Step 1. Visual Studio 2017 & Python If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/). -When selecting components, check "Desktop development with C++." Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)". +When selecting components, check "Desktop development with C++". Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)". If you do not already have a python development environment installed, also check "Python Development" in this screen. + +If you already have Visual Studio installed and need to add python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes. + +### Step 1a. Alternate Python + +If you do not wish to use the Python installation bundled with Visual Studio, you can download the installer from [here](https://www.python.org/downloads/). Ensure you get version 3.6.6 or higher. ### Step 2. Installing CMake diff --git a/android/app/build.gradle b/android/app/build.gradle index 76f5acfaea..0136736dc3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -24,7 +24,6 @@ android { '-DANDROID_STL=c++_shared', '-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake', '-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe' + EXEC_SUFFIX, - '-DNATIVE_SHREFLECT=' + HIFI_ANDROID_PRECOMPILED + '/shreflect' + EXEC_SUFFIX, '-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED, '-DRELEASE_NUMBER=' + RELEASE_NUMBER, '-DRELEASE_TYPE=' + RELEASE_TYPE, diff --git a/android/build.gradle b/android/build.gradle index 14f9e4803f..aafb96689e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -161,31 +161,19 @@ def packages = [ ] ] - def scribeLocalFile='scribe' + EXEC_SUFFIX def scribeFile='scribe_linux_x86_64' -def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6' -def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G' - -def shreflectLocalFile='shreflect' + EXEC_SUFFIX -def shreflectFile='shreflect_linux_x86_64' -def shreflectChecksum='d6094a8580066c0b6f4e80b5adfb1d98' -def shreflectVersion='jnrpudh6fptIg6T2.Z6fgKP2ultAdKmE' +def scribeChecksum='4635c28192724281d2367ce9e94380ab' +def scribeVersion='mPAY_N846oZH1tPY1bwChB_hzqkiYyoC' if (Os.isFamily(Os.FAMILY_MAC)) { scribeFile = 'scribe_osx_x86_64' - scribeChecksum='72db9d32d4e1e50add755570ac5eb749' - scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC' - shreflectFile='shreflect_osx_x86_64' - shreflectChecksum='d613ef0703c21371fee93fd2e54b964f' - shreflectVersion='.rYNzjSFq6WtWDnE5KIKRIAGyJtr__ad' + scribeChecksum='1ead61c285d265eba9a5ef91ae3b7c26' + scribeVersion='4TAXWdo9fviw60N2wUA8HNyQ9TabjZa3' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { scribeFile = 'scribe_win32_x86_64.exe' - scribeChecksum='678e43d290c90fda670c6fefe038a06d' - scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7' - shreflectFile='shreflect_win32_x86_64.exe' - shreflectChecksum='6f4a77b8cceb3f1bbc655132c3665060' - shreflectVersion='iIyCyza1nelkbI7ihybF59bBlwrfAC3D' + scribeChecksum='9c29a62595daf4844f95f6744d568c15' + scribeVersion='DUoxjufeX8ZAIVRBKRczWTuZwT13enTv' } def options = [ @@ -461,27 +449,11 @@ task fixScribePermissions(type: Exec, dependsOn: verifyScribe) { commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + scribeLocalFile } -task downloadShreflect(type: Download) { - src baseUrl + shreflectFile + '?versionId=' + shreflectVersion - dest new File(baseFolder, shreflectLocalFile) - onlyIfNewer true -} - -task verifyShreflect(type: Verify, dependsOn: downloadShreflect) { - src new File(baseFolder, shreflectLocalFile); - checksum shreflectChecksum -} - -task fixShreflectPermissions(type: Exec, dependsOn: verifyShreflect) { - commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + shreflectLocalFile -} - -task setupScribe(dependsOn: [verifyScribe, verifyShreflect]) { } +task setupScribe(dependsOn: [verifyScribe]) { } // On Windows, we don't need to set the executable bit, but on OSX and Unix we do if (!Os.isFamily(Os.FAMILY_WINDOWS)) { setupScribe.dependsOn fixScribePermissions - setupScribe.dependsOn fixShreflectPermissions } task extractGvrBinaries(dependsOn: extractDependencies) { diff --git a/cmake/externals/glslang/CMakeLists.txt b/cmake/externals/glslang/CMakeLists.txt new file mode 100644 index 0000000000..4f8a6edf0d --- /dev/null +++ b/cmake/externals/glslang/CMakeLists.txt @@ -0,0 +1,42 @@ +set(EXTERNAL_NAME glslang) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/glslang/archive/7.8.2853.zip + URL_MD5 4f93e3818528176c622c137fba05cbf8 + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=-$ + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +# includes +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$") + +list(APPEND INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include) +#list(APPEND INCLUDE_DIRS ${INSTALL_DIR}/include) +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INCLUDE_DIRS} CACHE PATH "List of glslang include directories") +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of glslang include directories") + + +set(LIB_DIR ${SUFFIXED_INSTALL_DIR}/lib) +list(APPEND LIB_NAMES glslang HLSL OGLCompiler OSDependent SPIRV SPVRemapper) +include(SelectLibraryConfigurations) + +foreach(BASE_LIB ${LIB_NAMES}) + string(TOUPPER ${BASE_LIB} BASE_LIB_UPPER) + list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${LIB_DIR}/${BASE_LIB}.lib") + list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "${LIB_DIR}/${BASE_LIB}d.lib") +endforeach() + +select_library_configurations(${EXTERNAL_NAME_UPPER}) + +set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of glslang libraries") +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of glslang libraries") diff --git a/cmake/externals/spirv_binaries/CMakeLists.txt b/cmake/externals/spirv_binaries/CMakeLists.txt new file mode 100644 index 0000000000..d422eb9f16 --- /dev/null +++ b/cmake/externals/spirv_binaries/CMakeLists.txt @@ -0,0 +1,34 @@ +set(EXTERNAL_NAME spirv_binaries) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) +if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-win32-1.1.82.1.tar.gz) + set(DOWNLOAD_MD5 3a83ef490bce248b1a4d6726a3e5893e) + set(BIN_DIR "Bin") +elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-macos-1.1.82.1.tar.gz) + set(DOWNLOAD_MD5 a57d37275b2c5db023ba8e84a63461ff) + set(BIN_DIR "macOS/bin") +else () + set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-linux-x86_64-1.1.82.1.tar.gz) + set(DOWNLOAD_MD5 5a7c9eeda8cee6b36724da7f7cbe5ec6) + set(BIN_DIR "x86_64/bin") +endif () + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL ${DOWNLOAD_URL} + URL_MD5 ${DOWNLOAD_MD5} + BUILD_COMMAND "" + CONFIGURE_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +set(${EXTERNAL_NAME_UPPER}_DIR "${SOURCE_DIR}/${BIN_DIR}" CACHE FILEPATH "SPIRV binary tools location") + diff --git a/cmake/externals/spirv_cross/CMakeLists.txt b/cmake/externals/spirv_cross/CMakeLists.txt new file mode 100644 index 0000000000..eaa7e4ffa1 --- /dev/null +++ b/cmake/externals/spirv_cross/CMakeLists.txt @@ -0,0 +1,35 @@ +set(EXTERNAL_NAME spirv_cross) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/SPIRV-Cross/archive/2018-08-07.zip + URL_MD5 11198e4dc6a815ffbdb7a0a56d2d9261 + CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=-$ ${EXTRA_CMAKE_FLAGS} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$") + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of Draco include directories") + +if (UNIX) + set(LIB_PREFIX "lib") + set(LIB_EXT "a") +elseif (WIN32) + set(LIB_EXT "lib") +endif () + +foreach(lib glsl msl cpp hlsl reflect util core) + list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/spirv-cross-${lib}.${LIB_EXT}) +endforeach() + +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Path to SPIRV-Cross libraries") diff --git a/cmake/externals/spirv_headers/CMakeLists.txt b/cmake/externals/spirv_headers/CMakeLists.txt new file mode 100644 index 0000000000..9613f97991 --- /dev/null +++ b/cmake/externals/spirv_headers/CMakeLists.txt @@ -0,0 +1,18 @@ +set(EXTERNAL_NAME spirv_headers) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/SPIRV-Headers/archive/2c512180ca03b5d4f56283efc85745775b45fdc4.zip + URL_MD5 83e652221b5f21d5fdb61c45f5b4d9f9 + CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH= ${EXTRA_CMAKE_FLAGS} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(${EXTERNAL_NAME_UPPER}_ROOT ${INSTALL_DIR} CACHE PATH "List of include directories") diff --git a/cmake/externals/spirv_tools/CMakeLists.txt b/cmake/externals/spirv_tools/CMakeLists.txt new file mode 100644 index 0000000000..a58d72502e --- /dev/null +++ b/cmake/externals/spirv_tools/CMakeLists.txt @@ -0,0 +1,33 @@ +set(EXTERNAL_NAME spirv_tools) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/SPIRV-Tools/archive/v2018.4.zip + URL_MD5 7a7c69cf6ff0318910b4bfbdf30bcfc9 + CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DSPIRV-Headers_SOURCE_DIR=${SPIRV_HEADERS_ROOT} -DCMAKE_INSTALL_PREFIX:PATH=-$ ${EXTRA_CMAKE_FLAGS} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$") + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of SPIRV-Tools include directories") + +if (UNIX) + set(LIB_PREFIX "lib") + set(LIB_EXT "a") +elseif (WIN32) + set(LIB_EXT "lib") +endif () + +list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools-opt.${LIB_EXT}) +list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools-link.${LIB_EXT}) +list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools.${LIB_EXT}) +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Path to SPIRV-Tool libraries") diff --git a/cmake/init.cmake b/cmake/init.cmake index 9adcb167df..3f632b30f8 100644 --- a/cmake/init.cmake +++ b/cmake/init.cmake @@ -10,6 +10,10 @@ if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif () +if (POLICY CMP0074) + cmake_policy(SET CMP0074 OLD) +endif () + set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets") # Hide automoc folders (for IDEs) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 9c5ad70c78..06c29e06e3 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -8,34 +8,132 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # +# FIXME use the built tools + +macro(AUTOSCRIBE_APPEND_QRC) + string(CONCAT SHADER_QRC "${SHADER_QRC}" "${ARGV1}\n") +endmacro() + +set(VULKAN_DIR $ENV{VULKAN_SDK}) +set(GLSLANG_EXEC "${VULKAN_DIR}/Bin/glslangValidator.exe") +set(SPIRV_CROSS_EXEC "${VULKAN_DIR}/Bin/spirv-cross.exe") +set(SPIRV_OPT_EXEC "${VULKAN_DIR}/Bin/spirv-opt.exe") +set(GLSLC_EXEC "${VULKAN_DIR}/Bin/glslc.exe") +set(SCRIBE_EXEC "D:/scribe.exe") + +macro(AUTOSCRIBE_PLATFORM_SHADER) + set(AUTOSCRIBE_PLATFORM_PATH "${ARGV0}") + string(REGEX MATCH "([0-9]+(es)?)(/stereo)?" PLATFORM_PATH_REGEX ${AUTOSCRIBE_PLATFORM_PATH}) + set(AUTOSCRIBE_DIALECT "${CMAKE_MATCH_1}") + if (CMAKE_MATCH_3) + set(AUTOSCRIBE_VARIANT "stereo") + else() + set(AUTOSCRIBE_VARIANT "mono") + endif() + string(REGEX REPLACE "/" "\\\\" SOURCE_GROUP_PATH ${AUTOSCRIBE_PLATFORM_PATH}) + set(SOURCE_GROUP_PATH "${SHADER_LIB}\\${SOURCE_GROUP_PATH}") + set(AUTOSCRIBE_DIALECT_HEADER "${AUTOSCRIBE_HEADER_DIR}/${AUTOSCRIBE_DIALECT}/header.glsl") + set(AUTOSCRIBE_VARIANT_HEADER "${AUTOSCRIBE_HEADER_DIR}/${AUTOSCRIBE_VARIANT}.glsl") + + set(AUTOSCRIBE_OUTPUT_FILE "${SHADERS_DIR}/${SHADER_LIB}/${AUTOSCRIBE_PLATFORM_PATH}/${SHADER_NAME}.${SHADER_TYPE}") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/scribe" "${AUTOSCRIBE_OUTPUT_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_OUTPUT_FILE}) + set_property(SOURCE ${AUTOSCRIBE_OUTPUT_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SCRIBED_SHADERS ${AUTOSCRIBE_OUTPUT_FILE}) + + set(AUTOSCRIBE_SPIRV_FILE "${AUTOSCRIBE_OUTPUT_FILE}.spv") + # don't add unoptimized spirv to the QRC + #AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/spirv_unopt" "${AUTOSCRIBE_SPIRV_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_FILE}) + + set(AUTOSCRIBE_SPIRV_OPT_FILE "${AUTOSCRIBE_OUTPUT_FILE}.opt.spv") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/spirv" "${AUTOSCRIBE_SPIRV_OPT_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_OPT_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_OPT_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_OPT_FILE}) + + set(AUTOSCRIBE_SPIRV_GLSL_FILE "${AUTOSCRIBE_OUTPUT_FILE}.glsl") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/glsl" "${AUTOSCRIBE_SPIRV_GLSL_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_GLSL_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_GLSL_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_GLSL_FILE}) + + set(AUTOSCRIBE_SPIRV_JSON_FILE "${AUTOSCRIBE_OUTPUT_FILE}.json") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/json" "${AUTOSCRIBE_SPIRV_JSON_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_JSON_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_JSON_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND REFLECTED_SHADERS ${AUTOSCRIBE_SPIRV_JSON_FILE}) + + unset(SHADER_GEN_LINE) + list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_DIALECT}) + list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_VARIANT}) + file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${SHADER_FILE}) + list(APPEND SHADER_GEN_LINE ${TEMP_PATH}) + file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${AUTOSCRIBE_OUTPUT_FILE}) + list(APPEND SHADER_GEN_LINE ${TEMP_PATH}) + list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_SHADER_SEEN_LIBS}) + string(CONCAT AUTOSCRIBE_SHADERGEN_COMMANDS "${AUTOSCRIBE_SHADERGEN_COMMANDS}" "${SHADER_GEN_LINE}\n") + + # # FIXME need better mechanism for determining the include files + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_OUTPUT_FILE} + # COMMAND ${SCRIBE_COMMAND} ${SHADER_FILE} ${SCRIBE_ARGS} -o ${AUTOSCRIBE_OUTPUT_FILE} -h ${AUTOSCRIBE_DIALECT_HEADER} -h ${AUTOSCRIBE_VARIANT_HEADER} + # DEPENDS ${SCRIBE_COMMAND} ${SHADER_FILE} ${AUTOSCRIBE_DIALECT_HEADER} ${AUTOSCRIBE_VARIANT_HEADER}) + + # # Generate the spirv file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_FILE} + # COMMAND ${GLSLANG_EXEC} -V110 -o ${AUTOSCRIBE_SPIRV_FILE} ${AUTOSCRIBE_OUTPUT_FILE} + # DEPENDS ${AUTOSCRIBE_OUTPUT_FILE} ${GLSLANG_EXEC}) + + # # Generate the optimized spirv file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_OPT_FILE} + # COMMAND ${SPIRV_OPT_EXEC} -O ${AUTOSCRIBE_SPIRV_FILE} -o ${AUTOSCRIBE_SPIRV_OPT_FILE} + # DEPENDS ${AUTOSCRIBE_SPIRV_FILE} ${SPIRV_OPT_EXEC}) + + # # Generate the optimized GLSL file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_GLSL_FILE} + # COMMAND ${SPIRV_CROSS_EXEC} ${SPIRV_CROSS_ARGS} ${AUTOSCRIBE_SPIRV_OPT_FILE} --output ${AUTOSCRIBE_SPIRV_GLSL_FILE} + # DEPENDS ${AUTOSCRIBE_SPIRV_OPT_FILE} ${SPIRV_CROSS_EXEC}) + + # # Generate the optimized spirv file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_JSON_FILE} + # COMMAND ${SPIRV_CROSS_EXEC} --reflect json ${AUTOSCRIBE_SPIRV_OPT_FILE} --output ${AUTOSCRIBE_SPIRV_JSON_FILE} + # DEPENDS ${AUTOSCRIBE_SPIRV_OPT_FILE} ${SPIRV_CROSS_EXEC}) +endmacro() + macro(AUTOSCRIBE_SHADER) + # + # Set the include paths + # + # FIXME base the include paths off of output from the scribe tool, + # instead of treating every previously seen shader as a possible header unset(SHADER_INCLUDE_FILES) - # Grab include files foreach(includeFile ${ARGN}) list(APPEND SHADER_INCLUDE_FILES ${includeFile}) endforeach() - foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES}) get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH) list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR}) endforeach() - - list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS) - #Extract the unique include shader paths set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES}) foreach(EXTRA_SHADER_INCLUDE ${INCLUDES}) list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE}) endforeach() - list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS) - #message(ready for includes ${SHADER_INCLUDES_PATHS}) - - # make the scribe include arguments - set(SCRIBE_INCLUDES) + unset(SCRIBE_INCLUDES) foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS}) set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/) endforeach() + # + # Figure out the various output names + # # Define the final name of the generated shader file get_filename_component(SHADER_NAME ${SHADER_FILE} NAME_WE) get_filename_component(SHADER_EXT ${SHADER_FILE} EXT) @@ -46,38 +144,36 @@ macro(AUTOSCRIBE_SHADER) elseif(${SHADER_EXT} STREQUAL .slg) set(SHADER_TYPE geom) endif() - file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}") - set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}") - file(TO_CMAKE_PATH "${SHADER_TARGET}" COMPILED_SHADER) - set(REFLECTED_SHADER "${COMPILED_SHADER}.json") - set(SCRIBE_ARGS -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -D GLPROFILE ${GLPROFILE} -T ${SHADER_TYPE} ${SCRIBE_INCLUDES} ) - # Generate the frag/vert file - add_custom_command( - OUTPUT ${SHADER_TARGET} - COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS} - DEPENDS ${SHADER_FILE} ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES}) + # SHADER_SCRIBED -> the output of scribe + set(SHADER_SCRIBED "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}") - # Generate the json reflection - # FIXME move to spirv-cross for this task after we have spirv compatible shaders - add_custom_command( - OUTPUT ${REFLECTED_SHADER} - COMMAND ${SHREFLECT_COMMAND} ${COMPILED_SHADER} - DEPENDS ${SHREFLECT_DEPENDENCY} ${COMPILED_SHADER}) + # SHADER_NAME_FILE -> a file containing the shader name and extension (useful for debugging and for + # determining the type of shader from the filename) + set(SHADER_NAME_FILE "${SHADER_SCRIBED}.name") + file(TO_CMAKE_PATH "${SHADER_SCRIBED}" SHADER_SCRIBED) + file(WRITE "${SHADER_SCRIBED}.name" "${SHADER_NAME}.${SHADER_TYPE}") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/name" "${SHADER_NAME_FILE}") - #output the generated file name - source_group("Compiled/${SHADER_LIB}" FILES ${COMPILED_SHADER}) - set_property(SOURCE ${COMPILED_SHADER} PROPERTY SKIP_AUTOMOC ON) - list(APPEND COMPILED_SHADERS ${COMPILED_SHADER}) + if (USE_GLES) + set(SPIRV_CROSS_ARGS --version 310es) + AUTOSCRIBE_PLATFORM_SHADER("310es") + AUTOSCRIBE_PLATFORM_SHADER("310es/stereo") + else() + set(SPIRV_CROSS_ARGS --version 410 --no-420pack-extension) + AUTOSCRIBE_PLATFORM_SHADER("410") + AUTOSCRIBE_PLATFORM_SHADER("410/stereo") + if (NOT APPLE) + set(SPIRV_CROSS_ARGS --version 450) + AUTOSCRIBE_PLATFORM_SHADER("450") + AUTOSCRIBE_PLATFORM_SHADER("450/stereo") + endif() + endif() - source_group("Reflected/${SHADER_LIB}" FILES ${REFLECTED_SHADER}) - list(APPEND REFLECTED_SHADERS ${REFLECTED_SHADER}) - - string(CONCAT SHADER_QRC "${SHADER_QRC}" "${COMPILED_SHADER}\n") - string(CONCAT SHADER_QRC "${SHADER_QRC}" "${REFLECTED_SHADER}\n") string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${SHADER_NAME} = ${SHADER_COUNT},\n") - + string(CONCAT SHADER_SHADERS_ARRAY "${SHADER_SHADERS_ARRAY}" "${SHADER_COUNT},\n") MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1") endmacro() @@ -86,6 +182,8 @@ macro(AUTOSCRIBE_SHADER_LIB) message(FATAL_ERROR "AUTOSCRIBE_SHADER_LIB can only be used by the shaders library") endif() + file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}") + list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES "${CMAKE_SOURCE_DIR}/libraries/${SHADER_LIB}/src") string(REGEX REPLACE "[-]" "_" SHADER_NAMESPACE ${SHADER_LIB}) string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace ${SHADER_NAMESPACE} {\n") @@ -165,66 +263,103 @@ macro(AUTOSCRIBE_SHADER_LIB) # Finish the shader enums string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "} // namespace ${SHADER_NAMESPACE}\n") - #file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") - #foreach(HIFI_LIBRARY ${ARGN}) - #list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src) - #endforeach() - #endif() endmacro() macro(AUTOSCRIBE_SHADER_LIBS) - set(SCRIBE_COMMAND scribe) - set(SHREFLECT_COMMAND shreflect) - set(SHREFLECT_DEPENDENCY shreflect) - - # Target dependant Custom rule on the SHADER_FILE - if (ANDROID) - set(GLPROFILE LINUX_GL) - set(SCRIBE_COMMAND ${NATIVE_SCRIBE}) - set(SHREFLECT_COMMAND ${NATIVE_SHREFLECT}) - unset(SHREFLECT_DEPENDENCY) - else() - if (APPLE) - set(GLPROFILE MAC_GL) - elseif(UNIX) - set(GLPROFILE LINUX_GL) - else() - set(GLPROFILE PC_GL) - endif() - endif() - + message(STATUS "Shader processing start") + set(AUTOSCRIBE_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/headers) # Start the shader IDs - set(SHADER_COUNT 1) set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders") - set(SHADER_ENUMS "") file(MAKE_DIRECTORY ${SHADERS_DIR}) + set(SHADER_ENUMS "") + set(SHADER_COUNT 1) # # Scribe generation & program defintiion # foreach(SHADER_LIB ${ARGN}) + list(APPEND AUTOSCRIBE_SHADER_SEEN_LIBS ${SHADER_LIB}) AUTOSCRIBE_SHADER_LIB(${SHADER_LIB}) endforeach() # Generate the library files configure_file( ShaderEnums.cpp.in - ${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp) + ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.cpp) configure_file( ShaderEnums.h.in - ${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h) - configure_file( - shaders.qrc.in - ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.h) - set(AUTOSCRIBE_SHADER_LIB_SRC "${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h;${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp") - set(QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + configure_file(shaders.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + list(APPEND QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + + list(APPEND AUTOSCRIBE_SHADER_HEADERS ${AUTOSCRIBE_HEADER_DIR}/mono.glsl ${AUTOSCRIBE_HEADER_DIR}/stereo.glsl) + list(APPEND AUTOSCRIBE_SHADER_HEADERS ${AUTOSCRIBE_HEADER_DIR}/450/header.glsl ${AUTOSCRIBE_HEADER_DIR}/410/header.glsl ${AUTOSCRIBE_HEADER_DIR}/310es/header.glsl) + source_group("Shader Headers" FILES ${AUTOSCRIBE_HEADER_DIR}/mono.glsl ${AUTOSCRIBE_HEADER_DIR}/stereo.glsl) + source_group("Shader Headers\\450" FILES ${AUTOSCRIBE_HEADER_DIR}/450/header.glsl) + source_group("Shader Headers\\410" FILES ${AUTOSCRIBE_HEADER_DIR}/410/header.glsl) + source_group("Shader Headers\\310es" FILES ${AUTOSCRIBE_HEADER_DIR}/310es/header.glsl) + + list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_HEADERS}) + list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.h ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.cpp) + # Write the shadergen command list + set(AUTOSCRIBE_SHADERGEN_COMMANDS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shadergen.txt) + file(WRITE ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} "${AUTOSCRIBE_SHADERGEN_COMMANDS}") + + # grab the SPIRV binaries we require + # note we don't use the normal ADD_DEPENDENCY_EXTERNAL_PROJECTS macro because only a custom command + # depends on these, not any of our build artifacts, so there's no valid target for the add_dependencies + # call in ADD_DEPENDENCY_EXTERNAL_PROJECTS to use + add_subdirectory(${EXTERNAL_PROJECT_DIR}/spirv_binaries ${EXTERNALS_BINARY_DIR}/spirv_binaries) + + target_python() + + # A custom python script which will generate + if (ANDROID) + add_custom_command( + OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS} + COMMENT "Generating/updating shaders" + COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_SOURCE_DIR}/tools/shadergen.py + --commands ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} + --spirv-binaries ${SPIRV_BINARIES_DIR} + --scribe ${NATIVE_SCRIBE} + --build-dir ${CMAKE_CURRENT_BINARY_DIR} + --source-dir ${CMAKE_SOURCE_DIR} + DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} spirv_binaries ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS}) + else() + add_custom_command( + OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS} + COMMENT "Generating/updating shaders" + COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_SOURCE_DIR}/tools/shadergen.py + --commands ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} + --spirv-binaries ${SPIRV_BINARIES_DIR} + --scribe $ + --build-dir ${CMAKE_CURRENT_BINARY_DIR} + --source-dir ${CMAKE_SOURCE_DIR} + DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} scribe spirv_binaries ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS}) + endif() + + add_custom_target(shadergen DEPENDS ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS}) + set_target_properties(shadergen PROPERTIES FOLDER "Shaders") + # Custom targets required to force generation of the shaders via scribe - add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS}) - add_custom_target(compiled_shaders SOURCES ${COMPILED_SHADERS}) - add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS}) + add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS} ${AUTOSCRIBE_SHADER_HEADERS}) set_target_properties(scribe_shaders PROPERTIES FOLDER "Shaders") - set_target_properties(compiled_shaders PROPERTIES FOLDER "Shaders") + + add_custom_target(scribed_shaders SOURCES ${SCRIBED_SHADERS}) + set_target_properties(scribed_shaders PROPERTIES FOLDER "Shaders") + add_dependencies(scribed_shaders shadergen) + + add_custom_target(spirv_shaders SOURCES ${SPIRV_SHADERS}) + set_target_properties(spirv_shaders PROPERTIES FOLDER "Shaders") + add_dependencies(spirv_shaders shadergen) + + add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS}) set_target_properties(reflected_shaders PROPERTIES FOLDER "Shaders") + add_dependencies(reflected_shaders shadergen) + + message(STATUS "Shader processing end") endmacro() + + diff --git a/cmake/macros/TargetPython.cmake b/cmake/macros/TargetPython.cmake new file mode 100644 index 0000000000..cd0ea0f34c --- /dev/null +++ b/cmake/macros/TargetPython.cmake @@ -0,0 +1,22 @@ +macro(TARGET_PYTHON) + if (NOT HIFI_PYTHON_EXEC) + # Find the python interpreter + if (CAME_VERSION VERSION_LESS 3.12) + # this logic is deprecated in CMake after 3.12 + # FIXME eventually we should make 3.12 the min cmake verion and just use the Python3 find_package path + set(Python_ADDITIONAL_VERSIONS 3) + find_package(PythonInterp) + set(HIFI_PYTHON_VERSION ${PYTHON_VERSION_STRING}) + set(HIFI_PYTHON_EXEC ${PYTHON_EXECUTABLE}) + else() + # the new hotness + find_package(Python3) + set(HIFI_PYTHON_VERSION ${Python3_VERSION}) + set(HIFI_PYTHON_EXEC ${Python3_EXECUTABLE}) + endif() + + if ((NOT HIFI_PYTHON_EXEC) OR (HIFI_PYTHON_VERSION VERSION_LESS 3.5)) + message(FATAL_ERROR "Unable to locate Python interpreter 3.5 or higher") + endif() + endif() +endmacro() \ No newline at end of file diff --git a/cmake/macros/TargetSPIRV.cmake b/cmake/macros/TargetSPIRV.cmake new file mode 100644 index 0000000000..94c9df9d13 --- /dev/null +++ b/cmake/macros/TargetSPIRV.cmake @@ -0,0 +1,15 @@ +macro(TARGET_SPIRV) + add_dependency_external_projects(spirv_cross) + target_link_libraries(${TARGET_NAME} ${SPIRV_CROSS_LIBRARIES}) + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SPIRV_CROSS_INCLUDE_DIRS}) + + # spirv-tools requires spirv-headers + add_dependency_external_projects(spirv_headers) + add_dependency_external_projects(spirv_tools) + target_link_libraries(${TARGET_NAME} ${SPIRV_TOOLS_LIBRARIES}) + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SPIRV_TOOLS_INCLUDE_DIRS}) + + add_dependency_external_projects(glslang) + target_link_libraries(${TARGET_NAME} ${GLSLANG_LIBRARIES}) + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${GLSLANG_INCLUDE_DIRS}) +endmacro() diff --git a/cmake/macros/TargetSpirvBinaries.cmake b/cmake/macros/TargetSpirvBinaries.cmake new file mode 100644 index 0000000000..6cc102d38e --- /dev/null +++ b/cmake/macros/TargetSpirvBinaries.cmake @@ -0,0 +1,10 @@ +# +# Created by Bradley Austin Davis on 2016/02/16 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_SPIRV_BINARIES) + add_dependency_external_projects(spirv_binaries) +endmacro() + diff --git a/cmake/macros/TargetVulkan.cmake b/cmake/macros/TargetVulkan.cmake new file mode 100644 index 0000000000..4702583ff5 --- /dev/null +++ b/cmake/macros/TargetVulkan.cmake @@ -0,0 +1,19 @@ +# +# Created by Bradley Austin Davis on 2016/02/16 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_VULKAN) + find_package(Vulkan) + + if (Vulkan_FOUND) + add_definitions(-DHAVE_VULKAN) + target_include_directories(${TARGET_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${Vulkan_LIBRARIES}) + + add_dependency_external_projects(glslang) + target_include_directories(${TARGET_NAME} PRIVATE ${GLSLANG_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${GLSLANG_LIBRARIES}) + endif() +endmacro() \ No newline at end of file diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index e6b6986e7b..89dcc61805 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME avatars-renderer) setup_hifi_library(Network Script) -link_hifi_libraries(shared gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer) +link_hifi_libraries(shared shaders gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer) include_hifi_library_headers(avatars) include_hifi_library_headers(networking) include_hifi_library_headers(fbx) diff --git a/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf b/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf index 17dedce7f9..e70053dcd9 100644 --- a/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf +++ b/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf @@ -2,11 +2,11 @@ struct TextureData { ivec2 textureSize; }; -layout(std140, binding=0) uniform textureDataBuffer { +LAYOUT_STD140(binding=0) uniform textureDataBuffer { TextureData textureData; }; -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 580bea254a..6448c6d3a1 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -363,56 +363,35 @@ void OpenGLDisplayPlugin::customizeContext() { } if (!_presentPipeline) { + gpu::StatePointer blendState = gpu::StatePointer(new gpu::State()); + blendState->setDepthTest(gpu::State::DepthTest(false)); + blendState->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::StatePointer scissorState = gpu::StatePointer(new gpu::State()); + scissorState->setDepthTest(gpu::State::DepthTest(false)); + scissorState->setScissorEnable(true); + { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTexture); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(true); - _simplePipeline = gpu::Pipeline::create(program, state); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTexture); + _simplePipeline = gpu::Pipeline::create(program, scissorState); + _hudPipeline = gpu::Pipeline::create(program, blendState); } { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::SrgbToLinear); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(true); - _presentPipeline = gpu::Pipeline::create(program, state); + _presentPipeline = gpu::Pipeline::create(program, scissorState); } { - auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord); - auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _hudPipeline = gpu::Pipeline::create(program, state); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTextureMirroredX); + _mirrorHUDPipeline = gpu::Pipeline::create(program, blendState); } { - auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord); - auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTextureMirroredX); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _mirrorHUDPipeline = gpu::Pipeline::create(program, state); - } - - { - auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawTransformUnitQuad); - auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _cursorPipeline = gpu::Pipeline::create(program, state); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTransformedTexture); + _cursorPipeline = gpu::Pipeline::create(program, blendState); } } updateCompositeFramebuffer(); diff --git a/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf b/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf index c2bcfb5cb3..aad9e71e0e 100644 --- a/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf +++ b/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf @@ -1,10 +1,10 @@ // OpenGLDisplayPlugin_present.frag -layout(binding = 0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; -layout(location = 0) in vec2 varTexCoord0; +layout(location=0) in vec2 varTexCoord0; -layout(location = 0) out vec4 outFragColor; +layout(location=0) out vec4 outFragColor; float sRGBFloatToLinear(float value) { const float SRGB_ELBOW = 0.04045; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 5003e36e86..a705b61cd3 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -30,12 +30,14 @@ using namespace render::entities; // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; +static_assert(shader::render_utils::program::simple != 0, "Validate simple program exists"); +static_assert(shader::render_utils::program::simple_transparent != 0, "Validate simple transparent program exists"); ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { _procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple); // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering - _procedural._opaquefragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple); - _procedural._transparentfragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_transparent); + _procedural._opaqueFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple); + _procedural._transparentFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple_transparent); _procedural._opaqueState->setCullMode(gpu::State::CULL_NONE); _procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); PrepareStencil::testMaskDrawShape(*_procedural._opaqueState); diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 211685a9ba..ea54637b91 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -15,7 +15,7 @@ <@include DeferredBufferWrite.slh@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=0) in vec3 interpolatedNormal; diff --git a/libraries/entities-renderer/src/paintStroke_fade.slf b/libraries/entities-renderer/src/paintStroke_fade.slf index e5f70c8038..1ace04f7b3 100644 --- a/libraries/entities-renderer/src/paintStroke_fade.slf +++ b/libraries/entities-renderer/src/paintStroke_fade.slf @@ -18,7 +18,7 @@ <$declareFadeFragment()$> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=0) in vec3 interpolatedNormal; @@ -30,7 +30,7 @@ struct PolyLineUniforms { vec3 color; }; -layout(binding=0) uniform polyLineBuffer { +LAYOUT(binding=0) uniform polyLineBuffer { PolyLineUniforms polyline; }; diff --git a/libraries/entities-renderer/src/polyvox.slf b/libraries/entities-renderer/src/polyvox.slf index 441dfc11e5..6b1aa25a25 100644 --- a/libraries/entities-renderer/src/polyvox.slf +++ b/libraries/entities-renderer/src/polyvox.slf @@ -20,15 +20,15 @@ layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal; layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position; layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition; -layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; struct PolyvoxParams { vec4 voxelVolumeSize; }; -layout(binding=0) uniform polyvoxParamsBuffer { +LAYOUT(binding=0) uniform polyvoxParamsBuffer { PolyvoxParams params; }; diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf index 6e236193aa..ae2e05c3dc 100644 --- a/libraries/entities-renderer/src/polyvox_fade.slf +++ b/libraries/entities-renderer/src/polyvox_fade.slf @@ -23,15 +23,15 @@ layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position; layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition; layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _worldFadePosition; -layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; struct PolyvoxParams { vec4 voxelVolumeSize; }; -layout(binding=0) uniform polyvoxParamsBuffer { +LAYOUT(binding=0) uniform polyvoxParamsBuffer { PolyvoxParams params; }; diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf index 7a0cedf011..7dadb6fc49 100644 --- a/libraries/entities-renderer/src/textured_particle.slf +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -10,7 +10,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec4 varColor; layout(location=1) in vec2 varTexcoord; diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 3eacaec3b5..4d17fe132b 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -43,7 +43,7 @@ struct ParticleUniforms { vec2 spare; }; -layout(std140, binding=0) uniform particleBuffer { +LAYOUT_STD140(binding=0) uniform particleBuffer { ParticleUniforms particle; }; diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index dca495ee03..c547708ffa 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -5,4 +5,4 @@ include_hifi_library_headers(fbx) include_hifi_library_headers(gpu) include_hifi_library_headers(image) include_hifi_library_headers(ktx) -link_hifi_libraries(shared networking octree avatars graphics model-networking) \ No newline at end of file +link_hifi_libraries(shared shaders networking octree avatars graphics model-networking) \ No newline at end of file diff --git a/libraries/gpu-gl-common/CMakeLists.txt b/libraries/gpu-gl-common/CMakeLists.txt index 2b6f8d4d40..70cf3536ed 100644 --- a/libraries/gpu-gl-common/CMakeLists.txt +++ b/libraries/gpu-gl-common/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME gpu-gl-common) setup_hifi_library(Concurrent) -link_hifi_libraries(shared gl gpu) +link_hifi_libraries(shared gl gpu shaders) GroupSources("src") target_opengl() diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 267c2a97ad..c309bcb864 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -643,18 +643,21 @@ protected: } } _pipeline; - // Backend dependant compilation of the shader + // Backend dependent compilation of the shader virtual void postLinkProgram(ShaderObject& programObject, const Shader& program) const; virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler); virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler); - virtual std::string getBackendShaderHeader() const = 0; - // For a program, this will return a string containing all the source files (without any - // backend headers or defines). For a vertex, fragment or geometry shader, this will - // return the fully customized shader with all the version and backend specific + + // For a program, this will return a string containing all the source files (without any + // backend headers or defines). For a vertex, fragment or geometry shader, this will + // return the fully customized shader with all the version and backend specific // preprocessor directives // The program string returned can be used as a key for a cache of shader binaries // The shader strings can be reliably sent to the low level `compileShader` functions - virtual std::string getShaderSource(const Shader& shader, int version) final; + virtual std::string getShaderSource(const Shader& shader, shader::Variant version) final; + shader::Variant getShaderVariant() const { return isStereo() ? shader::Variant::Stereo : shader::Variant::Mono; } + virtual shader::Dialect getShaderDialect() const = 0; + class ElementResource { public: gpu::Element _element; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp index 7a06b3af86..1e811653f9 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp @@ -54,7 +54,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) { // check the program cache // pick the program version #ifdef GPU_STEREO_CAMERA_BUFFER - GLuint glprogram = pipelineObject->_program->getProgram((GLShader::Version)isStereo()); + GLuint glprogram = pipelineObject->_program->getProgram(getShaderVariant()); #else GLuint glprogram = pipelineObject->_program->getProgram(); #endif diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp index 7267e29be2..f737842ec0 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp @@ -25,120 +25,53 @@ static const std::array SHADER_DOMAINS{ { GL_GEOMETRY_SHADER, } }; -// Domain specific defines -// Must match the order of type specified in gpu::Shader::Type -static const std::array DOMAIN_DEFINES{ { - "#define GPU_VERTEX_SHADER", - "#define GPU_PIXEL_SHADER", - "#define GPU_GEOMETRY_SHADER", -} }; - -// Stereo specific defines -static const std::string stereoVersion{ -#ifdef GPU_STEREO_DRAWCALL_INSTANCED -R"SHADER( -#define GPU_TRANSFORM_IS_STEREO -#define GPU_TRANSFORM_STEREO_CAMERA -#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED -#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN -)SHADER" -#endif -#ifdef GPU_STEREO_DRAWCALL_DOUBLED -#ifdef GPU_STEREO_CAMERA_BUFFER -R"SHADER( -#define GPU_TRANSFORM_IS_STEREO -#define GPU_TRANSFORM_STEREO_CAMERA -#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED -)SHADER" -#else -R"SHADER( -#define GPU_TRANSFORM_IS_STEREO -)SHADER" -#endif -#endif -}; - -// TextureTable specific defines -static const std::string textureTableVersion { - "#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n" -}; - -// Versions specific of the shader -static const std::array VERSION_DEFINES { { - "", - stereoVersion -} }; - -static std::string getShaderTypeString(Shader::Type type) { - switch (type) { - case Shader::Type::VERTEX: - return "vertex"; - case Shader::Type::PIXEL: - return "pixel"; - case Shader::Type::GEOMETRY: - return "geometry"; - case Shader::Type::PROGRAM: - return "program"; - default: - qFatal("Unexpected shader type %d", type); - Q_UNREACHABLE(); - } -} - -std::string GLBackend::getShaderSource(const Shader& shader, int version) { +std::string GLBackend::getShaderSource(const Shader& shader, shader::Variant variant) { if (shader.isProgram()) { std::string result; - result.append("// VERSION " + std::to_string(version)); for (const auto& subShader : shader.getShaders()) { - result.append("//-------- "); - result.append(getShaderTypeString(subShader->getType())); - result.append("\n"); - result.append(subShader->getSource().getCode()); + if (subShader) { + result += subShader->getSource().getSource(getShaderDialect(), variant); + } } return result; - } - - std::string shaderDefines = getBackendShaderHeader() + "\n" - + (supportsBindless() ? textureTableVersion : "\n") - + DOMAIN_DEFINES[shader.getType()] + "\n" - + VERSION_DEFINES[version]; - - return shaderDefines + "\n" + shader.getSource().getCode(); + } + return shader.getSource().getSource(getShaderDialect(), variant); } GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) { // Any GLSLprogram ? normally yes... GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; GLShader::ShaderObjects shaderObjects; - Shader::CompilationLogs compilationLogs(GLShader::NumVersions); + const auto& variants = shader::allVariants(); + Shader::CompilationLogs compilationLogs(variants.size()); shader.incrementCompilationAttempt(); - - for (int version = 0; version < GLShader::NumVersions; version++) { - auto& shaderObject = shaderObjects[version]; - auto shaderSource = getShaderSource(shader, version); + for (const auto& variant : variants) { + auto index = static_cast(variant); + auto shaderSource = getShaderSource(shader, variant); + auto& shaderObject = shaderObjects[index]; if (handler) { bool retest = true; std::string currentSrc = shaderSource; // When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails. - // The retest bool is set to false as soon as the compilation succeed to wexit the while loop. + // The retest bool is set to false as soon as the compilation succeed to exit the while loop. // The handler tells us if we should retry or not while returning a modified version of the source. while (retest) { - bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[version].message); - compilationLogs[version].compiled = result; + bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[index].message); + compilationLogs[index].compiled = result; if (!result) { std::string newSrc; - retest = handler(shader, currentSrc, compilationLogs[version], newSrc); + retest = handler(shader, currentSrc, compilationLogs[index], newSrc); currentSrc = newSrc; } else { retest = false; } } } else { - compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[version].message); + compilationLogs[index].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[index].message); } - if (!compilationLogs[version].compiled) { - qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str(); + if (!compilationLogs[index].compiled) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[index].message.c_str(); shader.setCompilationLogs(compilationLogs); return nullptr; } @@ -162,11 +95,13 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: GLShader::ShaderObjects programObjects; program.incrementCompilationAttempt(); - Shader::CompilationLogs compilationLogs(GLShader::NumVersions); + const auto& variants = shader::allVariants(); + Shader::CompilationLogs compilationLogs(variants.size()); - for (int version = 0; version < GLShader::NumVersions; version++) { - auto& programObject = programObjects[version]; - auto programSource = getShaderSource(program, version); + for (const auto& variant : variants) { + auto index = static_cast(variant); + auto& programObject = programObjects[index]; + auto programSource = getShaderSource(program, variant); auto hash = ::gl::getShaderHash(programSource); CachedShader cachedBinary; @@ -199,11 +134,11 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: for (auto subShader : program.getShaders()) { auto object = GLShader::sync((*this), *subShader, handler); if (object) { - shaderGLObjects.push_back(object->_shaderObjects[version].glshader); + shaderGLObjects.push_back(object->_shaderObjects[index].glshader); } else { qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?"; - compilationLogs[version].compiled = false; - compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?"); + compilationLogs[index].compiled = false; + compilationLogs[index].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?"); program.setCompilationLogs(compilationLogs); return nullptr; } @@ -211,9 +146,9 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: glprogram = ::gl::buildProgram(shaderGLObjects); - if (!::gl::linkProgram(glprogram, compilationLogs[version].message)) { - qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str(); - compilationLogs[version].compiled = false; + if (!::gl::linkProgram(glprogram, compilationLogs[index].message)) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[index].message.c_str(); + compilationLogs[index].compiled = false; glDeleteProgram(glprogram); glprogram = 0; return nullptr; @@ -228,12 +163,12 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: } if (glprogram == 0) { - qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str(); + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[index].message.c_str(); program.setCompilationLogs(compilationLogs); return nullptr; } - compilationLogs[version].compiled = true; + compilationLogs[index].compiled = true; programObject.glprogram = glprogram; postLinkProgram(programObject, program); } @@ -249,7 +184,10 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: static const GLint INVALID_UNIFORM_INDEX = -1; GLint GLBackend::getRealUniformLocation(GLint location) const { - auto& shader = _pipeline._programShader->_shaderObjects[(GLShader::Version)isStereo()]; + auto variant = isStereo() ? shader::Variant::Stereo : shader::Variant::Mono; + auto index = static_cast(variant); + + auto& shader = _pipeline._programShader->_shaderObjects[index]; auto itr = shader.uniformRemap.find(location); if (itr == shader.uniformRemap.end()) { // This shouldn't happen, because we use reflection to determine all the possible @@ -264,20 +202,23 @@ GLint GLBackend::getRealUniformLocation(GLint location) const { void GLBackend::postLinkProgram(ShaderObject& shaderObject, const Shader& program) const { const auto& glprogram = shaderObject.glprogram; - const auto& expectedUniforms = program.getUniforms(); - const auto expectedLocationsByName = expectedUniforms.getLocationsByName(); - const auto uniforms = ::gl::Uniform::load(glprogram, expectedUniforms.getNames()); - auto& uniformRemap = shaderObject.uniformRemap; + const auto& expectedUniforms = program.getReflection().uniforms; - // Pre-initialize all the uniforms with an invalid location - for (const auto& entry : expectedLocationsByName) { + auto& uniformRemap = shaderObject.uniformRemap; + // initialize all the uniforms with an invalid location + for (const auto& entry : expectedUniforms) { uniformRemap[entry.second] = INVALID_UNIFORM_INDEX; } - // Now load up all the actual found uniform location + + // Get the actual uniform locations from the shader + const auto names = Shader::Reflection::getNames(expectedUniforms); + const auto uniforms = ::gl::Uniform::load(glprogram, names); + + // Now populate the remapping with the found locations for (const auto& uniform : uniforms) { const auto& name = uniform.name; - const auto& expectedLocation = expectedLocationsByName.at(name); + const auto& expectedLocation = expectedUniforms.at(name); const auto& location = uniform.binding; uniformRemap[expectedLocation] = location; } @@ -462,3 +403,4 @@ void GLBackend::initShaderBinaryCache() { void GLBackend::killShaderBinaryCache() { ::gl::saveShaderCache(_shaderBinaryCache._binaries); } + diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp index a099e6e66a..e00dc9fc25 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp @@ -52,7 +52,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) { // Special case for view correction matrices, any pipeline that declares the correction buffer // uniform will automatically have it provided without any client code necessary. // Required for stable lighting in the HMD. - object->_cameraCorrection = shader->getUniformBuffers().isValid(gpu::slot::buffer::CameraCorrection); + object->_cameraCorrection = shader->getReflection().validUniformBuffer(gpu::slot::buffer::CameraCorrection); object->_program = programObject; object->_state = stateObject; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLShader.h b/libraries/gpu-gl-common/src/gpu/gl/GLShader.h index 5d5d8a4a3c..1d56bb2122 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLShader.h @@ -14,43 +14,45 @@ namespace gpu { namespace gl { struct ShaderObject { - GLuint glshader { 0 }; - GLuint glprogram { 0 }; + enum class BindingType + { + INPUT, + OUTPUT, + TEXTURE, + SAMPLER, + UNIFORM_BUFFER, + RESOURCE_BUFFER, + UNIFORM, + }; - using LocationMap = std::unordered_map ; - LocationMap uniformRemap; + using LocationMap = std::unordered_map; + using ReflectionMap = std::map; + using UniformMap = std::unordered_map; + + GLuint glshader{ 0 }; + GLuint glprogram{ 0 }; + + UniformMap uniformRemap; }; class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr); - - enum Version { - Mono = 0, - Stereo, - - NumVersions - }; - using ShaderObject = gpu::gl::ShaderObject; - using ShaderObjects = std::array< ShaderObject, NumVersions >; - - using UniformMapping = std::map; - using UniformMappingVersions = std::vector; + using ShaderObjects = std::array; GLShader(const std::weak_ptr& backend); ~GLShader(); ShaderObjects _shaderObjects; - GLuint getProgram(Version version = Mono) const { - return _shaderObjects[version].glprogram; + GLuint getProgram(shader::Variant version = shader::Variant::Mono) const { + return _shaderObjects[static_cast(version)].glprogram; } const std::weak_ptr _backend; }; -} } - +}} // namespace gpu::gl #endif diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index faddab8531..225c795754 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME gpu-gl) setup_hifi_library(Concurrent) -link_hifi_libraries(shared gl gpu gpu-gl-common) +link_hifi_libraries(shared gl gpu gpu-gl-common shaders) if (UNIX) target_link_libraries(${TARGET_NAME} pthread) endif(UNIX) diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 5d691d032a..881487c9db 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -170,8 +170,7 @@ protected: // Output stage void do_blit(const Batch& batch, size_t paramOffset) override; - std::string getBackendShaderHeader() const override; - + shader::Dialect getShaderDialect() const override { return shader::Dialect::glsl410; } void postLinkProgram(ShaderObject& programObject, const Shader& program) const override; }; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp index 46f91fdc15..f162afc497 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp @@ -12,22 +12,13 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl41; -// GLSL version -std::string GL41Backend::getBackendShaderHeader() const { - static const std::string header( - R"SHADER(#version 410 core - #define GPU_GL410 - #define BITFIELD int - )SHADER"); - return header; -} - void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& program) const { Parent::postLinkProgram(programObject, program); const auto& glprogram = programObject.glprogram; + const auto& reflection = program.getReflection(); // For the UBOs, use glUniformBlockBinding to fixup the locations based on the reflection { - const auto expectedUbos = program.getUniformBuffers().getLocationsByName(); + const auto& expectedUbos = reflection.uniformBuffers; auto ubos = ::gl::UniformBlock::load(glprogram); for (const auto& ubo : ubos) { const auto& name = ubo.name; @@ -41,7 +32,7 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro // For the Textures, use glUniform1i to fixup the active texture slots based on the reflection { - const auto expectedTextures = program.getTextures().getLocationsByName(); + const auto& expectedTextures = reflection.textures; for (const auto& expectedTexture : expectedTextures) { auto location = glGetUniformLocation(glprogram, expectedTexture.first.c_str()); if (location < 0) { @@ -53,8 +44,9 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro // For the resource buffers, do the same as for the textures, since in GL 4.1 that's how they're implemented { - const auto expectedResourceBuffers = program.getResourceBuffers().getLocationsByName(); - const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, program.getResourceBuffers().getNames()); + const auto& expectedResourceBuffers = reflection.resourceBuffers; + const auto names = Shader::Reflection::getNames(expectedResourceBuffers); + const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, names); for (const auto& resourceBuffer : resourceBufferUniforms) { const auto& targetBinding = expectedResourceBuffers.at(resourceBuffer.name); glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 77095375af..c1ce074188 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -23,7 +23,7 @@ #define GPU_BINDLESS_TEXTURES 0 namespace gpu { namespace gl45 { - + using namespace gpu::gl; using TextureWeakPointer = std::weak_ptr; @@ -56,6 +56,7 @@ public: using Parent = GLTexture; friend class GL45Backend; static GLuint allocate(const Texture& texture); + protected: GL45Texture(const std::weak_ptr& backend, const Texture& texture); void generateMips() const override; @@ -88,6 +89,7 @@ public: virtual const Bindless& getBindless() const; void releaseBindless() const; void recreateBindless() const; + private: mutable Bindless _bindless; #endif @@ -98,10 +100,11 @@ public: mutable Sampler _cachedSampler{ getInvalidSampler() }; }; -#if GPU_BINDLESS_TEXTURES +#if GPU_BINDLESS_TEXTURES class GL45TextureTable : public GLObject { static GLuint allocate(); using Parent = GLObject; + public: using BindlessArray = std::array; @@ -116,7 +119,6 @@ public: }; #endif - // // Textures that have fixed allocation sizes and cannot be managed at runtime // @@ -134,12 +136,13 @@ public: void allocateStorage() const; void syncSampler() const override; - const Size _size { 0 }; + const Size _size{ 0 }; }; class GL45AttachmentTexture : public GL45FixedAllocationTexture { using Parent = GL45FixedAllocationTexture; friend class GL45Backend; + protected: GL45AttachmentTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45AttachmentTexture(); @@ -148,6 +151,7 @@ public: class GL45StrictResourceTexture : public GL45FixedAllocationTexture { using Parent = GL45FixedAllocationTexture; friend class GL45Backend; + protected: GL45StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45StrictResourceTexture(); @@ -179,6 +183,7 @@ public: class GL45ResourceTexture : public GL45VariableAllocationTexture { using Parent = GL45VariableAllocationTexture; friend class GL45Backend; + protected: GL45ResourceTexture(const std::weak_ptr& backend, const Texture& texture); @@ -186,7 +191,6 @@ public: size_t promote() override; size_t demote() override; void populateTransferQueue(TransferQueue& pendingTransfers) override; - void allocateStorage(uint16 mip); Size copyMipsFromTexture(); @@ -226,7 +230,6 @@ public: }; #endif - protected: void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; @@ -244,7 +247,6 @@ protected: GLuint getQueryID(const QueryPointer& query) override; GLQuery* syncGPUObject(const Query& query) override; - // Draw Stage void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; @@ -270,7 +272,7 @@ protected: void do_blit(const Batch& batch, size_t paramOffset) override; // Shader Stage - std::string getBackendShaderHeader() const override; + shader::Dialect getShaderDialect() const override; // Texture Management Stage void initTextureManagementStage() override; @@ -282,9 +284,8 @@ protected: #endif }; -} } +}} // namespace gpu::gl45 Q_DECLARE_LOGGING_CATEGORY(gpugl45logging) #endif - diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp index 6cc0d226d6..cf8279b8e6 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp @@ -7,22 +7,16 @@ // #include "GL45Backend.h" #include -//#include using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -// GLSL version -std::string GL45Backend::getBackendShaderHeader() const { - static const std::string header( - R"SHADER(#version 450 core - #define GPU_GL450 - #define BITFIELD int - )SHADER" -#ifdef GPU_SSBO_TRANSFORM_OBJECT - R"SHADER(#define GPU_SSBO_TRANSFORM_OBJECT)SHADER" +shader::Dialect GL45Backend::getShaderDialect() const { +#if defined(Q_OS_MAC) + // We build, but don't actually use GL 4.5 on OSX + throw std::runtime_error("GL 4.5 unavailable on OSX"); +#else + return shader::Dialect::glsl450; #endif - ); - return header; } diff --git a/libraries/gpu-gles/CMakeLists.txt b/libraries/gpu-gles/CMakeLists.txt index 82bf670781..3e529f7dcd 100644 --- a/libraries/gpu-gles/CMakeLists.txt +++ b/libraries/gpu-gles/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME gpu-gles) setup_hifi_library(Gui Concurrent) -link_hifi_libraries(shared gl gpu gpu-gl-common) +link_hifi_libraries(shared shaders gl gpu gpu-gl-common) GroupSources("src") target_opengl() diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h index 7f6765c129..8ecdb2494b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -27,11 +27,7 @@ class GLESBackend : public GLBackend { friend class Context; public: - static const GLint TRANSFORM_OBJECT_SLOT { 31 }; static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 }; - static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 }; - static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 }; - static const GLint RESOURCE_BUFFER_SLOT0_TEX_UNIT { 35 }; explicit GLESBackend(bool syncCache) : Parent(syncCache) {} GLESBackend() : Parent() {} virtual ~GLESBackend() { @@ -166,7 +162,7 @@ protected: // Output stage void do_blit(const Batch& batch, size_t paramOffset) override; - std::string getBackendShaderHeader() const override; + shader::Dialect getShaderDialect() const override { return shader::Dialect::glsl310es; } }; } } diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp index ee8408c533..dded307249 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp @@ -12,15 +12,3 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gles; -// GLSL version -std::string GLESBackend::getBackendShaderHeader() const { - static const std::string header( - R"SHADER(#version 310 es - #extension GL_EXT_texture_buffer : enable - precision highp float; - precision highp samplerBuffer; - precision highp sampler2DShadow; - #define BITFIELD highp int - )SHADER"); - return header; -} diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp index 661eb0de99..7e1ee0da3b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp @@ -60,12 +60,11 @@ void GLESBackend::transferTransformState(const Batch& batch) const { glBindBuffer(GL_ARRAY_BUFFER, 0); } - glActiveTexture(GL_TEXTURE0 + GLESBackend::TRANSFORM_OBJECT_SLOT); + glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms); glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); if (!batch._objects.empty()) { glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer); } - CHECK_GL_ERROR(); // Make sure the current Camera offset is unknown before render Draw diff --git a/libraries/gpu/src/gpu/DrawColor.slf b/libraries/gpu/src/gpu/DrawColor.slf index fdea26fa68..3d5b569662 100644 --- a/libraries/gpu/src/gpu/DrawColor.slf +++ b/libraries/gpu/src/gpu/DrawColor.slf @@ -17,7 +17,7 @@ struct DrawColorParams { vec4 color; }; -layout(binding=0) uniform drawColorParamsBuffer { +LAYOUT(binding=0) uniform drawColorParamsBuffer { DrawColorParams params; }; diff --git a/libraries/gpu/src/gpu/DrawColoredTexture.slf b/libraries/gpu/src/gpu/DrawColoredTexture.slf index 0fe3707b1c..a4f03f925d 100755 --- a/libraries/gpu/src/gpu/DrawColoredTexture.slf +++ b/libraries/gpu/src/gpu/DrawColoredTexture.slf @@ -13,13 +13,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; struct DrawColorParams { vec4 color; }; -layout(binding=0) uniform drawColorParams { +LAYOUT(binding=0) uniform drawColorParams { DrawColorParams params; }; diff --git a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv index 8849cb494a..a59180ec31 100755 --- a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv +++ b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv @@ -25,7 +25,7 @@ struct TexCoordRectParams { vec4 texcoordRect; }; -layout(binding=0) uniform texcoordRectBuffer { +LAYOUT(binding=0) uniform texcoordRectBuffer { TexCoordRectParams params; }; diff --git a/libraries/gpu/src/gpu/DrawTexture.slf b/libraries/gpu/src/gpu/DrawTexture.slf index 4298729b8b..f8f06eb6ca 100755 --- a/libraries/gpu/src/gpu/DrawTexture.slf +++ b/libraries/gpu/src/gpu/DrawTexture.slf @@ -14,7 +14,7 @@ // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/gpu/src/gpu/drawTexture.slp b/libraries/gpu/src/gpu/DrawTexture.slp similarity index 57% rename from libraries/gpu/src/gpu/drawTexture.slp rename to libraries/gpu/src/gpu/DrawTexture.slp index e04be84618..f922364b75 100644 --- a/libraries/gpu/src/gpu/drawTexture.slp +++ b/libraries/gpu/src/gpu/DrawTexture.slp @@ -1,2 +1 @@ VERTEX DrawUnitQuadTexcoord -FRAGMENT DrawTexture diff --git a/libraries/gpu/src/gpu/DrawTextureMirroredX.slf b/libraries/gpu/src/gpu/DrawTextureMirroredX.slf index ab6333f08d..abb52cbe7f 100644 --- a/libraries/gpu/src/gpu/DrawTextureMirroredX.slf +++ b/libraries/gpu/src/gpu/DrawTextureMirroredX.slf @@ -14,7 +14,7 @@ // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/gpu/src/gpu/DrawTextureMirroredX.slp b/libraries/gpu/src/gpu/DrawTextureMirroredX.slp new file mode 100644 index 0000000000..db9a4a4fac --- /dev/null +++ b/libraries/gpu/src/gpu/DrawTextureMirroredX.slp @@ -0,0 +1 @@ +VERTEX DrawUnitQuadTexcoord \ No newline at end of file diff --git a/libraries/gpu/src/gpu/DrawTextureOpaque.slf b/libraries/gpu/src/gpu/DrawTextureOpaque.slf index b3227325bf..e23529e851 100755 --- a/libraries/gpu/src/gpu/DrawTextureOpaque.slf +++ b/libraries/gpu/src/gpu/DrawTextureOpaque.slf @@ -16,7 +16,7 @@ <@include gpu/ShaderConstants.h@> -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; diff --git a/libraries/gpu/src/gpu/DrawTransformedTexture.slp b/libraries/gpu/src/gpu/DrawTransformedTexture.slp new file mode 100644 index 0000000000..daeafe6012 --- /dev/null +++ b/libraries/gpu/src/gpu/DrawTransformedTexture.slp @@ -0,0 +1,2 @@ +VERTEX DrawTransformUnitQuad +FRAGMENT DrawTexture diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 0191d9d4f1..d4236ac66c 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -10,44 +10,49 @@ // #include "Shader.h" -#include -#include -#include - -#include -#include - -#include #include "Context.h" using namespace gpu; -std::atomic Shader::_nextShaderID( 1 ); -Shader::DomainShaderMaps Shader::_domainShaderMaps; Shader::ProgramMap Shader::_programMap; -Shader::Shader(Type type, const Source& source) : - _source(source), - _type(type), - _ID(_nextShaderID++) +Shader::Shader(Type type, const Source& source, bool dynamic) : + _type(type) { + auto& thisSource = const_cast(_source); + thisSource = source; + if (!dynamic) { + thisSource.id = source.id; + } } -Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel): - _type(type), - _ID(_nextShaderID++) +Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) : + _type(type) { + + auto& shaders = const_cast(_shaders); if (geometry) { - _shaders.resize(3); - _shaders[VERTEX] = vertex; - _shaders[GEOMETRY] = geometry; - _shaders[PIXEL] = pixel; + shaders.resize(3); + shaders[VERTEX] = vertex; + shaders[GEOMETRY] = geometry; + shaders[PIXEL] = pixel; } else { - _shaders.resize(2); - _shaders[VERTEX] = vertex; - _shaders[PIXEL] = pixel; + shaders.resize(2); + shaders[VERTEX] = vertex; + shaders[PIXEL] = pixel; + } + + auto& reflection = const_cast(getReflection()); + for (const auto& subShader : _shaders) { + reflection.merge(subShader->getReflection()); + } + if (_shaders[VERTEX]) { + reflection.inputs = _shaders[VERTEX]->getReflection().inputs; + } + if (_shaders[PIXEL]) { + reflection.outputs = _shaders[PIXEL]->getReflection().outputs; } } @@ -55,46 +60,27 @@ Shader::~Shader() { } -void populateSlotSet(Shader::SlotSet& slotSet, const Shader::LocationMap& map) { - for (const auto& entry : map) { - const auto& name = entry.first; - const auto& location = entry.second; - slotSet.insert({ name, location, Element() }); - } +static std::unordered_map> _shaderCache; + +Shader::ID Shader::getID() const { + if (isProgram()) { + return (_shaders[VERTEX]->getID() << 16) | (_shaders[PIXEL]->getID()); + } + + return _source.id; } -Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) { - auto found = _domainShaderMaps[type].find(source); - if (found != _domainShaderMaps[type].end()) { +Shader::Pointer Shader::createOrReuseDomainShader(Type type, uint32_t sourceId) { + // Don't attempt to cache non-static shaders + auto found = _shaderCache.find(sourceId); + if (found != _shaderCache.end()) { auto sharedShader = (*found).second.lock(); if (sharedShader) { return sharedShader; } } - auto shader = Pointer(new Shader(type, source)); - const auto& reflection = source.getReflection(); - if (0 != reflection.count(BindingType::INPUT)) { - populateSlotSet(shader->_inputs, reflection.find(BindingType::INPUT)->second); - } - if (0 != reflection.count(BindingType::OUTPUT)) { - populateSlotSet(shader->_outputs, reflection.find(BindingType::OUTPUT)->second); - } - if (0 != reflection.count(BindingType::UNIFORM_BUFFER)) { - populateSlotSet(shader->_uniformBuffers, reflection.find(BindingType::UNIFORM_BUFFER)->second); - } - if (0 != reflection.count(BindingType::RESOURCE_BUFFER)) { - populateSlotSet(shader->_resourceBuffers, reflection.find(BindingType::RESOURCE_BUFFER)->second); - } - if (0 != reflection.count(BindingType::TEXTURE)) { - populateSlotSet(shader->_textures, reflection.find(BindingType::TEXTURE)->second); - } - if (0 != reflection.count(BindingType::SAMPLER)) { - populateSlotSet(shader->_samplers, reflection.find(BindingType::SAMPLER)->second); - } - if (0 != reflection.count(BindingType::UNIFORM)) { - populateSlotSet(shader->_uniforms, reflection.find(BindingType::UNIFORM)->second); - } - _domainShaderMaps[type].emplace(source, std::weak_ptr(shader)); + auto shader = Pointer(new Shader(type, getShaderSource(sourceId), false)); + _shaderCache.insert({ sourceId, shader }); return shader; } @@ -137,28 +123,6 @@ ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& verte // Program is a new one, let's create it auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader)); - - // Combine the slots from the sub-shaders - for (const auto& shader : program->_shaders) { - const auto& reflection = shader->_source.getReflection(); - if (0 != reflection.count(BindingType::UNIFORM_BUFFER)) { - populateSlotSet(program->_uniformBuffers, reflection.find(BindingType::UNIFORM_BUFFER)->second); - } - if (0 != reflection.count(BindingType::RESOURCE_BUFFER)) { - populateSlotSet(program->_resourceBuffers, reflection.find(BindingType::RESOURCE_BUFFER)->second); - } - if (0 != reflection.count(BindingType::TEXTURE)) { - populateSlotSet(program->_textures, reflection.find(BindingType::TEXTURE)->second); - } - if (0 != reflection.count(BindingType::SAMPLER)) { - populateSlotSet(program->_samplers, reflection.find(BindingType::SAMPLER)->second); - } - if (0 != reflection.count(BindingType::UNIFORM)) { - populateSlotSet(program->_uniforms, reflection.find(BindingType::UNIFORM)->second); - } - - } - _programMap.emplace(key, std::weak_ptr(program)); return program; } @@ -175,24 +139,21 @@ void Shader::incrementCompilationAttempt() const { } Shader::Pointer Shader::createVertex(const Source& source) { - return createOrReuseDomainShader(VERTEX, source); + return Pointer(new Shader(VERTEX, source, true)); } Shader::Pointer Shader::createPixel(const Source& source) { - return createOrReuseDomainShader(FRAGMENT, source); + return Pointer(new Shader(FRAGMENT, source, true)); } Shader::Pointer Shader::createVertex(uint32_t id) { - return createVertex(getShaderSource(id)); + return createOrReuseDomainShader(VERTEX, id); } Shader::Pointer Shader::createPixel(uint32_t id) { - return createPixel(getShaderSource(id)); + return createOrReuseDomainShader(FRAGMENT, id); } -Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) { - return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader); -} Shader::Pointer Shader::createProgram(uint32_t programId) { auto vertexShader = createVertex(shader::getVertexId(programId)); @@ -200,98 +161,15 @@ Shader::Pointer Shader::createProgram(uint32_t programId) { return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, fragmentShader); } +Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) { + return Pointer(new Shader(PROGRAM, vertexShader, nullptr, pixelShader)); +} + +// Dynamic program, bypass caching Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) { - return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader); + return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader)); } -static const std::string IGNORED_BINDING = "transformObjectBuffer"; - -void updateBindingsFromJsonObject(Shader::LocationMap& inOutSet, const QJsonObject& json) { - for (const auto& key : json.keys()) { - auto keyStr = key.toStdString(); - if (IGNORED_BINDING == keyStr) { - continue; - } - inOutSet[keyStr] = json[key].toInt(); - } -} - -void updateTextureAndResourceBuffersFromJsonObjects(Shader::LocationMap& inOutTextures, Shader::LocationMap& inOutResourceBuffers, - const QJsonObject& json, const QJsonObject& types) { - static const std::string RESOURCE_BUFFER_TEXTURE_TYPE = "samplerBuffer"; - for (const auto& key : json.keys()) { - auto keyStr = key.toStdString(); - if (keyStr == IGNORED_BINDING) { - continue; - } - auto location = json[key].toInt(); - auto type = types[key].toString().toStdString(); - if (type == RESOURCE_BUFFER_TEXTURE_TYPE) { - inOutResourceBuffers[keyStr] = location; - } else { - inOutTextures[key.toStdString()] = location; - } - } -} - -Shader::ReflectionMap getShaderReflection(const std::string& reflectionJson) { - if (reflectionJson.empty() && reflectionJson != std::string("null")) { - return {}; - } - -#define REFLECT_KEY_INPUTS "inputs" -#define REFLECT_KEY_OUTPUTS "outputs" -#define REFLECT_KEY_UBOS "uniformBuffers" -#define REFLECT_KEY_SSBOS "storageBuffers" -#define REFLECT_KEY_UNIFORMS "uniforms" -#define REFLECT_KEY_TEXTURES "textures" -#define REFLECT_KEY_TEXTURE_TYPES "textureTypes" - - auto doc = QJsonDocument::fromJson(reflectionJson.c_str()); - if (doc.isNull()) { - qWarning() << "Invalid shader reflection JSON" << reflectionJson.c_str(); - return {}; - } - - Shader::ReflectionMap result; - auto json = doc.object(); - if (json.contains(REFLECT_KEY_INPUTS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::INPUT], json[REFLECT_KEY_INPUTS].toObject()); - } - if (json.contains(REFLECT_KEY_OUTPUTS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::OUTPUT], json[REFLECT_KEY_OUTPUTS].toObject()); - } - // FIXME eliminate the last of the uniforms - if (json.contains(REFLECT_KEY_UNIFORMS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::UNIFORM], json[REFLECT_KEY_UNIFORMS].toObject()); - } - if (json.contains(REFLECT_KEY_UBOS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::UNIFORM_BUFFER], json[REFLECT_KEY_UBOS].toObject()); - } - - // SSBOs need to come BEFORE the textures. In GL 4.5 the reflection slots aren't really used, but in 4.1 the slots - // are used to explicitly setup bindings after shader linkage, so we want the resource buffer slots to contain the - // texture locations, not the SSBO locations - if (json.contains(REFLECT_KEY_SSBOS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::RESOURCE_BUFFER], json[REFLECT_KEY_SSBOS].toObject()); - } - - // samplerBuffer textures map to gpu ResourceBuffer, while all other textures map to regular gpu Texture - if (json.contains(REFLECT_KEY_TEXTURES)) { - updateTextureAndResourceBuffersFromJsonObjects( - result[Shader::BindingType::TEXTURE], - result[Shader::BindingType::RESOURCE_BUFFER], - json[REFLECT_KEY_TEXTURES].toObject(), - json[REFLECT_KEY_TEXTURE_TYPES].toObject()); - } - - - return result; -} - -Shader::Source Shader::getShaderSource(uint32_t id) { - auto source = shader::loadShaderSource(id); - auto reflectionJson = shader::loadShaderReflection(id); - auto reflection = getShaderReflection(reflectionJson); - return { source, reflection }; +const Shader::Source& Shader::getShaderSource(uint32_t id) { + return shader::Source::get(id); } diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index ad828a0cff..35426bed20 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace gpu { @@ -42,58 +43,10 @@ public: typedef std::shared_ptr Pointer; typedef std::vector Shaders; - // Needs to match values in shaders/Shaders.h - enum class BindingType - { - INVALID = -1, - INPUT = 0, - OUTPUT, - TEXTURE, - SAMPLER, - UNIFORM_BUFFER, - RESOURCE_BUFFER, - UNIFORM, - }; - - using LocationMap = std::unordered_map; - using ReflectionMap = std::map; - - class Source { - public: - enum Language - { - INVALID = -1, - GLSL = 0, - SPIRV = 1, - MSL = 2, - HLSL = 3, - }; - - Source() {} - Source(const std::string& code, const ReflectionMap& reflection, Language lang = GLSL) : - _code(code), _reflection(reflection), _lang(lang) {} - Source(const Source& source) : _code(source._code), _reflection(source._reflection), _lang(source._lang) {} - virtual ~Source() {} - - virtual const std::string& getCode() const { return _code; } - virtual const ReflectionMap& getReflection() const { return _reflection; } - - class Less { - public: - bool operator()(const Source& x, const Source& y) const { - if (x._lang == y._lang) { - return x._code < y._code; - } else { - return (x._lang < y._lang); - } - } - }; - - protected: - std::string _code; - ReflectionMap _reflection; - Language _lang; - }; + using Source = shader::Source; + using Reflection = shader::Reflection; + using Dialect = shader::Dialect; + using Variant = shader::Variant; struct CompilationLog { std::string message; @@ -112,85 +65,13 @@ public: bool operator()(const T& x, const T& y) const { return x._name < y._name; } }; - class Slot { - public: - std::string _name; - int32 _location{ INVALID_LOCATION }; - Element _element; - uint16 _resourceType{ Resource::BUFFER }; - uint32 _size{ 0 }; - - Slot(const Slot& s) : - _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {} - Slot(Slot&& s) : - _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {} - Slot(const std::string& name, - int32 location, - const Element& element, - uint16 resourceType = Resource::BUFFER, - uint32 size = 0) : - _name(name), - _location(location), _element(element), _resourceType(resourceType), _size(size) {} - Slot(const std::string& name) : _name(name) {} - - Slot& operator=(const Slot& s) { - _name = s._name; - _location = s._location; - _element = s._element; - _resourceType = s._resourceType; - _size = s._size; - return (*this); - } - }; - - class SlotSet : protected std::set> { - using Parent = std::set>; - - public: - void insert(const Parent::value_type& value) { - Parent::insert(value); - if (value._location != INVALID_LOCATION) { - _validSlots.insert(value._location); - } - } - - using Parent::begin; - using Parent::empty; - using Parent::end; - using Parent::size; - - using LocationMap = std::unordered_map; - using NameVector = std::vector; - - NameVector getNames() const { - NameVector result; - for (const auto& entry : *this) { - result.push_back(entry._name); - } - return result; - } - - LocationMap getLocationsByName() const { - LocationMap result; - for (const auto& entry : *this) { - result.insert({ entry._name, entry._location }); - } - return result; - } - - bool isValid(int32 slot) const { return 0 != _validSlots.count(slot); } - - protected: - std::unordered_set _validSlots; - }; - - static Source getShaderSource(uint32_t id); - static Source getVertexShaderSource(uint32_t id) { return getShaderSource(id); } - static Source getFragmentShaderSource(uint32_t id) { return getShaderSource(id); } - + static const Source& getShaderSource(uint32_t id); + static const Source& getVertexShaderSource(uint32_t id) { return getShaderSource(id); } + static const Source& getFragmentShaderSource(uint32_t id) { return getShaderSource(id); } static Pointer createVertex(const Source& source); static Pointer createPixel(const Source& source); static Pointer createGeometry(const Source& source); + static Pointer createVertex(uint32_t shaderId); static Pointer createPixel(uint32_t shaderId); static Pointer createGeometry(uint32_t shaderId); @@ -201,8 +82,7 @@ public: ~Shader(); - ID getID() const { return _ID; } - + ID getID() const; Type getType() const { return _type; } bool isProgram() const { return getType() > NUM_DOMAINS; } bool isDomain() const { return getType() < NUM_DOMAINS; } @@ -211,17 +91,12 @@ public: const Shaders& getShaders() const { return _shaders; } - // Access the exposed uniform, input and output slot - const SlotSet& getUniforms() const { return _uniforms; } - const SlotSet& getUniformBuffers() const { return _uniformBuffers; } - const SlotSet& getResourceBuffers() const { return _resourceBuffers; } - const SlotSet& getTextures() const { return _textures; } - const SlotSet& getSamplers() const { return _samplers; } + const Reflection& getReflection() const { return _source.reflection; } // Compilation Handler can be passed while compiling a shader (in the makeProgram call) to be able to give the hand to - // the caller thread if the comilation fails and to prvide a different version of the source for it + // the caller thread if the compilation fails and to provide a different version of the source for it // @param0 the Shader object that just failed to compile - // @param1 the original source code as submited to the compiler + // @param1 the original source code as submitted to the compiler // @param2 the compilation log containing the error message // @param3 a new string ready to be filled with the new version of the source that could be proposed from the handler functor // @return boolean true if the backend should keep trying to compile the shader with the new source returned or false to stop and fail that shader compilation @@ -240,32 +115,21 @@ public: const GPUObjectPointer gpuObject{}; protected: - Shader(Type type, const Source& source); + Shader(Type type, const Source& source, bool dynamic); Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel); Shader(const Shader& shader); // deep copy of the sysmem shader Shader& operator=(const Shader& shader); // deep copy of the sysmem texture // Source contains the actual source code or nothing if the shader is a program - Source _source; + const Source _source; // if shader is composed of sub shaders, here they are - Shaders _shaders; - - // List of exposed uniform, input and output slots - SlotSet _uniforms; - SlotSet _uniformBuffers; - SlotSet _resourceBuffers; - SlotSet _textures; - SlotSet _samplers; - SlotSet _inputs; - SlotSet _outputs; + const Shaders _shaders; + // The type of the shader, the master key - Type _type; - - // The unique identifier of a shader in the GPU lib - uint32_t _ID{ 0 }; + const Type _type; // Number of attempts to compile the shader mutable uint32_t _numCompilationAttempts{ 0 }; @@ -277,13 +141,9 @@ protected: // Global maps of the shaders // Unique shader ID - static std::atomic _nextShaderID; + //static std::atomic _nextShaderID; - using ShaderMap = std::map, Source::Less>; - using DomainShaderMaps = std::array; - static DomainShaderMaps _domainShaderMaps; - - static ShaderPointer createOrReuseDomainShader(Type type, const Source& source); + static ShaderPointer createOrReuseDomainShader(Type type, uint32_t sourceId); using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key class ProgramKeyLess { diff --git a/libraries/gpu/src/gpu/ShaderConstants.h b/libraries/gpu/src/gpu/ShaderConstants.h index 0724b4eb40..e9a1821ef4 100644 --- a/libraries/gpu/src/gpu/ShaderConstants.h +++ b/libraries/gpu/src/gpu/ShaderConstants.h @@ -98,21 +98,6 @@ enum Attribute { }; } // namespace attr -namespace uniform { -enum Uniform { - Extra0 = GPU_UNIFORM_EXTRA0, - Extra1 = GPU_UNIFORM_EXTRA1, - Extra2 = GPU_UNIFORM_EXTRA2, - Extra3 = GPU_UNIFORM_EXTRA3, - Extra4 = GPU_UNIFORM_EXTRA4, - Extra5 = GPU_UNIFORM_EXTRA5, - Extra6 = GPU_UNIFORM_EXTRA6, - Extra7 = GPU_UNIFORM_EXTRA7, - Extra8 = GPU_UNIFORM_EXTRA8, - Extra9 = GPU_UNIFORM_EXTRA9, -}; -} // namespace uniform - } } // namespace gpu::slot // !> diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index fd2cb86177..43205ba4c2 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -16,7 +16,7 @@ #define TransformCamera _TransformCamera -layout(std140, binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffer { +LAYOUT_STD140(binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffer { #ifdef GPU_TRANSFORM_IS_STEREO #ifdef GPU_TRANSFORM_STEREO_CAMERA TransformCamera _camera[2]; @@ -26,7 +26,7 @@ layout(std140, binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffe #else TransformCamera _camera; #endif -}; +} _cameraBlock; #ifdef GPU_VERTEX_SHADER #ifdef GPU_TRANSFORM_IS_STEREO @@ -76,12 +76,12 @@ TransformCamera getTransformCamera() { _stereoSide = gl_InstanceID % 2; #endif #endif - return _camera[_stereoSide]; + return _cameraBlock._camera[_stereoSide]; #else - return _camera; + return _cameraBlock._camera; #endif #else - return _camera; + return _cameraBlock._camera; #endif } @@ -93,7 +93,7 @@ bool cam_isStereo() { #ifdef GPU_TRANSFORM_IS_STEREO return getTransformCamera()._stereoInfo.x > 0.0; #else - return _camera._stereoInfo.x > 0.0; + return _cameraBlock._camera._stereoInfo.x > 0.0; #endif } @@ -102,10 +102,10 @@ float cam_getStereoSide() { #ifdef GPU_TRANSFORM_STEREO_CAMERA return getTransformCamera()._stereoInfo.y; #else - return _camera._stereoInfo.y; + return _cameraBlock._camera._stereoInfo.y; #endif #else - return _camera._stereoInfo.y; + return _cameraBlock._camera._stereoInfo.y; #endif } @@ -120,7 +120,7 @@ struct TransformObject { layout(location=GPU_ATTR_DRAW_CALL_INFO) in ivec2 _drawCallInfo; #if defined(GPU_SSBO_TRANSFORM_OBJECT) -layout(std140, binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer { +LAYOUT_STD140(binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer { TransformObject _object[]; }; TransformObject getTransformObject() { @@ -128,7 +128,7 @@ TransformObject getTransformObject() { return transformObject; } #else -layout(binding=GPU_TEXTURE_TRANSFORM_OBJECT) uniform samplerBuffer transformObjectBuffer; +LAYOUT(binding=GPU_TEXTURE_TRANSFORM_OBJECT) uniform samplerBuffer transformObjectBuffer; TransformObject getTransformObject() { int offset = 8 * _drawCallInfo.x; @@ -167,7 +167,9 @@ TransformObject getTransformObject() { vec4 eyeClipEdge[2]= vec4[2](vec4(-1,0,0,1), vec4(1,0,0,1)); vec2 eyeOffsetScale = vec2(-0.5, +0.5); uint eyeIndex = uint(_stereoSide); +#ifndef GPU_GLES gl_ClipDistance[0] = dot(<$clipPos$>, eyeClipEdge[eyeIndex]); +#endif float newClipPosX = <$clipPos$>.x * 0.5 + eyeOffsetScale[eyeIndex] * <$clipPos$>.w; <$clipPos$>.x = newClipPosX; #endif diff --git a/libraries/graphics/src/graphics/Light.slh b/libraries/graphics/src/graphics/Light.slh index d22da44c66..c00bfea6a2 100644 --- a/libraries/graphics/src/graphics/Light.slh +++ b/libraries/graphics/src/graphics/Light.slh @@ -51,7 +51,7 @@ float getLightAmbientMapNumMips(LightAmbient l) { return l._ambient.y; } <@if N@> -layout(binding=GRAPHICS_BUFFER_LIGHT) uniform lightBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_LIGHT) uniform lightBuffer { Light lightArray[<$N$>]; }; Light getLight(int index) { @@ -59,7 +59,7 @@ Light getLight(int index) { } <@else@> -layout(binding=GRAPHICS_BUFFER_KEY_LIGHT) uniform keyLightBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_KEY_LIGHT) uniform keyLightBuffer { Light light; }; Light getKeyLight() { @@ -79,7 +79,7 @@ Light getKeyLight() { <@if N@> -layout(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { LightAmbient lightAmbientArray[<$N$>]; }; @@ -88,7 +88,7 @@ LightAmbient getLightAmbient(int index) { } <@else@> -layout(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { LightAmbient lightAmbient; }; diff --git a/libraries/graphics/src/graphics/Material.slh b/libraries/graphics/src/graphics/Material.slh index ea59059cf1..d2055b9a59 100644 --- a/libraries/graphics/src/graphics/Material.slh +++ b/libraries/graphics/src/graphics/Material.slh @@ -48,7 +48,7 @@ struct Material { vec4 _scatteringSpare2Key; }; -layout(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer { Material _mat; TexMapArray _texMapArray; }; diff --git a/libraries/graphics/src/graphics/MaterialTextures.slh b/libraries/graphics/src/graphics/MaterialTextures.slh index 0a60feccfc..db329c3852 100644 --- a/libraries/graphics/src/graphics/MaterialTextures.slh +++ b/libraries/graphics/src/graphics/MaterialTextures.slh @@ -11,6 +11,7 @@ <@if not MODEL_MATERIAL_TEXTURES_SLH@> <@def MODEL_MATERIAL_TEXTURES_SLH@> +<@include graphics/ShaderConstants.h@> <@include graphics/Material.slh@> <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> @@ -91,21 +92,21 @@ float fetchScatteringMap(vec2 uv) { #else <@if withAlbedo@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap; vec4 fetchAlbedoMap(vec2 uv) { return texture(albedoMap, uv, TAA_TEXTURE_LOD_BIAS); } <@endif@> <@if withRoughness@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap; float fetchRoughnessMap(vec2 uv) { return (texture(roughnessMap, uv, TAA_TEXTURE_LOD_BIAS).r); } <@endif@> <@if withNormal@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap; vec3 fetchNormalMap(vec2 uv) { // unpack normal, swizzle to get into hifi tangent space with Y axis pointing out vec2 t = 2.0 * (texture(normalMap, uv, TAA_TEXTURE_LOD_BIAS).rg - vec2(0.5, 0.5)); @@ -115,28 +116,28 @@ vec3 fetchNormalMap(vec2 uv) { <@endif@> <@if withMetallic@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_METALLIC) uniform sampler2D metallicMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_METALLIC) uniform sampler2D metallicMap; float fetchMetallicMap(vec2 uv) { return (texture(metallicMap, uv, TAA_TEXTURE_LOD_BIAS).r); } <@endif@> <@if withEmissive@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; vec3 fetchEmissiveMap(vec2 uv) { return texture(emissiveMap, uv, TAA_TEXTURE_LOD_BIAS).rgb; } <@endif@> <@if withOcclusion@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap; float fetchOcclusionMap(vec2 uv) { return texture(occlusionMap, uv).r; } <@endif@> <@if withScattering@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_SCATTERING) uniform sampler2D scatteringMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_SCATTERING) uniform sampler2D scatteringMap; float fetchScatteringMap(vec2 uv) { float scattering = texture(scatteringMap, uv, TAA_TEXTURE_LOD_BIAS).r; // boolean scattering for now return max(((scattering - 0.1) / 0.9), 0.0); @@ -185,7 +186,7 @@ float fetchScatteringMap(vec2 uv) { <$declareMaterialTexMapArrayBuffer()$> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; vec3 fetchLightmapMap(vec2 uv) { vec2 lightmapParams = getTexMapArray()._lightmapParams.xy; return (vec3(lightmapParams.x) + lightmapParams.y * texture(emissiveMap, uv).rgb); diff --git a/libraries/graphics/src/graphics/skybox.slf b/libraries/graphics/src/graphics/skybox.slf index 2b81a433f1..b24bf0f583 100755 --- a/libraries/graphics/src/graphics/skybox.slf +++ b/libraries/graphics/src/graphics/skybox.slf @@ -12,13 +12,13 @@ // <@include graphics/ShaderConstants.h@> -layout(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; +LAYOUT(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; struct Skybox { vec4 color; }; -layout(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { Skybox skybox; }; diff --git a/libraries/model-networking/CMakeLists.txt b/libraries/model-networking/CMakeLists.txt index 9a4bc780a6..12181651db 100644 --- a/libraries/model-networking/CMakeLists.txt +++ b/libraries/model-networking/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME model-networking) setup_hifi_library() -link_hifi_libraries(shared networking graphics fbx ktx image gl) +link_hifi_libraries(shared shaders networking graphics fbx ktx image gl) include_hifi_library_headers(gpu) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 79c0b31dff..1c082ed250 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -27,7 +27,7 @@ Q_LOGGING_CATEGORY(proceduralLog, "hifi.gpu.procedural") -// Userdata parsing constants +// User-data parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; static const QString URL_KEY = "shaderUrl"; static const QString VERSION_KEY = "version"; @@ -39,10 +39,7 @@ static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK"; static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; bool operator==(const ProceduralData& a, const ProceduralData& b) { - return ( - (a.version == b.version) && - (a.shaderUrl == b.shaderUrl) && - (a.uniforms == b.uniforms) && + return ((a.version == b.version) && (a.shaderUrl == b.shaderUrl) && (a.uniforms == b.uniforms) && (a.channels == b.channels)); } @@ -108,7 +105,9 @@ Procedural::Procedural() { _transparentState->setCullMode(gpu::State::CULL_NONE); _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); _transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + _standardInputsBuffer = std::make_shared(sizeof(StandardInputs), nullptr); } void Procedural::setProceduralData(const ProceduralData& proceduralData) { @@ -119,7 +118,7 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { _dirty = true; _enabled = false; - if (proceduralData.version != _data.version ) { + if (proceduralData.version != _data.version) { _data.version = proceduralData.version; _shaderDirty = true; } @@ -144,7 +143,6 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { _channels[channel] = textureCache->getTexture(QUrl()); } } - _channelsDirty = true; } if (proceduralData.shaderUrl != _data.shaderUrl) { @@ -212,28 +210,11 @@ bool Procedural::isReady() const { return true; } -std::string Procedural::replaceProceduralBlock(const std::string& fragmentSource) { - std::string result = fragmentSource; - auto replaceIndex = result.find(PROCEDURAL_VERSION); - if (replaceIndex != std::string::npos) { - if (_data.version == 1) { - result.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1"); - } else if (_data.version == 2) { - result.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1"); - } - } - replaceIndex = result.find(PROCEDURAL_BLOCK); - if (replaceIndex != std::string::npos) { - result.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data()); - } - return result; -} - void Procedural::prepare(gpu::Batch& batch, - const glm::vec3& position, - const glm::vec3& size, - const glm::quat& orientation, - const glm::vec4& color) { + const glm::vec3& position, + const glm::vec3& size, + const glm::quat& orientation, + const glm::vec4& color) { _entityDimensions = size; _entityPosition = position; _entityOrientation = glm::mat3_cast(orientation); @@ -256,19 +237,21 @@ void Procedural::prepare(gpu::Batch& batch, } // Build the fragment shader - std::string opaqueShaderSource = replaceProceduralBlock(_opaquefragmentSource.getCode()); - auto opaqueReflection = _opaquefragmentSource.getReflection(); - auto& opaqueUniforms = opaqueReflection[gpu::Shader::BindingType::UNIFORM]; - std::string transparentShaderSource = replaceProceduralBlock(_transparentfragmentSource.getCode()); - auto transparentReflection = _transparentfragmentSource.getReflection(); - auto& transparentUniforms = transparentReflection[gpu::Shader::BindingType::UNIFORM]; + _opaqueFragmentSource.replacements.clear(); + if (_data.version == 1) { + _opaqueFragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V1 1"; + } else if (_data.version == 2) { + _opaqueFragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V2 1"; + } + _opaqueFragmentSource.replacements[PROCEDURAL_BLOCK] = _shaderSource.toStdString(); + _transparentFragmentSource.replacements = _opaqueFragmentSource.replacements; // Set any userdata specified uniforms int customSlot = procedural::slot::uniform::Custom; for (const auto& key : _data.uniforms.keys()) { std::string uniformName = key.toLocal8Bit().data(); - opaqueUniforms[uniformName] = customSlot; - transparentUniforms[uniformName] = customSlot; + _opaqueFragmentSource.reflection.uniforms[uniformName] = customSlot; + _transparentFragmentSource.reflection.uniforms[uniformName] = customSlot; ++customSlot; } @@ -276,18 +259,18 @@ void Procedural::prepare(gpu::Batch& batch, // qCDebug(procedural) << "FragmentShader:\n" << fragmentShaderSource.c_str(); // TODO: THis is a simple fix, we need a cleaner way to provide the "hosting" program for procedural custom shaders to be defined together with the required bindings. - _opaqueFragmentShader = gpu::Shader::createPixel({ opaqueShaderSource, opaqueReflection }); + _opaqueFragmentShader = gpu::Shader::createPixel(_opaqueFragmentSource); _opaqueShader = gpu::Shader::createProgram(_vertexShader, _opaqueFragmentShader); - if (!transparentShaderSource.empty() && transparentShaderSource != opaqueShaderSource) { - _transparentFragmentShader = gpu::Shader::createPixel({ transparentShaderSource, transparentReflection }); + _opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState); + if (_transparentFragmentSource.valid()) { + _transparentFragmentShader = gpu::Shader::createPixel(_transparentFragmentSource); _transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader); + _transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState); } else { _transparentFragmentShader = _opaqueFragmentShader; _transparentShader = _opaqueShader; + _transparentPipeline = _opaquePipeline; } - - _opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState); - _transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState); _start = usecTimestampNow(); _frameCount = 0; } @@ -299,12 +282,8 @@ void Procedural::prepare(gpu::Batch& batch, setupUniforms(transparent); } - if (_shaderDirty || _uniformsDirty || _channelsDirty || _prevTransparent != transparent) { - setupChannels(_shaderDirty || _uniformsDirty, transparent); - } - _prevTransparent = transparent; - _shaderDirty = _uniformsDirty = _channelsDirty = false; + _shaderDirty = _uniformsDirty = false; for (auto lambda : _uniforms) { lambda(batch); @@ -329,18 +308,13 @@ void Procedural::prepare(gpu::Batch& batch, } } + void Procedural::setupUniforms(bool transparent) { _uniforms.clear(); - auto& pipeline = transparent ? _transparentShader : _opaqueShader; - const auto& uniformSlots = pipeline->getUniforms(); auto customUniformCount = _data.uniforms.keys().size(); - // Set any userdata specified uniforms for (int i = 0; i < customUniformCount; ++i) { int slot = procedural::slot::uniform::Custom + i; - if (!uniformSlots.isValid(slot)) { - continue; - } QString key = _data.uniforms.keys().at(i); std::string uniformName = key.toLocal8Bit().data(); QJsonValue value = _data.uniforms[key]; @@ -350,113 +324,80 @@ void Procedural::setupUniforms(bool transparent) { } else if (value.isArray()) { auto valueArray = value.toArray(); switch (valueArray.size()) { - case 0: - break; + case 0: + break; - case 1: { - float v = valueArray[0].toDouble(); - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); - break; - } + case 1: { + float v = valueArray[0].toDouble(); + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); + break; + } - case 2: { - glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); - break; - } + case 2: { + glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); + break; + } - case 3: { - glm::vec3 v{ - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); - break; - } + case 3: { + glm::vec3 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + }; + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); + break; + } - default: - case 4: { - glm::vec4 v{ - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - valueArray[3].toDouble(), - }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); - break; - } + default: + case 4: { + glm::vec4 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble(), + }; + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); + break; + } } } } - if (uniformSlots.isValid(procedural::slot::uniform::Time)) { - _uniforms.push_back([=](gpu::Batch& batch) { - // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds - float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; - batch._glUniform(procedural::slot::uniform::Time, time); - }); - } + _uniforms.push_back([=](gpu::Batch& batch) { + _standardInputs.position = vec4(_entityPosition, 1.0f); + // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds + _standardInputs.time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; - if (uniformSlots.isValid(procedural::slot::uniform::Date)) { - _uniforms.push_back([=](gpu::Batch& batch) { + // Date + { QDateTime now = QDateTime::currentDateTimeUtc(); QDate date = now.date(); QTime time = now.time(); - vec4 v; - v.x = date.year(); + _standardInputs.date.x = date.year(); // Shadertoy month is 0 based - v.y = date.month() - 1; + _standardInputs.date.y = date.month() - 1; // But not the day... go figure - v.z = date.day(); + _standardInputs.date.z = date.day(); float fractSeconds = (time.msec() / 1000.0f); - v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; - batch._glUniform(procedural::slot::uniform::Date, v); - }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::FrameCount)) { - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::FrameCount, ++_frameCount); }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::Scale)) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::Scale, _entityDimensions); }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::Orientation)) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back( - [=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::Orientation, _entityOrientation); }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::Position)) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back( - [=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::Orientation, _entityPosition); }); - } -} - -void Procedural::setupChannels(bool shouldCreate, bool transparent) { - auto& pipeline = transparent ? _transparentShader : _opaqueShader; - const auto& uniformSlots = pipeline->getUniforms(); - - if (uniformSlots.isValid(procedural::slot::uniform::ChannelResolution)) { - if (!shouldCreate) { - // Instead of modifying the last element, just remove and recreate it. - _uniforms.pop_back(); + _standardInputs.date.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; } - _uniforms.push_back([=](gpu::Batch& batch) { - vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS]; - for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { - if (_channels[i]) { - channelSizes[i] = vec3(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0); - } + + _standardInputs.scale = vec4(_entityDimensions, 1.0f); + _standardInputs.frameCount = ++_frameCount; + _standardInputs.orientation = mat4(_entityOrientation); + + for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { + if (_channels[i]) { + _standardInputs.resolution[i] = vec4(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0f, 1.0f); + } else { + _standardInputs.resolution[i] = vec4(1.0f); } - batch._glUniform3fv(procedural::slot::uniform::ChannelResolution, MAX_PROCEDURAL_TEXTURE_CHANNELS, - &channelSizes[0].x); - }); - } + } + + _standardInputsBuffer->setSubData(0, _standardInputs); + batch.setUniformBuffer(0, _standardInputsBuffer, 0, sizeof(StandardInputs)); + }); } glm::vec4 Procedural::getColor(const glm::vec4& entityColor) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 973b323f60..781ac25249 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -65,14 +65,37 @@ public: void setDoesFade(bool doesFade) { _doesFade = doesFade; } gpu::Shader::Source _vertexSource; - gpu::Shader::Source _opaquefragmentSource; - gpu::Shader::Source _transparentfragmentSource; + gpu::Shader::Source _opaqueFragmentSource; + gpu::Shader::Source _transparentFragmentSource; gpu::StatePointer _opaqueState { std::make_shared() }; gpu::StatePointer _transparentState { std::make_shared() }; protected: + // DO NOT TOUCH + // We have to pack these in a particular way to match the ProceduralCommon.slh + // layout. + struct StandardInputs { + vec4 date; + vec4 position; + vec4 scale; + float time; + int frameCount; + vec2 _spare1; + vec4 resolution[4]; + mat4 orientation; + }; + + static_assert(0 == offsetof(StandardInputs, date), "ProceduralOffsets"); + static_assert(16 == offsetof(StandardInputs, position), "ProceduralOffsets"); + static_assert(32 == offsetof(StandardInputs, scale), "ProceduralOffsets"); + static_assert(48 == offsetof(StandardInputs, time), "ProceduralOffsets"); + static_assert(52 == offsetof(StandardInputs, frameCount), "ProceduralOffsets"); + static_assert(56 == offsetof(StandardInputs, _spare1), "ProceduralOffsets"); + static_assert(64 == offsetof(StandardInputs, resolution), "ProceduralOffsets"); + static_assert(128 == offsetof(StandardInputs, orientation), "ProceduralOffsets"); + // Procedural metadata ProceduralData _data; @@ -88,13 +111,14 @@ protected: bool _dirty { false }; bool _shaderDirty { true }; bool _uniformsDirty { true }; - bool _channelsDirty { true }; // Rendering objects UniformLambdas _uniforms; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; gpu::PipelinePointer _opaquePipeline; gpu::PipelinePointer _transparentPipeline; + StandardInputs _standardInputs; + gpu::BufferPointer _standardInputsBuffer; gpu::ShaderPointer _vertexShader; gpu::ShaderPointer _opaqueFragmentShader; gpu::ShaderPointer _transparentFragmentShader; @@ -109,9 +133,6 @@ protected: private: // This should only be called from the render thread, as it shares data with Procedural::prepare void setupUniforms(bool transparent); - void setupChannels(bool shouldCreate, bool transparent); - - std::string replaceProceduralBlock(const std::string& fragmentSource); mutable quint64 _fadeStartTime { 0 }; mutable bool _hasStartedFade { false }; diff --git a/libraries/procedural/src/procedural/ProceduralCommon.slh b/libraries/procedural/src/procedural/ProceduralCommon.slh index c36f2da1d3..64a4fdd1f9 100644 --- a/libraries/procedural/src/procedural/ProceduralCommon.slh +++ b/libraries/procedural/src/procedural/ProceduralCommon.slh @@ -14,18 +14,48 @@ <$declareStandardCameraTransform()$> -#define PROCEDURAL 1 +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL0) uniform sampler2D iChannel0; +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3; -//PROCEDURAL_VERSION +// DO NOT TOUCH +// This block does not follow our normal rules of always using a struct and +// always using 16 byte aligned types like vec4 and mat4 +// +// This is because this block must be EXACTLY how it is in order to maintain +// comptability with existing procedural shaders that previously relied on these +// inputs as uniforms, not members of a UBO -#ifdef PROCEDURAL_V1 +LAYOUT_STD140(binding=0) uniform standardInputsBuffer { + // Offset 0 + vec4 date; + // Offset 16, acts as vec4 for alignment purposes + vec3 worldPosition; + // Offset 32, acts as vec4 for alignment purposes + vec3 worldScale; + // Offset 48 + float globalTime; + // Offset 52 + int frameCount; + // Offset 56 + vec2 _spare1; + // Offset 64, acts as vec4[4] for alignment purposes + vec3 channelResolution[4]; + // Offset 128, acts as vec4[3] for alignment purposes + // Also, each individual component is aligned as a vec4 + mat3 worldOrientation; + // Offset 176 + vec4 _spare2; +} standardInputs; -// shader playback time (in seconds) -layout(location=PROCEDURAL_UNIFORM_TIME) uniform float iGlobalTime; -// the dimensions of the object being rendered -layout(location=PROCEDURAL_UNIFORM_SCALE) uniform vec3 iWorldScale; - -#else +#define iDate standardInputs.date +#define iWorldPosition standardInputs.worldPosition +#define iWorldScale standardInputs.worldScale +#define iGlobalTime standardInputs.globalTime +#define iFrameCount standardInputs.frameCount +#define iChannelResolution standardInputs.channelResolution +#define iWorldOrientation standardInputs.worldOrientation // Unimplemented uniforms // Resolution doesn't make sense in the VR context @@ -37,20 +67,9 @@ const float iSampleRate = 1.0; // No support for video input const vec4 iChannelTime = vec4(0.0); +#define PROCEDURAL 1 -layout(location=PROCEDURAL_UNIFORM_TIME) uniform float iGlobalTime; // shader playback time (in seconds) -layout(location=PROCEDURAL_UNIFORM_DATE) uniform vec4 iDate; -layout(location=PROCEDURAL_UNIFORM_FRAME_COUNT) uniform int iFrameCount; -layout(location=PROCEDURAL_UNIFORM_POSITION) uniform vec3 iWorldPosition; // the position of the object being rendered -layout(location=PROCEDURAL_UNIFORM_SCALE) uniform vec3 iWorldScale; // the dimensions of the object being rendered -layout(location=PROCEDURAL_UNIFORM_ORIENTATION) uniform mat3 iWorldOrientation; // the orientation of the object being rendered -layout(location=PROCEDURAL_UNIFORM_CHANNEL_RESOLUTION) uniform vec3 iChannelResolution[4]; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL0) uniform sampler2D iChannel0; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3; - -#endif +//PROCEDURAL_VERSION // hack comment for extra whitespace diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 0addb57fcf..ea5be23eb8 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -19,7 +19,7 @@ ProceduralSkybox::ProceduralSkybox() : graphics::Skybox() { _procedural._vertexSource = gpu::Shader::createVertex(shader::graphics::vertex::skybox)->getSource(); - _procedural._opaquefragmentSource = gpu::Shader::createPixel(shader::procedural::fragment::proceduralSkybox)->getSource(); + _procedural._opaqueFragmentSource = shader::Source::get(shader::procedural::fragment::proceduralSkybox); // Adjust the pipeline state for background using the stencil test _procedural.setDoesFade(false); // Must match PrepareStencil::STENCIL_BACKGROUND diff --git a/libraries/procedural/src/procedural/ShaderConstants.h b/libraries/procedural/src/procedural/ShaderConstants.h index bfbf2a2691..cd0d997050 100644 --- a/libraries/procedural/src/procedural/ShaderConstants.h +++ b/libraries/procedural/src/procedural/ShaderConstants.h @@ -14,14 +14,6 @@ #ifndef PROCEDURAL_SHADER_CONSTANTS_H #define PROCEDURAL_SHADER_CONSTANTS_H -#define PROCEDURAL_UNIFORM_TIME 200 -#define PROCEDURAL_UNIFORM_DATE 201 -#define PROCEDURAL_UNIFORM_FRAME_COUNT 202 -#define PROCEDURAL_UNIFORM_POSITION 203 -#define PROCEDURAL_UNIFORM_SCALE 204 -#define PROCEDURAL_UNIFORM_ORIENTATION 205 -// Additional space because orientation will take up 3-4 locations, being a matrix -#define PROCEDURAL_UNIFORM_CHANNEL_RESOLUTION 209 #define PROCEDURAL_UNIFORM_CUSTOM 220 #define PROCEDURAL_TEXTURE_CHANNEL0 0 @@ -33,15 +25,9 @@ namespace procedural { namespace slot { + namespace uniform { enum Uniform { - Time = PROCEDURAL_UNIFORM_TIME, - Date = PROCEDURAL_UNIFORM_DATE, - FrameCount = PROCEDURAL_UNIFORM_FRAME_COUNT, - Position = PROCEDURAL_UNIFORM_POSITION, - Scale = PROCEDURAL_UNIFORM_SCALE, - Orientation = PROCEDURAL_UNIFORM_ORIENTATION, - ChannelResolution = PROCEDURAL_UNIFORM_CHANNEL_RESOLUTION, Custom = PROCEDURAL_UNIFORM_CUSTOM, }; } diff --git a/libraries/procedural/src/procedural/proceduralSkybox.slf b/libraries/procedural/src/procedural/proceduralSkybox.slf index e18b7abef6..12e8de9dc3 100644 --- a/libraries/procedural/src/procedural/proceduralSkybox.slf +++ b/libraries/procedural/src/procedural/proceduralSkybox.slf @@ -12,13 +12,13 @@ // <@include graphics/ShaderConstants.h@> -layout(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; +LAYOUT(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; struct Skybox { vec4 color; }; -layout(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { Skybox skybox; }; @@ -28,9 +28,13 @@ layout(location=0) out vec4 _fragColor; <@include procedural/ProceduralCommon.slh@> #line 1001 -//PROCEDURAL_BLOCK +//PROCEDURAL_BLOCK_BEGIN +vec3 getSkyboxColor() { + return vec3(abs(sin(iGlobalTime / 5.0)), 1.0, 0.0); +} +//PROCEDURAL_BLOCK_END -#line 2033 +#line 2038 void main(void) { vec3 color = getSkyboxColor(); // Protect from NaNs and negative values diff --git a/libraries/procedural/src/procedural/proceduralSkybox.slp b/libraries/procedural/src/procedural/proceduralSkybox.slp new file mode 100644 index 0000000000..5247547850 --- /dev/null +++ b/libraries/procedural/src/procedural/proceduralSkybox.slp @@ -0,0 +1 @@ +VERTEX graphics::vertex::skybox \ No newline at end of file diff --git a/libraries/render-utils/src/Blendshape.slh b/libraries/render-utils/src/Blendshape.slh index df62af5a77..73a561c73f 100644 --- a/libraries/render-utils/src/Blendshape.slh +++ b/libraries/render-utils/src/Blendshape.slh @@ -10,13 +10,13 @@ <@func declareBlendshape(USE_NORMAL, USE_TANGENT)@> -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer blendshapeOffsetsBuffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer blendshapeOffsetsBuffer; uvec4 getPackedBlendshapeOffset(int i) { return floatBitsToUint(texelFetch(blendshapeOffsetsBuffer, i)); } #else -layout(std140, binding=0) buffer blendshapeOffsetsBuffer { +LAYOUT_STD140(binding=0) buffer blendshapeOffsetsBuffer { uvec4 _packedBlendshapeOffsets[]; }; uvec4 getPackedBlendshapeOffset(int i) { diff --git a/libraries/render-utils/src/BloomApply.slf b/libraries/render-utils/src/BloomApply.slf index a53894de60..dcdb989780 100644 --- a/libraries/render-utils/src/BloomApply.slf +++ b/libraries/render-utils/src/BloomApply.slf @@ -12,11 +12,11 @@ <@include BloomApply.shared.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D blurMap0; -layout(binding=1) uniform sampler2D blurMap1; -layout(binding=2) uniform sampler2D blurMap2; +LAYOUT(binding=0) uniform sampler2D blurMap0; +LAYOUT(binding=1) uniform sampler2D blurMap1; +LAYOUT(binding=2) uniform sampler2D blurMap2; -layout(std140, binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { Parameters parameters; }; diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index 47a1fb0d9f..bbf863994f 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -12,8 +12,8 @@ <@include BloomThreshold.shared.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=RENDER_UTILS_TEXTURE_BLOOM_COLOR) uniform sampler2D colorMap; -layout(std140, binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { +LAYOUT(binding=RENDER_UTILS_TEXTURE_BLOOM_COLOR) uniform sampler2D colorMap; +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { Parameters parameters; }; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index be9e75a9a5..9597ce1052 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -243,7 +243,7 @@ static const std::string DEFAULT_CUSTOM_SHADER{ " }" }; -static std::string getFileContent(std::string fileName, std::string defaultContent = std::string()) { +static std::string getFileContent(const std::string& fileName, const std::string& defaultContent = std::string()) { QFile customFile(QString::fromStdString(fileName)); if (customFile.open(QIODevice::ReadOnly)) { return customFile.readAll().toStdString(); @@ -270,7 +270,7 @@ DebugDeferredBuffer::~DebugDeferredBuffer() { } } -std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string customFile) { +std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, const std::string& customFile) { switch (mode) { case AlbedoMode: return DEFAULT_ALBEDO_SHADER; @@ -334,7 +334,7 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return std::string(); } -bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, std::string customFile) const { +bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, const std::string& customFile) const { if (mode != CustomMode) { return !_pipelines[mode]; } @@ -351,19 +351,17 @@ bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, std::string customFile) return true; } -const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::string customFile) { +const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, const std::string& customFile) { if (pipelineNeedsUpdate(mode, customFile)) { - static const auto FRAGMENT_SHADER_SOURCE = - gpu::Shader::createPixel(shader::render_utils::fragment::debug_deferred_buffer)->getSource(); - static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; - static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER_SOURCE.getCode().find(SOURCE_PLACEHOLDER); - Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, "Could not find source placeholder"); + static_assert(shader::render_utils::program::debug_deferred_buffer != 0, "Validate debug deferred program"); - auto bakedFragmentShader = FRAGMENT_SHADER_SOURCE.getCode(); - bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), getShaderSourceCode(mode, customFile)); + static const std::string REPLACEMENT_MARKER{ "//SOURCE_PLACEHOLDER" }; + shader::Source resolvedFragmentSource; + resolvedFragmentSource = shader::Source::get(shader::render_utils::fragment::debug_deferred_buffer); + resolvedFragmentSource.replacements[REPLACEMENT_MARKER] = getShaderSourceCode(mode, customFile); const auto vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); - const auto ps = gpu::Shader::createPixel({ bakedFragmentShader, FRAGMENT_SHADER_SOURCE.getReflection() }); + const auto ps = gpu::Shader::createPixel(resolvedFragmentSource); const auto program = gpu::Shader::createProgram(vs, ps); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index dba3ff8532..cdaf5db83a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -112,9 +112,9 @@ private: using StandardPipelines = std::array; using CustomPipelines = std::unordered_map; - bool pipelineNeedsUpdate(Mode mode, std::string customFile = std::string()) const; - const gpu::PipelinePointer& getPipeline(Mode mode, std::string customFile = std::string()); - std::string getShaderSourceCode(Mode mode, std::string customFile = std::string()); + bool pipelineNeedsUpdate(Mode mode, const std::string& customFile = std::string()) const; + const gpu::PipelinePointer& getPipeline(Mode mode, const std::string& customFile = std::string()); + std::string getShaderSourceCode(Mode mode, const std::string& customFile = std::string()); ParametersBuffer _parameters; StandardPipelines _pipelines; diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index e5a7c39d54..f3b8c0404a 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -17,23 +17,23 @@ // See DeferredShader_MapSlot in DeferredLightingEffect.cpp for constants // the albedo texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_COLOR) uniform sampler2D albedoMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_COLOR) uniform sampler2D albedoMap; // the normal texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_NORMAL) uniform sampler2D normalMap; // the specular texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_SPECULAR) uniform sampler2D specularMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_SPECULAR) uniform sampler2D specularMap; // the depth texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_DEPTH) uniform sampler2D depthMap; -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_LINEAR_Z_EYE) uniform sampler2D linearZeyeMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_LINEAR_Z_EYE) uniform sampler2D linearZeyeMap; // the obscurance texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_OBSCURANCE) uniform sampler2D obscuranceMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_OBSCURANCE) uniform sampler2D obscuranceMap; // the lighting texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_LIGHTING) uniform sampler2D lightingMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_LIGHTING) uniform sampler2D lightingMap; struct DeferredFragment { @@ -170,14 +170,14 @@ DeferredFragment unpackDeferredFragment(DeferredFrameTransform deferredTransform <@func declareDeferredCurvature()@> // the curvature texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_CURVATURE) uniform sampler2D curvatureMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_CURVATURE) uniform sampler2D curvatureMap; vec4 fetchCurvature(vec2 texcoord) { return texture(curvatureMap, texcoord); } // the curvature texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_DIFFUSED_CURVATURE) uniform sampler2D diffusedCurvatureMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_DIFFUSED_CURVATURE) uniform sampler2D diffusedCurvatureMap; vec4 fetchDiffusedCurvature(vec2 texcoord) { return texture(diffusedCurvatureMap, texcoord); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a10949e0e6..8cf56ec7ad 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -44,7 +44,7 @@ using namespace render; struct LightLocations { bool shadowTransform{ false }; void initialize(const gpu::ShaderPointer& program) { - shadowTransform = program->getUniformBuffers().isValid(ru::Buffer::ShadowParams); + shadowTransform = program->getReflection().validUniformBuffer(ru::Buffer::ShadowParams); } }; diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index 19986805f6..8a8805e928 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -24,7 +24,7 @@ struct CameraCorrection { mat4 _prevViewInverse; }; -layout(binding=GPU_BUFFER_CAMERA_CORRECTION) uniform cameraCorrectionBuffer { +LAYOUT(binding=GPU_BUFFER_CAMERA_CORRECTION) uniform cameraCorrectionBuffer { CameraCorrection cameraCorrection; }; @@ -42,7 +42,7 @@ struct DeferredFrameTransform { mat4 _invProjectionUnJittered[2]; }; -layout(binding=RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM) uniform deferredFrameTransformBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM) uniform deferredFrameTransformBuffer { DeferredFrameTransform frameTransform; }; diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 47347ba135..a7523f969b 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -19,12 +19,12 @@ <@include FadeObjectParams.shared.slh@> // See ShapePipeline::Slot::BUFFER in ShapePipeline.h -layout(std140, binding=RENDER_UTILS_BUFFER_FADE_PARAMS) uniform fadeParametersBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_FADE_PARAMS) uniform fadeParametersBuffer { FadeParameters fadeParameters[CATEGORY_COUNT]; }; // See ShapePipeline::Slot::MAP in ShapePipeline.h -layout(binding=RENDER_UTILS_TEXTURE_FADE_MASK) uniform sampler2D fadeMaskMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_FADE_MASK) uniform sampler2D fadeMaskMap; vec3 getNoiseInverseSize(int category) { return fadeParameters[category]._noiseInvSizeAndLevel.xyz; @@ -117,7 +117,7 @@ void applyFade(FadeObjectParams params, vec3 position, out vec3 emissive) { <@func declareFadeFragmentUniform()@> -layout(std140, binding=RENDER_UTILS_BUFFER_FADE_OBJECT_PARAMS) uniform fadeObjectParametersBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_FADE_OBJECT_PARAMS) uniform fadeObjectParametersBuffer { FadeObjectParams fadeObjectParams; }; diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index bb3c0bc769..8d90b4c816 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -21,7 +21,7 @@ <@include Haze.slh@> -layout(binding=RENDER_UTILS_TEXTURE_HAZE_LINEAR_DEPTH) uniform sampler2D linearDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_HAZE_LINEAR_DEPTH) uniform sampler2D linearDepthMap; vec4 unpackPositionFromZeye(vec2 texcoord) { float Zeye = -texture(linearDepthMap, texcoord).x; diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index b7bcfcefcd..a7654da8d2 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -39,7 +39,7 @@ struct HazeParams { }; // See ShapePipeline::Slot::BUFFER in ShapePipeline.h -layout(std140, binding=RENDER_UTILS_BUFFER_HAZE_PARAMS) uniform hazeBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_HAZE_PARAMS) uniform hazeBuffer { HazeParams hazeParams; }; diff --git a/libraries/render-utils/src/Highlight.slh b/libraries/render-utils/src/Highlight.slh index 885df34d26..264b57acbb 100644 --- a/libraries/render-utils/src/Highlight.slh +++ b/libraries/render-utils/src/Highlight.slh @@ -15,12 +15,12 @@ <@include Highlight_shared.slh@> -layout(std140, binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuffer { HighlightParameters params; }; -layout(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH) uniform sampler2D sceneDepthMap; -layout(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH) uniform sampler2D highlightedDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH) uniform sampler2D sceneDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH) uniform sampler2D highlightedDepthMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 2d4aee7880..0cb08971ff 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -402,36 +402,31 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons } void DebugHighlight::initializePipelines() { - static const auto FRAGMENT_SHADER_SOURCE = gpu::Shader::createPixel(shader::render_utils::fragment::debug_deferred_buffer)->getSource(); - static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; - static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER_SOURCE.getCode().find(SOURCE_PLACEHOLDER); - Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, - "Could not find source placeholder"); - - auto state = std::make_shared(); - state->setDepthTest(gpu::State::DepthTest(false, false)); - state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); - state->setColorWriteMask(true, true, true, true); - - const auto vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); - + static const std::string REPLACEMENT_MARKER{ "//SOURCE_PLACEHOLDER" }; // Depth shader - { - static const std::string DEPTH_SHADER{ R"SHADER( + static const std::string DEPTH_SHADER{ R"SHADER( vec4 getFragmentColor() { float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; Zdb = 1.0-(1.0-Zdb)*100; return vec4(Zdb, Zdb, Zdb, 1.0); } )SHADER" }; + static const auto& vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); - auto fragmentShader = FRAGMENT_SHADER_SOURCE.getCode(); - fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEPTH_SHADER); - const auto ps = gpu::Shader::createPixel({ fragmentShader, FRAGMENT_SHADER_SOURCE.getReflection() }); - const auto program = gpu::Shader::createProgram(vs, ps); - _depthPipeline = gpu::Pipeline::create(program, state); - } + gpu::Shader::Source fragmentSource; + fragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::debug_deferred_buffer); + fragmentSource.replacements[REPLACEMENT_MARKER] = DEPTH_SHADER; + + const auto ps = gpu::Shader::createPixel(fragmentSource); + const auto program = gpu::Shader::createProgram(vs, ps); + + auto state = std::make_shared(); + state->setDepthTest(gpu::State::DepthTest(false, false)); + state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); + state->setColorWriteMask(true, true, true, true); + + _depthPipeline = gpu::Pipeline::create(program, state); } const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() { diff --git a/libraries/render-utils/src/Highlight_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv index 2ecebdea51..17ef7b6e07 100644 --- a/libraries/render-utils/src/Highlight_aabox.slv +++ b/libraries/render-utils/src/Highlight_aabox.slv @@ -22,8 +22,8 @@ struct ItemBound { vec4 boundDim_s; }; -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer ssbo0Buffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer ssbo0Buffer; ItemBound getItemBound(int i) { int offset = 2 * i; ItemBound bound; @@ -32,7 +32,7 @@ ItemBound getItemBound(int i) { return bound; } #else -layout(std140, binding=0) buffer ssbo0Buffer { +LAYOUT_STD140(binding=0) buffer ssbo0Buffer { ItemBound bounds[]; }; ItemBound getItemBound(int i) { @@ -45,7 +45,7 @@ struct HighlightParameters { vec2 outlineWidth; }; -layout(std140, binding=0) uniform parametersBuffer { +LAYOUT_STD140(binding=0) uniform parametersBuffer { HighlightParameters _parameters; }; diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index 797595bf47..4ea9c0cd4c 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -9,7 +9,7 @@ <@include render-utils/ShaderConstants.h@> <@func declareSkyboxMap()@> // declareSkyboxMap -layout(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; vec4 evalSkyboxLight(vec3 direction, float lod) { // textureQueryLevels is not available until #430, so we require explicit lod diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 8f57169ace..62af92e6ce 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -24,7 +24,7 @@ struct FrustumGrid { mat4 eyeToWorldMat; }; -layout(std140, binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_FRUSTUM_GRID) uniform frustumGridBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_FRUSTUM_GRID) uniform frustumGridBuffer { FrustumGrid frustumGrid; }; @@ -60,11 +60,11 @@ float projection_getFar(mat4 projection) { #define GRID_FETCH_BUFFER(i) i!> <@endif@> -layout(std140, binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_GRID) uniform clusterGridBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_GRID) uniform clusterGridBuffer { GRID_INDEX_TYPE _clusterGridTable[GRID_NUM_ELEMENTS]; }; -layout(std140, binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT) uniform clusterContentBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT) uniform clusterContentBuffer { GRID_INDEX_TYPE _clusterGridContent[GRID_NUM_ELEMENTS]; }; diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index d10a52be60..61c74c7e50 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -23,7 +23,7 @@ struct LightingModel { }; // See DeferredShader_BufferSlot in DeferredLightingEffect.cpp -layout(binding=RENDER_UTILS_BUFFER_LIGHT_MODEL) uniform lightingModelBuffer{ +LAYOUT(binding=RENDER_UTILS_BUFFER_LIGHT_MODEL) uniform lightingModelBuffer{ LightingModel lightingModel; }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 5551bbdfa8..a3f06c8942 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -229,7 +229,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip } void initForwardPipelines(ShapePlumber& plumber) { - using namespace shader::render_utils::program; + using namespace shader::render_utils; using Key = render::ShapeKey; auto addPipelineBind = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, _4); @@ -244,33 +244,33 @@ void initForwardPipelines(ShapePlumber& plumber) { forceLightBatchSetter = true; // Simple Opaques - addPipeline(Key::Builder(), simple); - addPipeline(Key::Builder().withUnlit(), simpleUnlit); + addPipeline(Key::Builder(), program::forward_simple_textured); + addPipeline(Key::Builder().withUnlit(), program::forward_simple_textured_unlit); // Simple Translucents - addPipeline(Key::Builder().withTranslucent(), simpleTranslucent); - addPipeline(Key::Builder().withTranslucent().withUnlit(), simpleTranslucentUnlit); + addPipeline(Key::Builder().withTranslucent(), program::forward_simple_textured_transparent); + addPipeline(Key::Builder().withTranslucent().withUnlit(), program::simple_transparent_textured_unlit); // Opaques - addPipeline(Key::Builder().withMaterial(), forward_model); - addPipeline(Key::Builder().withMaterial().withUnlit(), forward_model_unlit); - addPipeline(Key::Builder().withMaterial().withTangents(), forward_model_translucent); + addPipeline(Key::Builder().withMaterial(), program::forward_model); + addPipeline(Key::Builder().withMaterial().withUnlit(), program::forward_model_unlit); + addPipeline(Key::Builder().withMaterial().withTangents(), program::forward_model_translucent); // Deformed Opaques - addPipeline(Key::Builder().withMaterial().withDeformed(), forward_deformed_model); - addPipeline(Key::Builder().withMaterial().withDeformed().withTangents(), forward_deformed_model_normal_map); - addPipeline(Key::Builder().withMaterial().withDeformed().withDualQuatSkinned(), forward_deformed_model_dq); - addPipeline(Key::Builder().withMaterial().withDeformed().withTangents().withDualQuatSkinned(), forward_deformed_model_normal_map_dq); + addPipeline(Key::Builder().withMaterial().withDeformed(), program::forward_deformed_model); + addPipeline(Key::Builder().withMaterial().withDeformed().withTangents(), program::forward_deformed_model_normal_map); + addPipeline(Key::Builder().withMaterial().withDeformed().withDualQuatSkinned(), program::forward_deformed_model_dq); + addPipeline(Key::Builder().withMaterial().withDeformed().withTangents().withDualQuatSkinned(), program::forward_deformed_model_normal_map_dq); // Translucents - addPipeline(Key::Builder().withMaterial().withTranslucent(), forward_model_translucent); - addPipeline(Key::Builder().withMaterial().withTranslucent().withTangents(), forward_model_normal_map_translucent); + addPipeline(Key::Builder().withMaterial().withTranslucent(), program::forward_model_translucent); + addPipeline(Key::Builder().withMaterial().withTranslucent().withTangents(), program::forward_model_normal_map_translucent); // Deformed Translucents - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent(), forward_deformed_translucent); - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents(), forward_deformed_translucent_normal_map); - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withDualQuatSkinned(), forward_deformed_translucent_dq); - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents().withDualQuatSkinned(), forward_deformed_translucent_normal_map_dq); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent(), program::forward_deformed_translucent); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents(), program::forward_deformed_translucent_normal_map); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withDualQuatSkinned(), program::forward_deformed_translucent_dq); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents().withDualQuatSkinned(), program::forward_deformed_translucent_normal_map_dq); forceLightBatchSetter = false; } diff --git a/libraries/render-utils/src/ShadingModel.slh b/libraries/render-utils/src/ShadingModel.slh index 6b0b7bca18..99aa01cc5e 100644 --- a/libraries/render-utils/src/ShadingModel.slh +++ b/libraries/render-utils/src/ShadingModel.slh @@ -15,7 +15,7 @@ <@func declareBeckmannSpecular()@> -layout(binding=RENDER_UTILS_TEXTURE_SSSC_SPECULAR_BECKMANN) uniform sampler2D scatteringSpecularBeckmann; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_SPECULAR_BECKMANN) uniform sampler2D scatteringSpecularBeckmann; float fetchSpecularBeckmann(float ndoth, float roughness) { return pow(2.0 * texture(scatteringSpecularBeckmann, vec2(ndoth, roughness)).r, 10.0); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 5115a876fe..9506c9805d 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -19,7 +19,7 @@ #define SHADOW_SCREEN_SPACE_DITHER 1 // the shadow texture -layout(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; // Sample the shadowMap with PCF (built-in) float fetchShadow(int cascadeIndex, vec3 shadowTexcoord) { diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh index 99c4b923f4..9819dac38c 100644 --- a/libraries/render-utils/src/ShadowCore.slh +++ b/libraries/render-utils/src/ShadowCore.slh @@ -13,7 +13,7 @@ <@include Shadows_shared.slh@> -layout(std140, binding=RENDER_UTILS_BUFFER_SHADOW_PARAMS) uniform shadowTransformBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_SHADOW_PARAMS) uniform shadowTransformBuffer { ShadowParameters shadow; }; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 622ca946c2..63246e85a1 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -18,7 +18,7 @@ const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; -layout(std140, binding=GRAPHICS_BUFFER_SKINNING) uniform skinClusterBuffer { +LAYOUT_STD140(binding=GRAPHICS_BUFFER_SKINNING) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 84b51d626a..e004e66501 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -421,6 +421,10 @@ void DebugSubsurfaceScattering::configure(const Config& config) { _showSpecularTable = config.showSpecularTable; _showCursorPixel = config.showCursorPixel; _debugCursorTexcoord = config.debugCursorTexcoord; + if (!_debugParams) { + _debugParams = std::make_shared(sizeof(glm::vec4), nullptr); + } + _debugParams->setSubData(0, _debugCursorTexcoord); } @@ -479,6 +483,10 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo assert(lightStage); // const auto light = DependencyManager::get()->getLightStage()->getLight(0); const auto light = lightStage->getLight(0); + if (!_debugParams) { + _debugParams = std::make_shared(sizeof(glm::vec4), nullptr); + _debugParams->setSubData(0, _debugCursorTexcoord); + } gpu::doInBatch("DebugSubsurfaceScattering::run", args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); @@ -521,9 +529,7 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo batch.setResourceTexture(ru::Texture::DeferredNormal, deferredFramebuffer->getDeferredNormalTexture()); batch.setResourceTexture(ru::Texture::DeferredColor, deferredFramebuffer->getDeferredColorTexture()); batch.setResourceTexture(ru::Texture::DeferredDepth, linearDepthTexture); - - - batch._glUniform2f(gpu::slot::uniform::Extra0, _debugCursorTexcoord.x, _debugCursorTexcoord.y); + batch.setUniformBuffer(1, _debugParams); batch.draw(gpu::TRIANGLE_STRIP, 4); } } diff --git a/libraries/render-utils/src/SubsurfaceScattering.h b/libraries/render-utils/src/SubsurfaceScattering.h index 780ce34d7f..e0073d23e8 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.h +++ b/libraries/render-utils/src/SubsurfaceScattering.h @@ -179,6 +179,7 @@ private: gpu::PipelinePointer _showLUTPipeline; gpu::PipelinePointer getShowLUTPipeline(); + gpu::BufferPointer _debugParams; bool _showProfile{ false }; bool _showLUT{ false }; bool _showSpecularTable{ false }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.slh b/libraries/render-utils/src/SubsurfaceScattering.slh index 3d37f52e4d..66b3ab1ea0 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.slh +++ b/libraries/render-utils/src/SubsurfaceScattering.slh @@ -56,7 +56,7 @@ vec3 generateProfile(vec2 uv) { <@func declareSubsurfaceScatteringProfileMap()@> -layout(binding=RENDER_UTILS_TEXTURE_SSSC_PROFILE) uniform sampler2D scatteringProfile; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_PROFILE) uniform sampler2D scatteringProfile; vec3 scatter(float r) { return texture(scatteringProfile, vec2(r * 0.5, 0.5)).rgb; @@ -104,7 +104,7 @@ vec3 integrate(float cosTheta, float skinRadius) { <@func declareSubsurfaceScatteringResource()@> -layout(binding=RENDER_UTILS_TEXTURE_SSSC_LUT) uniform sampler2D scatteringLUT; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_LUT) uniform sampler2D scatteringLUT; vec3 fetchBRDF(float LdotN, float curvature) { return texture(scatteringLUT, vec2( clamp(LdotN * 0.5 + 0.5, 0.0, 1.0), clamp(2.0 * curvature, 0.0, 1.0))).xyz; @@ -124,7 +124,7 @@ struct ScatteringParameters { vec4 debugFlags; }; -layout(binding=RENDER_UTILS_BUFFER_SSSC_PARAMS) uniform subsurfaceScatteringParametersBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_SSSC_PARAMS) uniform subsurfaceScatteringParametersBuffer { ScatteringParameters parameters; }; diff --git a/libraries/render-utils/src/WorkloadResource.slh b/libraries/render-utils/src/WorkloadResource.slh index 81b6ed78ce..ed23abd5ae 100644 --- a/libraries/render-utils/src/WorkloadResource.slh +++ b/libraries/render-utils/src/WorkloadResource.slh @@ -25,8 +25,8 @@ struct WorkloadProxy { vec4 region; }; -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer workloadProxiesBuffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer workloadProxiesBuffer; WorkloadProxy getWorkloadProxy(int i) { int offset = 2 * i; WorkloadProxy proxy; @@ -35,7 +35,7 @@ WorkloadProxy getWorkloadProxy(int i) { return proxy; } #else -layout(std140, binding=0) buffer workloadProxiesBuffer { +LAYOUT_STD140(binding=0) buffer workloadProxiesBuffer { WorkloadProxy _proxies[]; }; WorkloadProxy getWorkloadProxy(int i) { @@ -57,17 +57,23 @@ struct WorkloadView { vec4 regions[3]; }; -#if defined(GPU_GL410) -layout(binding=1) uniform samplerBuffer workloadViewsBuffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=1) uniform samplerBuffer workloadViewsBuffer; WorkloadView getWorkloadView(int i) { - int offset = 2 * i; + int offset = 8 * i; WorkloadView view; - view.origin = texelFetch(workloadViewsBuffer, offset); - view.radiuses = texelFetch(workloadViewsBuffer, offset + 1); + view.direction_far = texelFetch(workloadViewsBuffer, offset + 0); + view.fov = texelFetch(workloadViewsBuffer, offset + 1); + view.origin = texelFetch(workloadViewsBuffer, offset + 2); + view.backFront[0] = texelFetch(workloadViewsBuffer, offset + 3); + view.backFront[1] = texelFetch(workloadViewsBuffer, offset + 4); + view.regions[0] = texelFetch(workloadViewsBuffer, offset + 5); + view.regions[1] = texelFetch(workloadViewsBuffer, offset + 6); + view.regions[2] = texelFetch(workloadViewsBuffer, offset + 7); return view; } #else -layout(std140, binding=1) buffer workloadViewsBuffer { +LAYOUT_STD140(binding=1) buffer workloadViewsBuffer { WorkloadView _views[]; }; WorkloadView getWorkloadView(int i) { diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 013640d910..c6e3c49e54 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -16,8 +16,8 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> -layout(binding=RENDER_UTILS_DEBUG_TEXTURE0) uniform sampler2D debugTexture0; -layout(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; +LAYOUT(binding=RENDER_UTILS_DEBUG_TEXTURE0) uniform sampler2D debugTexture0; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; <@include ShadowCore.slh@> @@ -36,7 +36,13 @@ float curvatureAO(float k) { layout(location=0) in vec2 uv; layout(location=0) out vec4 outFragColor; -//SOURCE_PLACEHOLDER +//SOURCE_PLACEHOLDER_BEGIN +vec4 getFragmentColor() { + DeferredFragment frag = unpackDeferredFragmentNoPosition(uv); + return vec4(pow(frag.albedo, vec3(1.0 / 2.2)), 1.0); +} +//SOURCE_PLACEHOLDER_END + void main(void) { outFragColor = getFragmentColor(); diff --git a/libraries/render-utils/src/deferred_light_point.slv b/libraries/render-utils/src/deferred_light_point.slv index 1f4c66b6e5..3e6329be83 100644 --- a/libraries/render-utils/src/deferred_light_point.slv +++ b/libraries/render-utils/src/deferred_light_point.slv @@ -22,7 +22,7 @@ <$declareLightBuffer(256)$> -layout(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { int lightIndex[256]; }; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index c86551936b..0370acc6bc 100644 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -21,7 +21,7 @@ <$declareLightBuffer(256)$> -layout(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { int lightIndex[256]; }; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord0; diff --git a/libraries/render-utils/src/drawWorkloadView.slv b/libraries/render-utils/src/drawWorkloadView.slv index db4a33c450..2fdf3d773e 100644 --- a/libraries/render-utils/src/drawWorkloadView.slv +++ b/libraries/render-utils/src/drawWorkloadView.slv @@ -32,7 +32,7 @@ struct DrawMesh { vec4 verts[NUM_SEGMENT_PER_VIEW_REGION]; }; -layout(std140, binding=0) uniform DrawMeshBuffer { +LAYOUT_STD140(binding=0) uniform DrawMeshBuffer { DrawMesh _drawMeshBuffer; }; diff --git a/libraries/render-utils/src/forward_simple.slf b/libraries/render-utils/src/forward_simple.slf index ca3a13c024..9c86f9dff1 100644 --- a/libraries/render-utils/src/forward_simple.slf +++ b/libraries/render-utils/src/forward_simple.slf @@ -14,8 +14,10 @@ <@include DefaultMaterials.slh@> <@include ForwardGlobalLight.slh@> -<$declareEvalSkyboxGlobalColor()$> +<@include gpu/Transform.slh@> +<$declareEvalSkyboxGlobalColor()$> +<$declareStandardCameraTransform()$> // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; @@ -35,12 +37,6 @@ layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; layout(location=0) out vec4 _fragColor0; -<@include procedural/ProceduralCommon.slh@> - -#line 1001 -//PROCEDURAL_BLOCK - -#line 2030 void main(void) { vec3 normal = normalize(_normalWS.xyz); vec3 diffuse = _color.rgb; @@ -48,45 +44,18 @@ void main(void) { float shininess = DEFAULT_SHININESS; float emissiveAmount = 0.0; -#ifdef PROCEDURAL - -#ifdef PROCEDURAL_V1 - diffuse = getProceduralColor().rgb; - // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline - //diffuse = pow(diffuse, vec3(2.2)); - emissiveAmount = 1.0; -#else - emissiveAmount = getProceduralColors(diffuse, specular, shininess); -#endif - -#endif - TransformCamera cam = getTransformCamera(); vec3 fragPosition = _positionES.xyz; - if (emissiveAmount > 0.0) { - _fragColor0 = vec4(evalSkyboxGlobalColor( - cam._viewInverse, - 1.0, - DEFAULT_OCCLUSION, - fragPosition, - normal, - diffuse, - specular, - DEFAULT_METALLIC, - max(0.0, 1.0 - shininess / 128.0)), - 1.0); - } else { - _fragColor0 = vec4(evalSkyboxGlobalColor( - cam._viewInverse, - 1.0, - DEFAULT_OCCLUSION, - fragPosition, - normal, - diffuse, - DEFAULT_FRESNEL, - length(specular), - max(0.0, 1.0 - shininess / 128.0)), - 1.0); - } + _fragColor0 = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + DEFAULT_OCCLUSION, + fragPosition, + normal, + diffuse, + DEFAULT_FRESNEL, + length(specular), + max(0.0, 1.0 - shininess / 128.0)), + 1.0); } diff --git a/libraries/render-utils/src/forward_simple_textured.slf b/libraries/render-utils/src/forward_simple_textured.slf index 8570ae6183..ca31550b40 100644 --- a/libraries/render-utils/src/forward_simple_textured.slf +++ b/libraries/render-utils/src/forward_simple_textured.slf @@ -22,7 +22,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/forward_simple_textured_transparent.slf b/libraries/render-utils/src/forward_simple_textured_transparent.slf index 11c44c18a2..11d51bbd78 100644 --- a/libraries/render-utils/src/forward_simple_textured_transparent.slf +++ b/libraries/render-utils/src/forward_simple_textured_transparent.slf @@ -22,7 +22,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/forward_simple_textured_unlit.slf b/libraries/render-utils/src/forward_simple_textured_unlit.slf index 8ca46da499..ddbc5ae4d7 100644 --- a/libraries/render-utils/src/forward_simple_textured_unlit.slf +++ b/libraries/render-utils/src/forward_simple_textured_unlit.slf @@ -20,7 +20,7 @@ layout(location=0) out vec4 _fragColor0; // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; diff --git a/libraries/render-utils/src/fxaa.slf b/libraries/render-utils/src/fxaa.slf index f1096a3054..1539a87550 100644 --- a/libraries/render-utils/src/fxaa.slf +++ b/libraries/render-utils/src/fxaa.slf @@ -22,7 +22,7 @@ precision mediump float; precision mediump int; #endif -layout(binding=0) uniform sampler2D colorTexture; +LAYOUT(binding=0) uniform sampler2D colorTexture; //uniform sampler2D historyTexture; // FIXME make into a uniform buffer or push constant if this shader ever comes into use diff --git a/libraries/render-utils/src/fxaa_blend.slf b/libraries/render-utils/src/fxaa_blend.slf index c051801659..c22982bc3f 100644 --- a/libraries/render-utils/src/fxaa_blend.slf +++ b/libraries/render-utils/src/fxaa_blend.slf @@ -17,13 +17,13 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; -layout(binding=0) uniform sampler2D colorTexture; +LAYOUT(binding=0) uniform sampler2D colorTexture; struct FxaaBlendParams { vec4 sharpenIntensity; }; -layout(binding=0) uniform fxaaBlendParamsBuffer { +LAYOUT(binding=0) uniform fxaaBlendParamsBuffer { FxaaBlendParams params; }; diff --git a/libraries/render-utils/src/glowLine.slv b/libraries/render-utils/src/glowLine.slv index 075b291589..167aeb8c9e 100644 --- a/libraries/render-utils/src/glowLine.slv +++ b/libraries/render-utils/src/glowLine.slv @@ -21,7 +21,7 @@ struct LineData { float width; }; -layout(std140, binding=0) uniform LineDataBuffer { +LAYOUT_STD140(binding=0) uniform LineDataBuffer { LineData _lineData; }; diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf index c2380c980d..8e9b35dace 100644 --- a/libraries/render-utils/src/grid.slf +++ b/libraries/render-utils/src/grid.slf @@ -20,7 +20,7 @@ struct Grid { vec4 edge; }; -layout(binding=0) uniform gridBuffer { +LAYOUT(binding=0) uniform gridBuffer { Grid grid; }; diff --git a/libraries/render-utils/src/hmd_ui.slf b/libraries/render-utils/src/hmd_ui.slf index eebeb2e060..6895a90f9e 100644 --- a/libraries/render-utils/src/hmd_ui.slf +++ b/libraries/render-utils/src/hmd_ui.slf @@ -13,13 +13,13 @@ // <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D hudTexture; +LAYOUT(binding=0) uniform sampler2D hudTexture; struct HUDData { float alpha; }; -layout(std140, binding=0) uniform hudBuffer { +LAYOUT_STD140(binding=0) uniform hudBuffer { HUDData hud; }; diff --git a/libraries/render-utils/src/hmd_ui.slv b/libraries/render-utils/src/hmd_ui.slv index ab0d77c42a..6e782d1672 100644 --- a/libraries/render-utils/src/hmd_ui.slv +++ b/libraries/render-utils/src/hmd_ui.slv @@ -22,7 +22,7 @@ struct HUDData { float alpha; }; -layout(std140, binding=0) uniform hudBuffer { +LAYOUT_STD140(binding=0) uniform hudBuffer { HUDData hud; }; diff --git a/libraries/render-utils/src/parabola.slv b/libraries/render-utils/src/parabola.slv index 31b3ab8fae..53dfc75cfe 100644 --- a/libraries/render-utils/src/parabola.slv +++ b/libraries/render-utils/src/parabola.slv @@ -22,7 +22,7 @@ struct ParabolaData { ivec3 spare; }; -layout(std140, binding=0) uniform parabolaData { +LAYOUT_STD140(binding=0) uniform parabolaData { ParabolaData _parabolaData; }; diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index ccf6314a39..2d777d502f 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -131,15 +131,6 @@ namespace render_utils { namespace slot { -namespace uniform { -enum Uniform { - TextColor = RENDER_UTILS_UNIFORM_TEXT_COLOR, - TextOutline = RENDER_UTILS_UNIFORM_TEXT_OUTLINE, - TaaSharpenIntensity = GPU_UNIFORM_EXTRA0, - HighlightOutlineWidth = GPU_UNIFORM_EXTRA0, -}; -} - namespace buffer { enum Buffer { DeferredFrameTransform = RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM, diff --git a/libraries/render-utils/src/render-utils/debug_deferred_buffer.slp b/libraries/render-utils/src/render-utils/debug_deferred_buffer.slp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libraries/render-utils/src/render-utils/simple.slp b/libraries/render-utils/src/render-utils/simple.slp index 8a6e2e4f99..e69de29bb2 100644 --- a/libraries/render-utils/src/render-utils/simple.slp +++ b/libraries/render-utils/src/render-utils/simple.slp @@ -1 +0,0 @@ -FRAGMENT forward_simple_textured diff --git a/libraries/render-utils/src/render-utils/simpleTranslucent.slp b/libraries/render-utils/src/render-utils/simpleTranslucent.slp deleted file mode 100644 index 0163b09b84..0000000000 --- a/libraries/render-utils/src/render-utils/simpleTranslucent.slp +++ /dev/null @@ -1,2 +0,0 @@ -VERTEX simple -FRAGMENT forward_simple_textured_transparent diff --git a/libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp b/libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp deleted file mode 100644 index f1d1ec39be..0000000000 --- a/libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp +++ /dev/null @@ -1,2 +0,0 @@ -VERTEX simple -FRAGMENT simple_transparent_textured_unlit diff --git a/libraries/render-utils/src/render-utils/simpleUnlit.slp b/libraries/render-utils/src/render-utils/simpleUnlit.slp deleted file mode 100644 index ab491aa290..0000000000 --- a/libraries/render-utils/src/render-utils/simpleUnlit.slp +++ /dev/null @@ -1,2 +0,0 @@ -VERTEX simple -FRAGMENT forward_simple_textured_unlit diff --git a/libraries/render-utils/src/render-utils/simple_transparent.slp b/libraries/render-utils/src/render-utils/simple_transparent.slp new file mode 100644 index 0000000000..10e6b388c4 --- /dev/null +++ b/libraries/render-utils/src/render-utils/simple_transparent.slp @@ -0,0 +1 @@ +VERTEX simple diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index d35396e469..35e670eef8 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -13,14 +13,14 @@ <@include DeferredBufferWrite.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D Font; +LAYOUT(binding=0) uniform sampler2D Font; struct TextParams { vec4 color; vec4 outline; }; -layout(binding=0) uniform textParamsBuffer { +LAYOUT(binding=0) uniform textParamsBuffer { TextParams params; }; diff --git a/libraries/render-utils/src/sdf_text3D_transparent.slf b/libraries/render-utils/src/sdf_text3D_transparent.slf index 9dffca2038..6e271e1463 100644 --- a/libraries/render-utils/src/sdf_text3D_transparent.slf +++ b/libraries/render-utils/src/sdf_text3D_transparent.slf @@ -13,14 +13,14 @@ <@include DeferredBufferWrite.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D Font; +LAYOUT(binding=0) uniform sampler2D Font; struct TextParams { vec4 color; vec4 outline; }; -layout(binding=0) uniform textParamsBuffer { +LAYOUT(binding=0) uniform textParamsBuffer { TextParams params; }; diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index a7f5151880..039dbc4278 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -35,7 +35,17 @@ layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; <@include procedural/ProceduralCommon.slh@> #line 1001 -//PROCEDURAL_BLOCK +//PROCEDURAL_BLOCK_BEGIN + +vec3 getProceduralColor() { + return _color.rgb; +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return 1.0; +} + +//PROCEDURAL_BLOCK_END #line 2030 void main(void) { diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf deleted file mode 100644 index 97ed0c570c..0000000000 --- a/libraries/render-utils/src/simple_fade.slf +++ /dev/null @@ -1,110 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple_fade.frag -// fragment shader -// -// Created by Olivier Prat on 06/05/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include DeferredBufferWrite.slh@> - -<@include Fade.slh@> -<$declareFadeFragmentInstanced()$> - -<@include render-utils/ShaderConstants.h@> - -// the interpolated normal -layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; -layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normalMS; -layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; -layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; -#define _texCoord0 _texCoord01.xy -#define _texCoord1 _texCoord01.zw -layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _positionMS; -layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; -layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _positionWS; - -// For retro-compatibility -#define _normal _normalWS -#define _modelNormal _normalMS -#define _position _positionMS -#define _eyePosition _positionES - -<@include procedural/ProceduralCommon.slh@> - -#line 1001 -//PROCEDURAL_BLOCK - -#line 2030 -void main(void) { - vec3 fadeEmissive; - FadeObjectParams fadeParams; - - <$fetchFadeObjectParamsInstanced(fadeParams)$> - applyFade(fadeParams, _positionWS.xyz, fadeEmissive); - - vec3 normal = normalize(_normalWS.xyz); - vec3 diffuse = _color.rgb; - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; - float emissiveAmount = 0.0; - -#ifdef PROCEDURAL - -#ifdef PROCEDURAL_V1 - specular = getProceduralColor().rgb; - // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline - //specular = pow(specular, vec3(2.2)); - emissiveAmount = 1.0; -#else - emissiveAmount = getProceduralColors(diffuse, specular, shininess); -#endif - -#endif - - const float ALPHA_THRESHOLD = 0.999; - if (_color.a < ALPHA_THRESHOLD) { - if (emissiveAmount > 0.0) { - packDeferredFragmentTranslucent( - normal, - _color.a, - specular+fadeEmissive, - DEFAULT_FRESNEL, - DEFAULT_ROUGHNESS); - } else { - packDeferredFragmentTranslucent( - normal, - _color.a, - diffuse+fadeEmissive, - DEFAULT_FRESNEL, - DEFAULT_ROUGHNESS); - } - } else { - if (emissiveAmount > 0.0) { - packDeferredFragmentLightmap( - normal, - 1.0, - diffuse+fadeEmissive, - max(0.0, 1.0 - shininess / 128.0), - DEFAULT_METALLIC, - specular, - specular); - } else { - packDeferredFragment( - normal, - 1.0, - diffuse, - max(0.0, 1.0 - shininess / 128.0), - length(specular), - DEFAULT_EMISSIVE+fadeEmissive, - DEFAULT_OCCLUSION, - DEFAULT_SCATTERING); - } - } -} diff --git a/libraries/render-utils/src/simple_opaque_web_browser.slf b/libraries/render-utils/src/simple_opaque_web_browser.slf index cf4828d3b3..36b0c825ad 100644 --- a/libraries/render-utils/src/simple_opaque_web_browser.slf +++ b/libraries/render-utils/src/simple_opaque_web_browser.slf @@ -18,7 +18,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index 7676844084..b308b57345 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured_fade.slf b/libraries/render-utils/src/simple_textured_fade.slf index 600f19be0f..ad2b636708 100644 --- a/libraries/render-utils/src/simple_textured_fade.slf +++ b/libraries/render-utils/src/simple_textured_fade.slf @@ -20,7 +20,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured_unlit.slf b/libraries/render-utils/src/simple_textured_unlit.slf index e3d9b9daf6..f33cb704dc 100644 --- a/libraries/render-utils/src/simple_textured_unlit.slf +++ b/libraries/render-utils/src/simple_textured_unlit.slf @@ -18,7 +18,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf index bffadbe819..494920b363 100644 --- a/libraries/render-utils/src/simple_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf @@ -20,7 +20,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index 5db54aa770..0e29ed7470 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -39,7 +39,18 @@ layout(location=0) out vec4 _fragColor0; <@include procedural/ProceduralCommon.slh@> #line 1001 -//PROCEDURAL_BLOCK + +//PROCEDURAL_BLOCK_BEGIN + +vec3 getProceduralColor() { + return _color.rgb; +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return 1.0; +} + +//PROCEDURAL_BLOCK_END #line 2030 void main(void) { diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf index 5573a7aa22..ef83914096 100644 --- a/libraries/render-utils/src/simple_transparent_textured.slf +++ b/libraries/render-utils/src/simple_transparent_textured.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf index 44a3fe2e01..5fac67e1d2 100644 --- a/libraries/render-utils/src/simple_transparent_textured_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -26,7 +26,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit.slf b/libraries/render-utils/src/simple_transparent_textured_unlit.slf index 9d43e41c2f..bf3dbbdf88 100644 --- a/libraries/render-utils/src/simple_transparent_textured_unlit.slf +++ b/libraries/render-utils/src/simple_transparent_textured_unlit.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf index 43c28c41c3..943f361ead 100644 --- a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf @@ -19,7 +19,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; diff --git a/libraries/render-utils/src/simple_transparent_web_browser.slf b/libraries/render-utils/src/simple_transparent_web_browser.slf index df92d238bf..2adc16e278 100644 --- a/libraries/render-utils/src/simple_transparent_web_browser.slf +++ b/libraries/render-utils/src/simple_transparent_web_browser.slf @@ -18,7 +18,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b149d8f912..f0d522a41c 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -44,7 +44,7 @@ struct AmbientOcclusionParams { float _gaussianCoefs[8]; }; -layout(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; @@ -232,7 +232,7 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, // the depth pyramid texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_PYRAMID) uniform sampler2D pyramidMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_PYRAMID) uniform sampler2D pyramidMap; float getZEye(ivec2 pixel, int level) { return -texelFetch(pyramidMap, pixel, level).x; @@ -313,7 +313,7 @@ float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { <$declareAmbientOcclusion()$> // the source occlusion texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) { raw = texelFetch(occlusionMap, coords, 0).xyz; diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index ab7989e35e..e15e52f448 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -26,7 +26,7 @@ struct DebugParams{ vec4 pixelInfo; }; -layout(binding=RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS) uniform debugAmbientOcclusionBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS) uniform debugAmbientOcclusionBuffer { DebugParams debugParams; }; diff --git a/libraries/render-utils/src/ssao_makePyramid.slf b/libraries/render-utils/src/ssao_makePyramid.slf index c87fe1e682..eae1b853f9 100644 --- a/libraries/render-utils/src/ssao_makePyramid.slf +++ b/libraries/render-utils/src/ssao_makePyramid.slf @@ -14,7 +14,7 @@ <@include ssao.slh@> <$declareAmbientOcclusion()$> -layout(binding=0) uniform sampler2D depthMap; +LAYOUT(binding=0) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/standardDrawTexture.slf b/libraries/render-utils/src/standardDrawTexture.slf index 1a8af0f71c..620c811f75 100644 --- a/libraries/render-utils/src/standardDrawTexture.slf +++ b/libraries/render-utils/src/standardDrawTexture.slf @@ -14,7 +14,7 @@ <@include gpu/ShaderConstants.h@> // the texture -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=GPU_ATTR_POSITION) in vec3 varPosition; layout(location=GPU_ATTR_NORMAL) in vec3 varNormal; diff --git a/libraries/render-utils/src/standardDrawTextureNoBlend.slf b/libraries/render-utils/src/standardDrawTextureNoBlend.slf index 95138d123f..83915cd856 100644 --- a/libraries/render-utils/src/standardDrawTextureNoBlend.slf +++ b/libraries/render-utils/src/standardDrawTextureNoBlend.slf @@ -14,7 +14,7 @@ <@include gpu/ShaderConstants.h@> // the texture -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=GPU_ATTR_POSITION) in vec3 varPosition; layout(location=GPU_ATTR_NORMAL) in vec3 varNormal; diff --git a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf index 8664fa16fd..877c31c23d 100644 --- a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf +++ b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf @@ -26,10 +26,14 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 _fragColor; -// FIXME make into a uniform buffer or push constant if this shader ever comes into use -vec2 uniformCursorTexcoord = vec2(0.5); +struct SSSDebugParams { + vec4 cursorTexCoordSpare2; +}; -//uniform vec3 uniformLightVector = vec3(1.0); +// Deferred frame transform uses slot 0 +LAYOUT_STD140(binding=1) uniform sssDebugParamsBuffer { + SSSDebugParams sssDebugParams; +}; vec3 evalScatteringBRDF(vec2 texcoord) { DeferredFragment fragment = unpackDeferredFragmentNoPosition(texcoord); @@ -76,8 +80,6 @@ vec3 drawScatteringTableUV(vec2 cursor, vec2 texcoord) { vec3 bentNdotL = evalScatteringBentNdotL(normal, midNormal, lowNormal, fragLightDir); - // return clamp(bentNdotL * 0.5 + 0.5, 0.0, 1.0); - vec3 distance = vec3(0.0); for (int c = 0; c < 3; c++) { vec2 BRDFuv = vec2(clamp(bentNdotL[c] * 0.5 + 0.5, 0.0, 1.0), clamp(2.0 * curvature, 0.0, 1.0)); @@ -104,10 +106,8 @@ vec3 drawScatteringTableUV(vec2 cursor, vec2 texcoord) { } void main(void) { - // _fragColor = vec4(evalScatteringBRDF(varTexCoord0), 1.0); - // _fragColor = vec4(uniformCursorTexcoord, 0.0, 1.0); - - _fragColor = vec4(drawScatteringTableUV(uniformCursorTexcoord, varTexCoord0), 1.0); + vec2 cursorTexcoord = sssDebugParams.cursorTexCoordSpare2.xy; + _fragColor = vec4(drawScatteringTableUV(cursorTexcoord, varTexCoord0), 1.0); } diff --git a/libraries/render-utils/src/surfaceGeometry_copyDepth.slf b/libraries/render-utils/src/surfaceGeometry_copyDepth.slf index f018ee1105..efff6e913c 100644 --- a/libraries/render-utils/src/surfaceGeometry_copyDepth.slf +++ b/libraries/render-utils/src/surfaceGeometry_copyDepth.slf @@ -11,7 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(binding=0) uniform sampler2D depthMap; +LAYOUT(binding=0) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf b/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf index 34e78ea4ff..e4020dbdec 100644 --- a/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf +++ b/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf @@ -15,8 +15,8 @@ <@include gpu/PackedNormal.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; -layout(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; layout(location=0) in vec2 varTexCoord0; diff --git a/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf b/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf index b49bd618da..363fd0d4f8 100644 --- a/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf +++ b/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf @@ -25,7 +25,7 @@ struct SurfaceGeometryParams { vec4 curvatureInfo; }; -layout(binding= RENDER_UTILS_BUFFER_SG_PARAMS) uniform surfaceGeometryParamsBuffer { +LAYOUT(binding= RENDER_UTILS_BUFFER_SG_PARAMS) uniform surfaceGeometryParamsBuffer { SurfaceGeometryParams params; }; @@ -46,7 +46,7 @@ bool isFullResolution() { } -layout(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; float getZEye(ivec2 pixel) { return -texelFetch(linearDepthMap, pixel, 0).x; @@ -59,7 +59,7 @@ vec2 sideToFrameTexcoord(vec2 side, vec2 texcoordPos) { return vec2((texcoordPos.x + side.x) * side.y, texcoordPos.y); } -layout(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; vec3 getRawNormal(vec2 texcoord) { return texture(normalMap, texcoord).xyz; diff --git a/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf b/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf index 116f3b7686..fe0c320d1b 100644 --- a/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf +++ b/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf @@ -16,7 +16,7 @@ <@include DeferredTransform.slh@> <$declareDeferredFrameTransform()$> -layout(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/taa.slh b/libraries/render-utils/src/taa.slh index 2161ad9524..784c0824d5 100644 --- a/libraries/render-utils/src/taa.slh +++ b/libraries/render-utils/src/taa.slh @@ -16,11 +16,11 @@ <@include render-utils/ShaderConstants.h@> <@include gpu/Color.slh@> -layout(binding=RENDER_UTILS_TEXTURE_TAA_HISTORY) uniform sampler2D historyMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_SOURCE) uniform sampler2D sourceMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_VELOCITY) uniform sampler2D velocityMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_NEXT) uniform sampler2D nextMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_HISTORY) uniform sampler2D historyMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_SOURCE) uniform sampler2D sourceMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_VELOCITY) uniform sampler2D velocityMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_NEXT) uniform sampler2D nextMap; struct TAAParams { @@ -33,7 +33,7 @@ struct TAAParams vec4 regionInfo; }; -layout(std140, binding=RENDER_UTILS_BUFFER_TAA_PARAMS) uniform taaParamsBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_TAA_PARAMS) uniform taaParamsBuffer { TAAParams params; }; diff --git a/libraries/render-utils/src/toneMapping.slf b/libraries/render-utils/src/toneMapping.slf index 8d89e54a1b..29f618c2f0 100644 --- a/libraries/render-utils/src/toneMapping.slf +++ b/libraries/render-utils/src/toneMapping.slf @@ -26,7 +26,7 @@ const int ToneCurveGamma22 = 1; const int ToneCurveReinhard = 2; const int ToneCurveFilmic = 3; -layout(binding=RENDER_UTILS_BUFFER_TM_PARAMS) uniform toneMappingParamsBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_TM_PARAMS) uniform toneMappingParamsBuffer { ToneMappingParams params; }; float getTwoPowExposure() { @@ -36,7 +36,7 @@ int getToneCurve() { return params._toneCurve_s0_s1_s2.x; } -layout(binding=RENDER_UTILS_TEXTURE_TM_COLOR) uniform sampler2D colorMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TM_COLOR) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/velocityBuffer_cameraMotion.slf b/libraries/render-utils/src/velocityBuffer_cameraMotion.slf index 083440dbf8..0ec63a7b1d 100644 --- a/libraries/render-utils/src/velocityBuffer_cameraMotion.slf +++ b/libraries/render-utils/src/velocityBuffer_cameraMotion.slf @@ -17,7 +17,7 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; -layout(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; void main(void) { diff --git a/libraries/render-utils/src/zone_drawSkybox.slf b/libraries/render-utils/src/zone_drawSkybox.slf index 77de75a305..f8d1326b3a 100644 --- a/libraries/render-utils/src/zone_drawSkybox.slf +++ b/libraries/render-utils/src/zone_drawSkybox.slf @@ -12,13 +12,13 @@ <@include render-utils/ShaderConstants.h@> // FIXME use declareSkyboxMap from LightAmbient.slh? -layout(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; struct Skybox { vec4 color; }; -layout(binding=RENDER_UTILS_BUFFER_DEBUG_SKYBOX) uniform skyboxBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_DEBUG_SKYBOX) uniform skyboxBuffer { Skybox skybox; }; diff --git a/libraries/render/src/render/BlurTask.slh b/libraries/render/src/render/BlurTask.slh index c07e71688a..db6b8e3bab 100644 --- a/libraries/render/src/render/BlurTask.slh +++ b/libraries/render/src/render/BlurTask.slh @@ -21,7 +21,7 @@ struct BlurParameters { vec2 taps[BLUR_MAX_NUM_TAPS]; }; -layout(binding=0) uniform blurParamsBuffer { +LAYOUT(binding=0) uniform blurParamsBuffer { BlurParameters parameters; }; @@ -76,7 +76,7 @@ float getPosLinearDepthFar() { <$declareBlurUniforms()$> -layout(binding=0) uniform sampler2D sourceMap; +LAYOUT(binding=0) uniform sampler2D sourceMap; vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { texcoord = evalTexcoordTransformed(texcoord); @@ -112,8 +112,8 @@ vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { <$declareBlurUniforms()$> -layout(binding=0) uniform sampler2D sourceMap; -layout(binding=1) uniform sampler2D depthMap; +LAYOUT(binding=0) uniform sampler2D sourceMap; +LAYOUT(binding=1) uniform sampler2D depthMap; vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep) { texcoord = evalTexcoordTransformed(texcoord); diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 2b2accde37..d742428897 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -86,29 +86,30 @@ void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, BatchSetter batchSetter, ItemSetter itemSetter) { ShapeKey key{ filter._flags }; + const auto& reflection = program->getReflection(); auto locations = std::make_shared(); - locations->albedoTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialAlbedo); - locations->roughnessTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialRoughness); - locations->normalTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialNormal); - locations->metallicTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialMetallic); - locations->emissiveTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialEmissiveLightmap); - locations->occlusionTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialOcclusion); - locations->lightingModelBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightModel); - locations->skinClusterBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::Skinning); - locations->materialBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::Material); - locations->texMapArrayBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::TexMapArray); - locations->keyLightBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::KeyLight); - locations->lightBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::Light); - locations->lightAmbientBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::AmbientLight); - locations->lightAmbientMapUnit = program->getTextures().isValid(graphics::slot::texture::Skybox); - locations->fadeMaskTextureUnit = program->getTextures().isValid(render_utils::slot::texture::FadeMask); - locations->fadeParameterBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::FadeParameters); - locations->fadeObjectParameterBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::FadeObjectParameters); - locations->hazeParameterBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::HazeParams); + locations->albedoTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialAlbedo); + locations->roughnessTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialRoughness); + locations->normalTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialNormal); + locations->metallicTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialMetallic); + locations->emissiveTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialEmissiveLightmap); + locations->occlusionTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialOcclusion); + locations->lightingModelBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightModel); + locations->skinClusterBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::Skinning); + locations->materialBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::Material); + locations->texMapArrayBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::TexMapArray); + locations->keyLightBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::KeyLight); + locations->lightBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::Light); + locations->lightAmbientBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::AmbientLight); + locations->lightAmbientMapUnit = reflection.validTexture(graphics::slot::texture::Skybox); + locations->fadeMaskTextureUnit = reflection.validTexture(render_utils::slot::texture::FadeMask); + locations->fadeParameterBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::FadeParameters); + locations->fadeObjectParameterBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::FadeObjectParameters); + locations->hazeParameterBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::HazeParams); if (key.isTranslucent()) { - locations->lightClusterGridBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightClusterGrid); - locations->lightClusterContentBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightClusterContent); - locations->lightClusterFrustumBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightClusterFrustumGrid); + locations->lightClusterGridBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightClusterGrid); + locations->lightClusterContentBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightClusterContent); + locations->lightClusterFrustumBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightClusterFrustumGrid); } { diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index bd6ac6521a..24c17d43f1 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -258,7 +258,7 @@ public: using ItemSetter = std::function; - ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr) : + ShapePipeline(const gpu::PipelinePointer& pipeline, const LocationsPointer& locations, const BatchSetter& batchSetter = nullptr, const ItemSetter& itemSetter = nullptr) : pipeline(pipeline), locations(locations), _batchSetter(batchSetter), diff --git a/libraries/render/src/render/drawItemBounds.slv b/libraries/render/src/render/drawItemBounds.slv index ea4d0f24e6..0a9615c9c2 100644 --- a/libraries/render/src/render/drawItemBounds.slv +++ b/libraries/render/src/render/drawItemBounds.slv @@ -24,7 +24,7 @@ struct DrawItemBoundsParams { vec4 color; }; -layout(binding=0) uniform drawItemBoundsParamsBuffer { +LAYOUT(binding=0) uniform drawItemBoundsParamsBuffer { DrawItemBoundsParams params; }; @@ -34,8 +34,8 @@ struct ItemBound { vec4 boundDim_s; }; -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer ssbo0Buffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer ssbo0Buffer; ItemBound getItemBound(int i) { int offset = 2 * i; ItemBound bound; @@ -44,7 +44,7 @@ ItemBound getItemBound(int i) { return bound; } #else -layout(std140, binding=0) buffer ssbo0Buffer { +LAYOUT_STD140(binding=0) buffer ssbo0Buffer { ItemBound bounds[]; }; ItemBound getItemBound(int i) { diff --git a/libraries/render/src/render/drawItemStatus.slf b/libraries/render/src/render/drawItemStatus.slf index 9409ee6171..e88cf4c920 100644 --- a/libraries/render/src/render/drawItemStatus.slf +++ b/libraries/render/src/render/drawItemStatus.slf @@ -15,7 +15,7 @@ layout(location=0) in vec4 varColor; layout(location=1) in vec3 varTexcoord; layout(location=0) out vec4 outFragColor; -layout(binding=0) uniform sampler2D _icons; +LAYOUT(binding=0) uniform sampler2D _icons; vec2 getIconTexcoord(float icon, vec2 uv) { const vec2 ICON_COORD_SIZE = vec2(0.0625, 1.0); return vec2((uv.x + icon) * ICON_COORD_SIZE.x, uv.y * ICON_COORD_SIZE.y); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 31436bbf8b..588377c072 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -17,6 +17,6 @@ if (NOT ANDROID) endif () -link_hifi_libraries(shared networking octree gpu procedural graphics model-networking ktx recording avatars fbx entities controllers animation audio physics image midi) +link_hifi_libraries(shared networking octree shaders gpu procedural graphics model-networking ktx recording avatars fbx entities controllers animation audio physics image midi) # ui includes gl, but link_hifi_libraries does not use transitive includes, so gl must be explicit include_hifi_library_headers(gl) diff --git a/libraries/shaders/CMakeLists.txt b/libraries/shaders/CMakeLists.txt index a065c635e7..1d9c4d59a4 100644 --- a/libraries/shaders/CMakeLists.txt +++ b/libraries/shaders/CMakeLists.txt @@ -1,16 +1,7 @@ set(TARGET_NAME shaders) autoscribe_shader_libs(gpu graphics display-plugins procedural render render-utils entities-renderer) setup_hifi_library(Gui) - -add_dependencies(${TARGET_NAME} compiled_shaders reflected_shaders) - -# Despite the dependency above, the autogen logic will attempt to compile the QRC before -# the compiled_shaders project is built causing an error on a clean workspace because the -# QRC references files generated by the compiled_shaders target -# To fix that we need to explicitly add every shader as a dependnecy of the autogen process -foreach(COMPILED_SHADER ${COMPILED_SHADERS}) - set_property(TARGET ${TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "${COMPILED_SHADER}") -endforeach() +add_dependencies(${TARGET_NAME} scribed_shaders spirv_shaders reflected_shaders) link_hifi_libraries(shared gl) - +target_json() diff --git a/libraries/shaders/ShaderEnums.cpp.in b/libraries/shaders/ShaderEnums.cpp.in index 7f4751f116..042362288d 100644 --- a/libraries/shaders/ShaderEnums.cpp.in +++ b/libraries/shaders/ShaderEnums.cpp.in @@ -1,11 +1,19 @@ #include "ShaderEnums.h" +#include namespace shader { - -uint32_t all_programs[] = { +const std::vector& allPrograms() { + static const std::vector ALL_PROGRAMS{{ @SHADER_PROGRAMS_ARRAY@ - (uint32_t)-1 -}; - + }}; + return ALL_PROGRAMS; } +const std::vector& allShaders() { + static const std::vector ALL_SHADERS{{ +@SHADER_SHADERS_ARRAY@ + }}; + return ALL_SHADERS; +} + +} \ No newline at end of file diff --git a/libraries/shaders/headers/310es/header.glsl b/libraries/shaders/headers/310es/header.glsl new file mode 100644 index 0000000000..ac48d5c94c --- /dev/null +++ b/libraries/shaders/headers/310es/header.glsl @@ -0,0 +1,15 @@ +#version 310 es +#define GPU_GLES +#define GPU_GLES_310 +#define BITFIELD highp int +#define LAYOUT(X) layout(X) +#define LAYOUT_STD140(X) layout(std140, X) +#ifdef VULKAN + #define gl_InstanceID gl_InstanceIndex + #define gl_VertexID gl_VertexIndex +#endif +#extension GL_EXT_texture_buffer : enable +precision highp float; +precision highp samplerBuffer; +precision highp sampler2DShadow; +precision highp sampler2DArrayShadow; diff --git a/libraries/shaders/headers/410/header.glsl b/libraries/shaders/headers/410/header.glsl new file mode 100644 index 0000000000..901ae6f9db --- /dev/null +++ b/libraries/shaders/headers/410/header.glsl @@ -0,0 +1,15 @@ +#version 410 core +#define GPU_GL410 +#define BITFIELD int +#if defined(VULKAN) + #extension GL_ARB_shading_language_420pack : require + #define LAYOUT(X) layout(X) + #define LAYOUT_STD140(X) layout(std140, X) +#else + #define LAYOUT(X) + #define LAYOUT_STD140(X) layout(std140) +#endif +#ifdef VULKAN +#define gl_InstanceID gl_InstanceIndex +#define gl_VertexID gl_VertexIndex +#endif diff --git a/libraries/shaders/headers/450/header.glsl b/libraries/shaders/headers/450/header.glsl new file mode 100644 index 0000000000..6ce61b4378 --- /dev/null +++ b/libraries/shaders/headers/450/header.glsl @@ -0,0 +1,10 @@ +#version 450 core +#define GPU_GL450 +#define GPU_SSBO_TRANSFORM_OBJECT +#define BITFIELD int +#define LAYOUT(X) layout(X) +#define LAYOUT_STD140(X) layout(std140, X) +#ifdef VULKAN +#define gl_InstanceID gl_InstanceIndex +#define gl_VertexID gl_VertexIndex +#endif diff --git a/libraries/shaders/headers/mono.glsl b/libraries/shaders/headers/mono.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libraries/shaders/headers/stereo.glsl b/libraries/shaders/headers/stereo.glsl new file mode 100644 index 0000000000..090035b4a4 --- /dev/null +++ b/libraries/shaders/headers/stereo.glsl @@ -0,0 +1,4 @@ +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN diff --git a/libraries/shaders/src/shaders/Shaders.cpp b/libraries/shaders/src/shaders/Shaders.cpp index ac4810a896..549bf65f80 100644 --- a/libraries/shaders/src/shaders/Shaders.cpp +++ b/libraries/shaders/src/shaders/Shaders.cpp @@ -8,101 +8,362 @@ #include "Shaders.h" -#include #include #include #include #include -#include -#include -#include -#include +#include +#include +#include + +#include #include -static bool cleanShaders() { -#if defined(Q_OS_MAC) - static const bool CLEAN_SHADERS = true; -#else - static const bool CLEAN_SHADERS = ::gl::disableGl45(); - -#endif - return CLEAN_SHADERS; -} - // Can't use the Q_INIT_RESOURCE macro inside a namespace on Mac, // so this is done out of line -void initShaders() { - static std::once_flag once; - std::call_once(once, [] { - Q_INIT_RESOURCE(shaders); - }); -} -static std::vector splitStringIntoLines(const std::string& s) { - std::stringstream ss(s); - std::vector result; - - std::string line; - while (std::getline(ss, line, '\n')) { - result.push_back(line); - } - return result; -} - -static std::string loadResource(const std::string& path) { - return FileUtils::readFile(path.c_str()).toStdString(); +static void initShadersResources() { + Q_INIT_RESOURCE(shaders); } namespace shader { -void cleanShaderSource(std::string& shaderSource) { - static const std::regex LAYOUT_REGEX{ R"REGEX(^layout\((\s*std140\s*,\s*)?(?:binding|location)\s*=\s*(?:\b\w+\b)\)\s*(?!(?:flat\s+)?(?:out|in|buffer))\b(.*)$)REGEX" }; - static const int GROUP_STD140 = 1; - static const int THE_REST_OF_THE_OWL = 2; - std::vector lines = splitStringIntoLines(shaderSource); - std::vector outLines; - std::unordered_map locationDefines; - for (const auto& line : lines) { - std::cmatch m; - if (std::regex_match(line.c_str(), m, LAYOUT_REGEX)) { - std::string outLine; - if (m[GROUP_STD140].matched) { - outLine = "layout(std140) "; - } - outLine += m[THE_REST_OF_THE_OWL].str(); - outLines.push_back(outLine); - continue; - // On mac we have to strip out all the explicit binding location layouts, - // because GL 4.1 doesn't support them - } - outLines.push_back(line); - } - std::ostringstream joined; - std::copy(outLines.begin(), outLines.end(), std::ostream_iterator(joined, "\n")); - shaderSource = joined.str(); +#if defined(USE_GLES) + +static const Dialect DEFAULT_DIALECT = Dialect::glsl310es; + +const std::vector& allDialects() { + static const std::vector ALL_DIALECTS{ { Dialect::glsl310es } }; + return ALL_DIALECTS; } -std::string loadShaderSource(uint32_t shaderId) { - initShaders(); - auto shaderStr = loadResource(std::string(":/shaders/") + std::to_string(shaderId)); - if (cleanShaders()) { - // OSX only supports OpenGL 4.1 without ARB_shading_language_420pack or - // ARB_explicit_uniform_location or basically anything useful that's - // been released in the last 8 fucking years, so in that case we need to - // strip out all explicit locations and do a bunch of background magic to - // make the system seem like it is using the explicit locations - cleanShaderSource(shaderStr); - } - return shaderStr; -} - -std::string loadShaderReflection(uint32_t shaderId) { - initShaders(); - auto path = std::string(":/shaders/") + std::to_string(shaderId) + std::string("_reflection"); - auto json = loadResource(path); - return json; +#elif defined(Q_OS_MAC) + +static const Dialect DEFAULT_DIALECT = Dialect::glsl410; + +const std::vector& allDialects() { + static const std::vector ALL_DIALECTS{ Dialect::glsl410 }; + return ALL_DIALECTS; } +#else + +static const Dialect DEFAULT_DIALECT = Dialect::glsl450; + +const std::vector & allDialects() { + static const std::vector ALL_DIALECTS{ { Dialect::glsl450, Dialect::glsl410 } }; + return ALL_DIALECTS; } +#endif + +const std::vector& allVariants() { + static const std::vector ALL_VARIANTS{ { Variant::Mono, Variant::Stereo } }; + return ALL_VARIANTS; +} + +const std::string& dialectPath(Dialect dialect) { + static const std::string e310esPath { "/310es/" }; + static const std::string e410Path { "/410/" }; + static const std::string e450Path { "/450/" }; + switch (dialect) { +#if defined(USE_GLES) + case Dialect::glsl310es: return e310esPath; +#else +#if !defined(Q_OS_MAC) + case Dialect::glsl450: return e450Path; +#endif + case Dialect::glsl410: return e410Path; +#endif + default: break; + } + throw std::runtime_error("Invalid dialect"); +} + +static std::string loadResource(const std::string& path) { + if (!QFileInfo(path.c_str()).exists()) { + return {}; + } + return FileUtils::readFile(path.c_str()).toStdString(); +} + +static Binary loadSpirvResource(const std::string& path) { + Binary result; + { + QFile file(path.c_str()); + + if (file.open(QFile::ReadOnly)) { + QByteArray bytes = file.readAll(); + result.resize(bytes.size()); + memcpy(bytes.data(), result.data(), bytes.size()); + } + } + return result; +} + +DialectVariantSource loadDialectVariantSource(const std::string& basePath) { + DialectVariantSource result; + result.scribe = loadResource(basePath + "scribe"); + result.spirv = loadSpirvResource(basePath + "spirv"); + result.glsl = loadResource(basePath + "glsl"); + String reflectionJson = loadResource(basePath + "json"); + result.reflection.parse(reflectionJson); + return result; +} + +DialectSource loadDialectSource(Dialect dialect, uint32_t shaderId) { + std::string basePath = std::string(":/shaders/") + std::to_string(shaderId) + dialectPath(dialect); + DialectSource result; + result.variantSources[Variant::Mono] = loadDialectVariantSource(basePath); + auto stereo = loadDialectVariantSource(basePath + "stereo/"); + if (stereo.valid()) { + result.variantSources[Variant::Stereo] = stereo; + } + return result; +} + +Source::Pointer Source::loadSource(uint32_t shaderId) { + auto result = std::make_shared(); + result->id = shaderId; + const auto& dialects = allDialects(); + result->name = loadResource(std::string(":/shaders/") + std::to_string(shaderId) + std::string("/name")); + for (const auto& dialect : dialects) { + result->dialectSources[dialect] = loadDialectSource(dialect, shaderId); + } + result->reflection = result->dialectSources[DEFAULT_DIALECT].variantSources[Variant::Mono].reflection; + return result; +} + +Source& Source::operator=(const Source& other) { + // DO NOT COPY the shader ID + name = other.name; + dialectSources = other.dialectSources; + replacements = other.replacements; + reflection = other.reflection; + return *this; +} + +const Source& Source::get(uint32_t shaderId) { + static std::once_flag once; + static const std::unordered_map shadersById; + std::call_once(once, [] { + initShadersResources(); + auto& map = const_cast&>(shadersById); + for (const auto& shaderId : allShaders()) { + map[shaderId] = loadSource(shaderId); + } + }); + const auto itr = shadersById.find(shaderId); + static const Source EMPTY_SHADER; + if (itr == shadersById.end()) { + return EMPTY_SHADER; + } + return *(itr->second); +} + +bool Source::doReplacement(String& source) const { + bool replaced = false; + for (const auto& entry : replacements) { + const auto& key = entry.first; + // First try search for a block to replace + // Blocks are required because oftentimes we need a stub function + // in the original source code to allow it to compile. As such we + // need to replace the stub with our own code rather than just inject + // some code. + const auto beginMarker = key + "_BEGIN"; + auto beginIndex = source.find(beginMarker); + if (beginIndex != std::string::npos) { + const auto endMarker = key + "_END"; + auto endIndex = source.find(endMarker, beginIndex); + if (endIndex != std::string::npos) { + auto size = endIndex - beginIndex; + source.replace(beginIndex, size, entry.second); + replaced = true; + continue; + } + } + + // If no block is found, try for a simple line replacement + beginIndex = source.find(key); + if (beginIndex != std::string::npos) { + source.replace(beginIndex, key.size(), entry.second); + replaced = true; + continue; + } + } + + return replaced; +} + +const DialectVariantSource& Source::getDialectVariantSource(Dialect dialect, Variant variant) const { + auto dialectEntry = dialectSources.find(dialect); + if (dialectEntry == dialectSources.end()) { + throw std::runtime_error("Dialect source not found"); + } + + const auto& dialectSource = dialectEntry->second; + auto variantEntry = dialectSource.variantSources.find(variant); + // FIXME revert to mono if stereo source is requested but not present + // (for when mono and stereo sources are the same) + if (variantEntry == dialectSource.variantSources.end()) { + throw std::runtime_error("Variant source not found"); + } + + return variantEntry->second; +} + + +String Source::getSource(Dialect dialect, Variant variant) const { + String result; + const auto& variantSource = getDialectVariantSource(dialect, variant); + if (!replacements.empty()) { + std::string result = variantSource.scribe; + if (doReplacement(result)) { + return result; + } + } + +#ifdef Q_OS_ANDROID + // SPIRV cross injects "#extension GL_OES_texture_buffer : require" into the GLSL shaders, + // which breaks android rendering + return variantSource.scribe; +#else + if (variantSource.glsl.empty()) { + return variantSource.scribe; + } + return variantSource.glsl; +#endif +} + +const Reflection& Source::getReflection(Dialect dialect, Variant variant) const { + const auto& variantSource = getDialectVariantSource(dialect, variant); + return variantSource.reflection; +} + +static const std::string NAME_KEY{ "name" }; +static const std::string INPUTS_KEY{ "inputs" }; +static const std::string OUTPUTS_KEY{ "outputs" }; +static const std::string UBOS_KEY{ "ubos" }; +static const std::string SSBOS_KEY{ "ssbos" }; + +static const std::string TEXTURES_KEY{ "textures" }; +static const std::string LOCATION_KEY{ "location" }; +static const std::string BINDING_KEY{ "binding" }; +static const std::string TYPE_KEY{ "type" }; + +std::unordered_set populateBufferTextureSet(const nlohmann::json& input) { + std::unordered_set result; + static const std::string SAMPLER_BUFFER{ "samplerBuffer" }; + auto arraySize = input.size(); + for (size_t i = 0; i < arraySize; ++i) { + auto entry = input[i]; + std::string name = entry[NAME_KEY]; + std::string type = entry[TYPE_KEY]; + if (type == SAMPLER_BUFFER) { + result.insert(name); + } + } + return result; +} + +Reflection::LocationMap populateLocationMap(const nlohmann::json& input, const std::string& locationKey) { + Reflection::LocationMap result; + auto arraySize = input.size(); + for (size_t i = 0; i < arraySize; ++i) { + auto entry = input[i]; + std::string name = entry[NAME_KEY]; + // Location or binding, depending on the locationKey parameter + int32_t location = entry[locationKey]; + result[name] = location; + } + return result; +} + +void Reflection::parse(const std::string& jsonString) { + if (jsonString.empty()) { + return; + } + using json = nlohmann::json; + auto root = json::parse(jsonString); + + if (root.count(INPUTS_KEY)) { + inputs = populateLocationMap(root[INPUTS_KEY], LOCATION_KEY); + } + if (root.count(OUTPUTS_KEY)) { + outputs = populateLocationMap(root[OUTPUTS_KEY], LOCATION_KEY); + } + if (root.count(SSBOS_KEY)) { + resourceBuffers = populateLocationMap(root[SSBOS_KEY], BINDING_KEY); + } + if (root.count(UBOS_KEY)) { + uniformBuffers = populateLocationMap(root[UBOS_KEY], BINDING_KEY); + } + if (root.count(TEXTURES_KEY)) { + textures = populateLocationMap(root[TEXTURES_KEY], BINDING_KEY); + auto bufferTextures = populateBufferTextureSet(root[TEXTURES_KEY]); + if (!bufferTextures.empty()) { + if (!resourceBuffers.empty()) { + throw std::runtime_error("Input shader has both SSBOs and texture buffers defined"); + } + for (const auto& bufferTexture : bufferTextures){ + resourceBuffers[bufferTexture] = textures[bufferTexture]; + textures.erase(bufferTexture); + } + } + } + updateValid(); + +} + + +static void mergeMap(Reflection::LocationMap& output, const Reflection::LocationMap& input) { + for (const auto& entry : input) { + if (0 != output.count(entry.first)) { + if (output[entry.first] != entry.second) { + throw std::runtime_error("Invalid reflection for merging"); + } + } else { + output[entry.first] = entry.second; + } + } +} + +static void updateValidSet(Reflection::ValidSet& output, const Reflection::LocationMap& input) { + output.clear(); + output.reserve(input.size()); + for (const auto& entry : input) { + output.insert(entry.second); + } +} + +void Reflection::merge(const Reflection& reflection) { + mergeMap(textures, reflection.textures); + mergeMap(uniforms, reflection.uniforms); + mergeMap(uniformBuffers, reflection.uniformBuffers); + mergeMap(resourceBuffers, reflection.resourceBuffers); + updateValid(); +} + +void Reflection::updateValid() { + updateValidSet(validInputs, inputs); + updateValidSet(validOutputs, outputs); + updateValidSet(validTextures, textures); + updateValidSet(validUniformBuffers, uniformBuffers); + updateValidSet(validResourceBuffers, resourceBuffers); + updateValidSet(validUniforms, uniforms); +} + + +std::vector Reflection::getNames(const LocationMap& locations) { + std::vector result; + result.reserve(locations.size()); + for (const auto& entry : locations) { + result.push_back(entry.first); + } + return result; +} + + +} // namespace shader + diff --git a/libraries/shaders/src/shaders/Shaders.h b/libraries/shaders/src/shaders/Shaders.h index 1335c1b49b..025abf7b0b 100644 --- a/libraries/shaders/src/shaders/Shaders.h +++ b/libraries/shaders/src/shaders/Shaders.h @@ -8,27 +8,169 @@ #pragma once #include +#include #include +#include #include -#include +#include + +#include + +#include namespace shader { static const uint32_t INVALID_SHADER = (uint32_t)-1; static const uint32_t INVALID_PROGRAM = (uint32_t)-1; -extern uint32_t all_programs[]; +const std::vector& allPrograms(); +const std::vector& allShaders(); -std::string loadShaderSource(uint32_t shaderId); -std::string loadShaderReflection(uint32_t shaderId); +enum class Dialect +{ +#if defined(USE_GLES) + // GLES only support 3.1 es + glsl310es, +#elif defined(Q_OS_MAC) + // Mac only supports 4.1 + glsl410, +#else + // Everything else supports 4.1 and 4.5 + glsl450, + glsl410, +#endif +}; + +const std::vector& allDialects(); +const std::string& dialectPath(Dialect dialect); + +enum class Variant { + Mono, + Stereo, +}; + +const std::vector& allVariants(); + +static const uint32_t NUM_VARIANTS = 2; + +using Binary = std::vector; +using String = std::string; + +struct EnumClassHash +{ + template + std::size_t operator()(T t) const + { + return static_cast(t); + } +}; + +struct Reflection { + using LocationMap = std::unordered_map; + using ValidSet = std::unordered_set; + + void parse(const std::string& json); + void merge(const Reflection& reflection); + + bool validInput(int32_t location) const { return validLocation(validInputs, location); } + bool validOutput(int32_t location) const { return validLocation(validOutputs, location); } + bool validTexture(int32_t location) const { return validLocation(validTextures, location); } + bool validUniform(int32_t location) const { return validLocation(validUniforms, location); } + bool validUniformBuffer(int32_t location) const { return validLocation(validUniformBuffers, location); } + bool validResourceBuffer(int32_t location) const { return validLocation(validResourceBuffers, location); } + + + LocationMap inputs; + + LocationMap outputs; + + LocationMap textures; + + LocationMap uniformBuffers; + + // Either SSBOs or Textures with the type samplerBuffer, depending on dialect + LocationMap resourceBuffers; + + // Needed for procedural code, will map to push constants for Vulkan + LocationMap uniforms; + + static std::vector getNames(const LocationMap& locations); + +private: + + bool validLocation(const ValidSet& locations, int32_t location) const { + return locations.count(location) != 0; + } + + void updateValid(); + + ValidSet validInputs; + ValidSet validOutputs; + ValidSet validTextures; + ValidSet validUniformBuffers; + ValidSet validResourceBuffers; + ValidSet validUniforms; +}; + +struct DialectVariantSource { + // The output of the scribe application with platforms specific headers + String scribe; + // Optimized SPIRV version of the shader + Binary spirv; + // Regenerated GLSL from the optimized SPIRV + String glsl; + // Shader reflection from the optimized SPIRV + Reflection reflection; + + bool valid() const { return !scribe.empty(); } +}; + +struct DialectSource { + std::unordered_map variantSources; +}; + +struct Source { + using Pointer = std::shared_ptr; + Source() = default; + Source& operator=(const Source& other); + + uint32_t id{ INVALID_SHADER }; + + // The name of the shader file, with extension, i.e. DrawColor.frag + std::string name; + + // Generic reflection, copied from the 450 dialect / mono variant + Reflection reflection; + + // Map of platforms to their specific shaders + std::unordered_map dialectSources; + + // Support for swapping out code blocks for procedural and debugging shaders + std::unordered_map replacements; + + String getSource(Dialect dialect, Variant variant) const; + const Reflection& getReflection(Dialect dialect, Variant variant) const; + bool valid() const { return !dialectSources.empty(); } + static Source generate(const std::string& glsl) { throw std::runtime_error("Implement me"); } + static const Source& get(uint32_t shaderId); + +private: + // Disallow copy construction and assignment + Source(const Source& other) = default; + + static Source::Pointer loadSource(uint32_t shaderId) ; + + bool doReplacement(String& source) const; + const DialectVariantSource& getDialectVariantSource(Dialect dialect, Variant variant) const; + +}; inline uint32_t getVertexId(uint32_t programId) { return (programId >> 16) & UINT16_MAX; } - + inline uint32_t getFragmentId(uint32_t programId) { return programId & UINT16_MAX; } -} - +} // namespace shader diff --git a/libraries/ui/src/InteractiveWindow.cpp b/libraries/ui/src/InteractiveWindow.cpp index 6c7f2d503f..5f7999f826 100644 --- a/libraries/ui/src/InteractiveWindow.cpp +++ b/libraries/ui/src/InteractiveWindow.cpp @@ -292,8 +292,8 @@ int InteractiveWindow::getPresentationMode() const { return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt(); } -#ifdef Q_OS_WIN void InteractiveWindow::parentNativeWindowToMainWindow() { +#ifdef Q_OS_WIN if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "parentNativeWindowToMainWindow"); return; @@ -307,8 +307,8 @@ void InteractiveWindow::parentNativeWindowToMainWindow() { } const auto nativeWindow = qvariant_cast(nativeWindowProperty); SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId()); -} #endif +} void InteractiveWindow::setPresentationMode(int presentationMode) { if (QThread::currentThread() != thread()) { diff --git a/libraries/ui/src/InteractiveWindow.h b/libraries/ui/src/InteractiveWindow.h index f456b32e8d..a25d559557 100644 --- a/libraries/ui/src/InteractiveWindow.h +++ b/libraries/ui/src/InteractiveWindow.h @@ -84,9 +84,7 @@ private: Q_INVOKABLE void setPresentationMode(int presentationMode); Q_INVOKABLE int getPresentationMode() const; -#ifdef Q_OS_WIN Q_INVOKABLE void parentNativeWindowToMainWindow(); -#endif public slots: diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 893b7f48b1..664f9fe906 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -19,7 +19,7 @@ if (WIN32 AND (NOT USE_GLES)) set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) link_hifi_libraries( - shared task gl gpu ${PLATFORM_GL_BACKEND} controllers ui qml + shared task gl shaders gpu ${PLATFORM_GL_BACKEND} controllers ui qml plugins ui-plugins display-plugins input-plugins audio-client networking render-utils ${PLATFORM_GL_BACKEND} diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt index 00e90fb6d7..33d27c4e9d 100644 --- a/plugins/oculusLegacy/CMakeLists.txt +++ b/plugins/oculusLegacy/CMakeLists.txt @@ -13,7 +13,7 @@ if (APPLE) set(TARGET_NAME oculusLegacy) setup_hifi_plugin() - link_hifi_libraries(shared gl gpu plugins ui ui-plugins display-plugins input-plugins midi ${PLATFORM_GL_BACKEND}) + link_hifi_libraries(shared shaders gl gpu plugins ui ui-plugins display-plugins input-plugins midi ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index ff94152d57..eea08e66d5 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -13,7 +13,7 @@ if (WIN32 AND (NOT USE_GLES)) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui plugins display-plugins ui-plugins input-plugins script-engine - audio-client render-utils graphics gpu render model-networking fbx ktx image procedural ${PLATFORM_GL_BACKEND}) + audio-client render-utils graphics shaders gpu render model-networking fbx ktx image procedural ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) diff --git a/tests-manual/gpu-textures/CMakeLists.txt b/tests-manual/gpu-textures/CMakeLists.txt index 84f5027411..907690748a 100644 --- a/tests-manual/gpu-textures/CMakeLists.txt +++ b/tests-manual/gpu-textures/CMakeLists.txt @@ -4,7 +4,7 @@ setup_hifi_project(Quick Gui Script) setup_memory_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( - shared task networking gl + shared shaders task networking gl ktx gpu octree ${PLATFORM_GL_BACKEND} ) diff --git a/tests-manual/gpu-textures/src/TestTextures.cpp b/tests-manual/gpu-textures/src/TestTextures.cpp index 701e60fab8..5d5ddce6fa 100644 --- a/tests-manual/gpu-textures/src/TestTextures.cpp +++ b/tests-manual/gpu-textures/src/TestTextures.cpp @@ -81,8 +81,10 @@ TexturesTest::TexturesTest() { connect(&stats, &TextureTestStats::prevTexture, this, &TexturesTest::onPrevTexture); connect(&stats, &TextureTestStats::maxTextureMemory, this, &TexturesTest::onMaxTextureMemory); { - auto VS = gpu::Shader::createVertex({ vertexShaderSource, {} }); - auto PS = gpu::Shader::createPixel({ fragmentShaderSource, {} }); + shader::Source vertexSource; + + auto VS = gpu::Shader::createVertex(shader::Source::generate(vertexShaderSource)); + auto PS = gpu::Shader::createPixel(shader::Source::generate(fragmentShaderSource)); auto program = gpu::Shader::createProgram(VS, PS); // If the pipeline did not exist, make it auto state = std::make_shared(); diff --git a/tests-manual/gpu/CMakeLists.txt b/tests-manual/gpu/CMakeLists.txt index 30218f3f97..8fd0316c05 100644 --- a/tests-manual/gpu/CMakeLists.txt +++ b/tests-manual/gpu/CMakeLists.txt @@ -5,7 +5,7 @@ setup_memory_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( shared task networking gl - ktx gpu procedural octree image + ktx shaders gpu procedural octree image graphics model-networking fbx animation script-engine render render-utils ${PLATFORM_GL_BACKEND} diff --git a/tests-manual/render-utils/CMakeLists.txt b/tests-manual/render-utils/CMakeLists.txt index be75c53f2e..9f575ee8ca 100644 --- a/tests-manual/render-utils/CMakeLists.txt +++ b/tests-manual/render-utils/CMakeLists.txt @@ -8,7 +8,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") setup_memory_debugger() # link in the shared libraries -link_hifi_libraries(render-utils gl gpu shared ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(render-utils shaders gl gpu shared ${PLATFORM_GL_BACKEND}) target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) if (WIN32) diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt index 08678c1c26..e238405d62 100644 --- a/tests/shaders/CMakeLists.txt +++ b/tests/shaders/CMakeLists.txt @@ -3,7 +3,9 @@ macro (setup_testcase_dependencies) # link in the shared libraries link_hifi_libraries(shared test-utils gpu shaders gl ${PLATFORM_GL_BACKEND}) + #target_spirv() package_libraries_for_deployment() endmacro () setup_hifi_testcase(Gui) + diff --git a/tests/shaders/src/ShaderTests.cpp b/tests/shaders/src/ShaderTests.cpp index 03dc034cd0..692771f0fc 100644 --- a/tests/shaders/src/ShaderTests.cpp +++ b/tests/shaders/src/ShaderTests.cpp @@ -31,22 +31,24 @@ #include #include +#define RUNTIME_SHADER_COMPILE_TEST 0 + +#if RUNTIME_SHADER_COMPILE_TEST +#include +#include +#include +#include +#endif + QTEST_MAIN(ShaderTests) -#pragma optimize("", off) void ShaderTests::initTestCase() { - _window = new QWindow(); - _window->setSurfaceType(QSurface::SurfaceType::OpenGLSurface); - _context = new ::gl::Context(_window); + _context = new ::gl::OffscreenContext(); getDefaultOpenGLSurfaceFormat(); _context->create(); if (!_context->makeCurrent()) { qFatal("Unable to make test GL context current"); } - QOpenGLContextWrapper(_context->qglContext()).makeCurrent(_window); - if (!_context->makeCurrent()) { - qFatal("Unable to make test GL context current"); - } gl::initModuleGl(); if (!_context->makeCurrent()) { qFatal("Unable to make test GL context current"); @@ -62,6 +64,8 @@ void ShaderTests::cleanupTestCase() { qDebug() << "Done"; } +#if RUNTIME_SHADER_COMPILE_TEST + template QStringList toQStringList(const C& c) { QStringList result; @@ -80,7 +84,7 @@ std::unordered_set toStringSet(const C& c, F f) { return result; } -template +template bool isSubset(const C& parent, const C& child) { for (const auto& v : child) { if (0 == parent.count(v)) { @@ -120,6 +124,7 @@ gpu::Shader::ReflectionMap mergeReflection(const std::initializer_list std::unordered_map invertMap(const std::unordered_map& map) { @@ -127,58 +132,52 @@ std::unordered_map invertMap(const std::unordered_map& map) { for (const auto& entry : map) { result[entry.second] = entry.first; } + if (result.size() != map.size()) { + throw std::runtime_error("Map inversion failure, result size does not match input size"); + } return result; } -static void verifyBindings(const gpu::Shader::Source& source) { - const auto reflection = source.getReflection(); - for (const auto& entry : reflection) { - const auto& map = entry.second; - const auto reverseMap = invertMap(map); - if (map.size() != reverseMap.size()) { - QFAIL("Bindings are not unique"); - } - } - -} - - -static void verifyInterface(const gpu::Shader::Source& vertexSource, const gpu::Shader::Source& fragmentSource) { - if (0 == fragmentSource.getReflection().count(gpu::Shader::BindingType::INPUT)) { +static void verifyInterface(const gpu::Shader::Source& vertexSource, + const gpu::Shader::Source& fragmentSource, + shader::Dialect dialect, + shader::Variant variant) { + const auto& fragmentReflection = fragmentSource.getReflection(dialect, variant); + if (fragmentReflection.inputs.empty()) { return; } - auto fragIn = fragmentSource.getReflection().at(gpu::Shader::BindingType::INPUT); - if (0 == vertexSource.getReflection().count(gpu::Shader::BindingType::OUTPUT)) { - qDebug() << "No vertex output for fragment input"; - //QFAIL("No vertex output for fragment input"); - return; + + const auto& vertexReflection = vertexSource.getReflection(dialect, variant); + const auto& fragIn = fragmentReflection.inputs; + if (vertexReflection.outputs.empty()) { + throw std::runtime_error("No vertex outputs for fragment inputs"); } - auto vout = vertexSource.getReflection().at(gpu::Shader::BindingType::OUTPUT); + + const auto& vout = vertexReflection.outputs; auto vrev = invertMap(vout); - static const std::string IN_STEREO_SIDE_STRING = "_inStereoSide"; for (const auto entry : fragIn) { const auto& name = entry.first; - // The presence of "_inStereoSide" in fragment shaders is a bug due to the way we do reflection - // and use preprocessor macros in the shaders - if (name == IN_STEREO_SIDE_STRING) { - continue; - } if (0 == vout.count(name)) { - qDebug() << "Vertex output missing"; - //QFAIL("Vertex output missing"); - continue; + throw std::runtime_error("Vertex outputs missing"); } const auto& inLocation = entry.second; const auto& outLocation = vout.at(name); if (inLocation != outLocation) { - qDebug() << "Mismatch in vertex / fragment interface"; - //QFAIL("Mismatch in vertex / fragment interface"); - continue; + throw std::runtime_error("Mismatch in vertex / fragment interface"); } } } -template +static void verifyInterface(const gpu::Shader::Source& vertexSource, const gpu::Shader::Source& fragmentSource) { + for (const auto& dialect : shader::allDialects()) { + for (const auto& variant : shader::allVariants()) { + verifyInterface(vertexSource, fragmentSource, dialect, variant); + } + } +} + +#if RUNTIME_SHADER_COMPILE_TEST +template bool compareBindings(const C& actual, const gpu::Shader::LocationMap& expected) { if (actual.size() != expected.size()) { auto actualNames = toStringSet(actual, [](const auto& v) { return v.name; }); @@ -192,48 +191,341 @@ bool compareBindings(const C& actual, const gpu::Shader::LocationMap& expected) return true; } -void ShaderTests::testShaderLoad() { - std::set usedShaders; - uint32_t maxShader = 0; - try { +void configureGLSLCompilerResources(TBuiltInResource* glslCompilerResources) { + glslCompilerResources->maxLights = 32; + glslCompilerResources->maxClipPlanes = 6; + glslCompilerResources->maxTextureUnits = 32; + glslCompilerResources->maxTextureCoords = 32; + glslCompilerResources->maxVertexAttribs = 64; + glslCompilerResources->maxVertexUniformComponents = 4096; + glslCompilerResources->maxVaryingFloats = 64; + glslCompilerResources->maxVertexTextureImageUnits = 32; + glslCompilerResources->maxCombinedTextureImageUnits = 80; + glslCompilerResources->maxTextureImageUnits = 32; + glslCompilerResources->maxFragmentUniformComponents = 4096; + glslCompilerResources->maxDrawBuffers = 32; + glslCompilerResources->maxVertexUniformVectors = 128; + glslCompilerResources->maxVaryingVectors = 8; + glslCompilerResources->maxFragmentUniformVectors = 16; + glslCompilerResources->maxVertexOutputVectors = 16; + glslCompilerResources->maxFragmentInputVectors = 15; + glslCompilerResources->minProgramTexelOffset = -8; + glslCompilerResources->maxProgramTexelOffset = 7; + glslCompilerResources->maxClipDistances = 8; + glslCompilerResources->maxComputeWorkGroupCountX = 65535; + glslCompilerResources->maxComputeWorkGroupCountY = 65535; + glslCompilerResources->maxComputeWorkGroupCountZ = 65535; + glslCompilerResources->maxComputeWorkGroupSizeX = 1024; + glslCompilerResources->maxComputeWorkGroupSizeY = 1024; + glslCompilerResources->maxComputeWorkGroupSizeZ = 64; + glslCompilerResources->maxComputeUniformComponents = 1024; + glslCompilerResources->maxComputeTextureImageUnits = 16; + glslCompilerResources->maxComputeImageUniforms = 8; + glslCompilerResources->maxComputeAtomicCounters = 8; + glslCompilerResources->maxComputeAtomicCounterBuffers = 1; + glslCompilerResources->maxVaryingComponents = 60; + glslCompilerResources->maxVertexOutputComponents = 64; + glslCompilerResources->maxGeometryInputComponents = 64; + glslCompilerResources->maxGeometryOutputComponents = 128; + glslCompilerResources->maxFragmentInputComponents = 128; + glslCompilerResources->maxImageUnits = 8; + glslCompilerResources->maxCombinedImageUnitsAndFragmentOutputs = 8; + glslCompilerResources->maxCombinedShaderOutputResources = 8; + glslCompilerResources->maxImageSamples = 0; + glslCompilerResources->maxVertexImageUniforms = 0; + glslCompilerResources->maxTessControlImageUniforms = 0; + glslCompilerResources->maxTessEvaluationImageUniforms = 0; + glslCompilerResources->maxGeometryImageUniforms = 0; + glslCompilerResources->maxFragmentImageUniforms = 8; + glslCompilerResources->maxCombinedImageUniforms = 8; + glslCompilerResources->maxGeometryTextureImageUnits = 16; + glslCompilerResources->maxGeometryOutputVertices = 256; + glslCompilerResources->maxGeometryTotalOutputComponents = 1024; + glslCompilerResources->maxGeometryUniformComponents = 1024; + glslCompilerResources->maxGeometryVaryingComponents = 64; + glslCompilerResources->maxTessControlInputComponents = 128; + glslCompilerResources->maxTessControlOutputComponents = 128; + glslCompilerResources->maxTessControlTextureImageUnits = 16; + glslCompilerResources->maxTessControlUniformComponents = 1024; + glslCompilerResources->maxTessControlTotalOutputComponents = 4096; + glslCompilerResources->maxTessEvaluationInputComponents = 128; + glslCompilerResources->maxTessEvaluationOutputComponents = 128; + glslCompilerResources->maxTessEvaluationTextureImageUnits = 16; + glslCompilerResources->maxTessEvaluationUniformComponents = 1024; + glslCompilerResources->maxTessPatchComponents = 120; + glslCompilerResources->maxPatchVertices = 32; + glslCompilerResources->maxTessGenLevel = 64; + glslCompilerResources->maxViewports = 16; + glslCompilerResources->maxVertexAtomicCounters = 0; + glslCompilerResources->maxTessControlAtomicCounters = 0; + glslCompilerResources->maxTessEvaluationAtomicCounters = 0; + glslCompilerResources->maxGeometryAtomicCounters = 0; + glslCompilerResources->maxFragmentAtomicCounters = 8; + glslCompilerResources->maxCombinedAtomicCounters = 8; + glslCompilerResources->maxAtomicCounterBindings = 1; + glslCompilerResources->maxVertexAtomicCounterBuffers = 0; + glslCompilerResources->maxTessControlAtomicCounterBuffers = 0; + glslCompilerResources->maxTessEvaluationAtomicCounterBuffers = 0; + glslCompilerResources->maxGeometryAtomicCounterBuffers = 0; + glslCompilerResources->maxFragmentAtomicCounterBuffers = 1; + glslCompilerResources->maxCombinedAtomicCounterBuffers = 1; + glslCompilerResources->maxAtomicCounterBufferSize = 16384; + glslCompilerResources->maxTransformFeedbackBuffers = 4; + glslCompilerResources->maxTransformFeedbackInterleavedComponents = 64; + glslCompilerResources->maxCullDistances = 8; + glslCompilerResources->maxCombinedClipAndCullDistances = 8; + glslCompilerResources->maxSamples = 4; + glslCompilerResources->limits.nonInductiveForLoops = 1; + glslCompilerResources->limits.whileLoops = 1; + glslCompilerResources->limits.doWhileLoops = 1; + glslCompilerResources->limits.generalUniformIndexing = 1; + glslCompilerResources->limits.generalAttributeMatrixVectorIndexing = 1; + glslCompilerResources->limits.generalVaryingIndexing = 1; + glslCompilerResources->limits.generalSamplerIndexing = 1; + glslCompilerResources->limits.generalVariableIndexing = 1; + glslCompilerResources->limits.generalConstantMatrixVectorIndexing = 1; +} -#if 0 - uint32_t testPrograms[] = { - shader::render_utils::program::parabola, - shader::INVALID_PROGRAM, - }; -#else - const auto& testPrograms = shader::all_programs; +void writeSpirv(const std::string& filename, const std::vector& spirv) { + std::ofstream o(filename, std::ios::trunc | std::ios::binary); + for (const auto& word : spirv) { + o.write((const char*)&word, sizeof(word)); + } + o.close(); +} + +void write(const std::string& filename, const std::string& text) { + std::ofstream o(filename, std::ios::trunc); + o.write(text.c_str(), text.size()); + o.close(); +} + +bool endsWith(const std::string& s, const std::string& f) { + auto end = s.substr(s.size() - f.size()); + return (end == f); +} + +EShLanguage getShaderStage(const std::string& shaderName) { + static const std::string VERT_EXT{ ".vert" }; + static const std::string FRAG_EXT{ ".frag" }; + static const std::string GEOM_EXT{ ".geom" }; + static const size_t EXT_SIZE = VERT_EXT.size(); + if (shaderName.size() < EXT_SIZE) { + throw std::runtime_error("Invalid shader name"); + } + std::string ext = shaderName.substr(shaderName.size() - EXT_SIZE); + if (ext == VERT_EXT) { + return EShLangVertex; + } else if (ext == FRAG_EXT) { + return EShLangFragment; + } else if (ext == GEOM_EXT) { + return EShLangGeometry; + } + throw std::runtime_error("Invalid shader name"); +} + +const gpu::Shader::Source& loadShader(uint32_t shaderId); + +bool compileSpirv(uint32_t shaderId, bool stereo) { + const gpu::Shader::Source& source = loadShader(shaderId); + using namespace glslang; + + static const std::string CORE_HEADER( + R"SHADER(#version 450 core +#define GPU_GL450 +#define BITFIELD int +#define GPU_SSBO_TRANSFORM_OBJECT +#define gl_VertexID gl_VertexIndex +#define gl_InstanceID gl_InstanceIndex +)SHADER"); + + static const std::string DOMAIN_HEADER[] = { + "#define GPU_VERTEX_SHADER\r\n", + "#define GPU_PIXEL_SHADER\r\n", + "#define GPU_GEOMETRY_SHADER\r\n", + }; + + static const std::string STEREO_HEADER( + R"SHADER( +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN +)SHADER"); + + static std::once_flag once; + static TBuiltInResource glslCompilerResources; + std::call_once(once, [&] { configureGLSLCompilerResources(&glslCompilerResources); }); + + static const EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules); + auto shaderName = shader::loadShaderName(shaderId); + auto stage = getShaderStage(shaderName); + + TShader shader(stage); + std::vector strings; + strings.push_back(CORE_HEADER.c_str()); + strings.push_back(DOMAIN_HEADER[stage == EShLangVertex ? 0 : 1].c_str()); + if (stereo) { + strings.push_back(STEREO_HEADER.c_str()); + } + strings.push_back(source.getCode().c_str()); + shader.setStrings(strings.data(), (int)strings.size()); + shader.setEnvInput(EShSourceGlsl, stage, EShClientOpenGL, 450); + shader.setEnvClient(EShClientVulkan, EShTargetVulkan_1_1); + shader.setEnvTarget(EShTargetSpv, EShTargetSpv_1_3); + bool success = shader.parse(&glslCompilerResources, 450, false, messages); + if (!success) { + qWarning() << "Failed to parse shader " << shaderName.c_str(); + qWarning() << shader.getInfoLog(); + qWarning() << shader.getInfoDebugLog(); + return false; + } + + // Create and link a shader program containing the single shader + glslang::TProgram program; + program.addShader(&shader); + if (!program.link(messages)) { + qWarning() << "Failed to compile shader " << shaderName.c_str(); + qWarning() << program.getInfoLog(); + qWarning() << program.getInfoDebugLog(); + return false; + } + + std::string baseOutName = "d:/shaders/" + shaderName; + if (stereo) { + baseOutName += ".stereo"; + } + + // Output the SPIR-V code from the shader program + std::vector spirv; + glslang::GlslangToSpv(*program.getIntermediate(stage), spirv); + + spvtools::SpirvTools core(SPV_ENV_VULKAN_1_1); + spvtools::Optimizer opt(SPV_ENV_VULKAN_1_1); + + auto outputLambda = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { qWarning() << m; }; + core.SetMessageConsumer(outputLambda); + opt.SetMessageConsumer(outputLambda); + + if (!core.Validate(spirv)) { + throw std::runtime_error("invalid spirv"); + } + writeSpirv(baseOutName + ".spv", spirv); + + opt.RegisterPass(spvtools::CreateFreezeSpecConstantValuePass()) + .RegisterPass(spvtools::CreateStrengthReductionPass()) + .RegisterPass(spvtools::CreateEliminateDeadConstantPass()) + .RegisterPass(spvtools::CreateEliminateDeadFunctionsPass()) + .RegisterPass(spvtools::CreateUnifyConstantPass()); + + std::vector optspirv; + if (!opt.Run(spirv.data(), spirv.size(), &optspirv)) { + throw std::runtime_error("bad optimize run"); + } + writeSpirv(baseOutName + ".opt.spv", optspirv); + + std::string disassembly; + if (!core.Disassemble(optspirv, &disassembly)) { + throw std::runtime_error("bad disassembly"); + } + + write(baseOutName + ".spv.txt", disassembly); + + return true; +} #endif - size_t index = 0; - while (shader::INVALID_PROGRAM != testPrograms[index]) { - auto programId = testPrograms[index]; - ++index; +void validateDialectVariantSource(const shader::DialectVariantSource& source) { + if (source.scribe.empty()) { + throw std::runtime_error("Missing scribe source"); + } - uint32_t vertexId = shader::getVertexId(programId); - uint32_t fragmentId = shader::getFragmentId(programId); - usedShaders.insert(vertexId); - usedShaders.insert(fragmentId); - maxShader = std::max(maxShader, std::max(fragmentId, vertexId)); - auto vertexSource = gpu::Shader::getShaderSource(vertexId); - QVERIFY(!vertexSource.getCode().empty()); - verifyBindings(vertexSource); - auto fragmentSource = gpu::Shader::getShaderSource(fragmentId); - QVERIFY(!fragmentSource.getCode().empty()); - verifyBindings(fragmentSource); + if (source.spirv.empty()) { + throw std::runtime_error("Missing SPIRV"); + } + + if (source.glsl.empty()) { + throw std::runtime_error("Missing GLSL"); + } +} + +void validaDialectSource(const shader::DialectSource& dialectSource) { + for (const auto& variant : shader::allVariants()) { + validateDialectVariantSource(dialectSource.variantSources.find(variant)->second); + } +} + +void validateSource(const shader::Source& shader) { + if (shader.id == shader::INVALID_SHADER) { + throw std::runtime_error("Missing stored shader ID"); + } + + if (shader.name.empty()) { + throw std::runtime_error("Missing shader name"); + } + + static const auto& dialects = shader::allDialects(); + for (const auto dialect : dialects) { + if (!shader.dialectSources.count(dialect)) { + throw std::runtime_error("Missing platform shader"); + } + const auto& platformShader = shader.dialectSources.find(dialect)->second; + validaDialectSource(platformShader); + } +} + +void ShaderTests::testShaderLoad() { + try { + const auto& shaderIds = shader::allShaders(); + + // For debugging compile or link failures on individual programs, enable the following block and change the array values + // Be sure to end with the sentinal value of shader::INVALID_PROGRAM + const auto& programIds = shader::allPrograms(); + + for (auto shaderId : shaderIds) { + validateSource(shader::Source::get(shaderId)); + } + + { + std::unordered_set programUsedShaders; +#pragma omp parallel for + for (auto programId : programIds) { + auto vertexId = shader::getVertexId(programId); + shader::Source::get(vertexId); + programUsedShaders.insert(vertexId); + auto fragmentId = shader::getFragmentId(programId); + shader::Source::get(fragmentId); + programUsedShaders.insert(fragmentId); + } + + for (const auto& shaderId : shaderIds) { + if (programUsedShaders.count(shaderId)) { + continue; + } + const auto& shader = shader::Source::get(shaderId); + qDebug() << "Unused shader found" << shader.name.c_str(); + } + } + + // Traverse all programs again to do program level tests + for (const auto& programId : programIds) { + auto vertexId = shader::getVertexId(programId); + const auto& vertexSource = shader::Source::get(vertexId); + auto fragmentId = shader::getFragmentId(programId); + const auto& fragmentSource = shader::Source::get(fragmentId); verifyInterface(vertexSource, fragmentSource); - auto expectedBindings = mergeReflection({ vertexSource, fragmentSource }); - auto program = gpu::Shader::createProgram(programId); auto glBackend = std::static_pointer_cast(_gpuContext->getBackend()); auto glshader = gpu::gl::GLShader::sync(*glBackend, *program); + if (!glshader) { - qWarning() << "Failed to compile or link vertex " << vertexId << " fragment " << fragmentId; + qWarning() << "Failed to compile or link vertex " << vertexSource.name.c_str() << " fragment " + << fragmentSource.name.c_str(); QFAIL("Program link error"); } - +#if RUNTIME_SHADER_COMPILE_TEST + auto expectedBindings = mergeReflection({ vertexSource, fragmentSource }); QVERIFY(glshader != nullptr); for (const auto& shaderObject : glshader->_shaderObjects) { const auto& program = shaderObject.glprogram; @@ -260,9 +552,10 @@ void ShaderTests::testShaderLoad() { // Textures { auto textures = gl::Uniform::loadTextures(program); - auto expiredBegin = std::remove_if(textures.begin(), textures.end(), [&](const gl::Uniform& uniform) -> bool { - return uniform.name == "transformObjectBuffer"; - }); + auto expiredBegin = + std::remove_if(textures.begin(), textures.end(), [&](const gl::Uniform& uniform) -> bool { + return uniform.name == "transformObjectBuffer"; + }); textures.erase(expiredBegin, textures.end()); const auto expectedTextures = expectedBindings[gpu::Shader::BindingType::TEXTURE]; @@ -296,11 +589,13 @@ void ShaderTests::testShaderLoad() { // FIXME add storage buffer validation } +#endif } } catch (const std::runtime_error& error) { QFAIL(error.what()); } +#if RUNTIME_SHADER_COMPILE_TEST for (uint32_t i = 1; i <= maxShader; ++i) { auto used = usedShaders.count(i); if (0 != usedShaders.count(i)) { @@ -310,6 +605,7 @@ void ShaderTests::testShaderLoad() { auto name = QJsonDocument::fromJson(reflectionJson.c_str()).object()["name"].toString(); qDebug() << "Unused shader" << name; } +#endif qDebug() << "Completed all shaders"; } diff --git a/tests/shaders/src/ShaderTests.h b/tests/shaders/src/ShaderTests.h index d109341c1f..fd361d9e60 100644 --- a/tests/shaders/src/ShaderTests.h +++ b/tests/shaders/src/ShaderTests.h @@ -23,9 +23,8 @@ private slots: void testShaderLoad(); private: - QWindow* _window{ nullptr }; - gl::Context* _context{ nullptr }; + gl::OffscreenContext* _context{ nullptr }; gpu::ContextPointer _gpuContext; }; -#endif // hifi_ViewFruxtumTests_h +#endif // hifi_ViewFruxtumTests_h diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 9b36180bc2..1c36306410 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,9 +2,6 @@ add_subdirectory(scribe) set_target_properties(scribe PROPERTIES FOLDER "Tools") -add_subdirectory(shreflect) -set_target_properties(shreflect PROPERTIES FOLDER "Tools") - find_npm() if (NPM_EXECUTABLE) add_subdirectory(jsdoc) diff --git a/tools/ktx-tool/CMakeLists.txt b/tools/ktx-tool/CMakeLists.txt index 9daf8e0a1a..6bb09e0a9e 100644 --- a/tools/ktx-tool/CMakeLists.txt +++ b/tools/ktx-tool/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME ktx-tool) setup_hifi_project(Quick Gui Concurrent) -link_hifi_libraries(shared networking image gl gpu ktx) +link_hifi_libraries(shared networking image gl shaders gpu ktx) target_gli() diff --git a/tools/scribe/src/TextTemplate.cpp b/tools/scribe/src/TextTemplate.cpp index 89937c4da6..aad508487c 100755 --- a/tools/scribe/src/TextTemplate.cpp +++ b/tools/scribe/src/TextTemplate.cpp @@ -81,6 +81,7 @@ bool TextTemplate::loadFile(const ConfigPointer& config, const char* filename, S std::ifstream ifs; ifs.open(fullfilename.c_str()); if (ifs.is_open()) { + config->_includeFullPaths.insert(fullfilename); std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); source = str; ifs.close(); @@ -1003,3 +1004,9 @@ void TextTemplate::Config::displayTree(std::ostream& dst, int& level) const { } level--; } + +void TextTemplate::Config::displayMakefileDeps(std::ostream& dst) const { + for (const auto& include : _includeFullPaths) { + std::cout << include << std::endl; + } +} diff --git a/tools/scribe/src/TextTemplate.h b/tools/scribe/src/TextTemplate.h index 44edc23c12..b3b767176c 100755 --- a/tools/scribe/src/TextTemplate.h +++ b/tools/scribe/src/TextTemplate.h @@ -18,6 +18,7 @@ #include #include #include +#include class TextTemplate { public: @@ -26,6 +27,7 @@ public: typedef std::vector< String > StringVector; typedef std::map< String, String > Vars; typedef std::map< String, TextTemplate::Pointer > Includes; + using PathSet = std::unordered_set; class Tag { public: @@ -123,7 +125,7 @@ public: public: typedef std::shared_ptr< Config > Pointer; typedef bool (*IncluderCallback) (const Config::Pointer& config, const char* filename, String& source); - + PathSet _includeFullPaths; Includes _includes; Funcs _funcs; std::ostream* _logStream; @@ -139,6 +141,8 @@ public: void addIncludePath(const char* path); void displayTree(std::ostream& dst, int& level) const; + + void displayMakefileDeps(std::ostream& dst) const; }; static bool loadFile(const Config::Pointer& config, const char* filename, String& source); @@ -156,9 +160,12 @@ public: void displayTree(std::ostream& dst, int& level) const; + void displayMakefileDeps(std::ostream& dst) const { _config->displayMakefileDeps(dst); } + protected: Config::Pointer _config; Block::Pointer _root; + PathSet _includeFullPaths; int _numErrors; bool _steppingStarted; diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index c8c540c362..c1ade05bb1 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -25,10 +25,12 @@ int main (int argc, char** argv) { std::string srcFilename; std::string destFilename; std::string targetName; + std::list headerFiles; TextTemplate::Vars vars; std::string lastVarName; bool listVars = false; + bool makefileDeps = false; bool showParseTree = false; bool makeCPlusPlus = false; @@ -42,6 +44,7 @@ int main (int argc, char** argv) { GRAB_INCLUDE_PATH, GRAB_TARGET_NAME, GRAB_SHADER_TYPE, + GRAB_HEADER, EXIT, } mode = READY; @@ -65,6 +68,8 @@ int main (int argc, char** argv) { case READY: { if (inputs.back() == "-o") { mode = GRAB_OUTPUT; + } else if (inputs.back() == "-H") { + mode = GRAB_HEADER; } else if (inputs.back() == "-t") { mode = GRAB_TARGET_NAME; } else if (inputs.back() == "-D") { @@ -74,6 +79,9 @@ int main (int argc, char** argv) { } else if (inputs.back() == "-listVars") { listVars = true; mode = READY; + } else if (inputs.back() == "-M") { + makefileDeps = true; + mode = READY; } else if (inputs.back() == "-showParseTree") { showParseTree = true; mode = READY; @@ -85,7 +93,7 @@ int main (int argc, char** argv) { } else { // just grabbed the source filename, stop parameter parsing srcFilename = inputs.back(); - mode = EXIT; + mode = READY; } } break; @@ -102,6 +110,12 @@ int main (int argc, char** argv) { } break; + case GRAB_HEADER: { + headerFiles.push_back(inputs.back()); + mode = READY; + } + break; + case GRAB_VAR_NAME: { // grab first the name of the var lastVarName = inputs.back(); @@ -155,6 +169,9 @@ int main (int argc, char** argv) { cerr << " -I include_directory: Declare a directory to be added to the includes search pool." << endl; cerr << " -D varname varvalue: Declare a var used to generate the output file." << endl; cerr << " varname and varvalue must be made of alpha numerical characters with no spaces." << endl; + cerr << " -H : Prepend the contents of header file to the scribe output " << endl; + cerr << " This can be specified multiple times and the headers will be applied in the specified order" << endl; + cerr << " -M : Emit a list of files that the scribe output depends on, for make and similar build tools " << endl; cerr << " -listVars : Will list the vars name and value in the standard output." << endl; cerr << " -showParseTree : Draw the tree obtained while parsing the source" << endl; cerr << " -c++ : Generate a c++ source file containing the output file stream stored as a char[] variable" << endl; @@ -204,8 +221,37 @@ int main (int argc, char** argv) { auto scribe = std::make_shared(srcFilename, config); + std::string header; + if (!headerFiles.empty()) { + for (const auto& headerFile : headerFiles) { + std::fstream headerStream; + headerStream.open(headerFile, std::fstream::in); + if (!headerStream.is_open()) { + cerr << "Failed to open source file <" << headerFile << ">" << endl; + return 1; + } + header += std::string((std::istreambuf_iterator(headerStream)), std::istreambuf_iterator()); + } + } + + // Add the type define to the shader + switch (type) { + case VERTEX: + header += "#define GPU_VERTEX_SHADER\n"; + break; + + case FRAGMENT: + header += "#define GPU_PIXEL_SHADER\n"; + break; + + case GEOMETRY: + header += "#define GPU_GEOMETRY_SHADER\n"; + break; + } + // ready to parse and generate std::stringstream destStringStream; + destStringStream << header; int numErrors = scribe->scribe(destStringStream, srcStream, vars); if (numErrors) { cerr << "Scribe " << srcFilename << "> failed: " << numErrors << " errors." << endl; @@ -222,7 +268,9 @@ int main (int argc, char** argv) { scribe->displayTree(cerr, level); } - if (makeCPlusPlus) { + if (makefileDeps) { + scribe->displayMakefileDeps(cout); + } else if (makeCPlusPlus) { // Because there is a maximum size for literal strings declared in source we need to partition the // full source string stream into pages that seems to be around that value... const int MAX_STRING_LITERAL = 10000; diff --git a/tools/shadergen.py b/tools/shadergen.py new file mode 100644 index 0000000000..7450aebcb3 --- /dev/null +++ b/tools/shadergen.py @@ -0,0 +1,257 @@ +import re +import subprocess +import sys +import time +import os +import json +import argparse +import concurrent +from os.path import expanduser +from concurrent.futures import ThreadPoolExecutor +from argparse import ArgumentParser +from pathlib import Path +from threading import Lock + + # # Target dependant Custom rule on the SHADER_FILE + # if (ANDROID) + # set(GLPROFILE LINUX_GL) + # else() + # if (APPLE) + # set(GLPROFILE MAC_GL) + # elseif(UNIX) + # set(GLPROFILE LINUX_GL) + # else() + # set(GLPROFILE PC_GL) + # endif() + # endif() + +def getTypeForScribeFile(scribefilename): + last = scribefilename.rfind('.') + extension = scribefilename[last:] + switcher = { + '.slv': 'vert', + '.slf': 'frag', + '.slg': 'geom', + '.slc': 'comp', + } + if not extension in switcher: + raise ValueError("Unknown scribe file type for " + scribefilename) + return switcher.get(extension) + +def getCommonScribeArgs(scribefile, includeLibs): + scribeArgs = [args.scribe] + # FIXME use the sys.platform to set the correct value + scribeArgs.extend(['-D', 'GLPROFILE', 'PC_GL']) + scribeArgs.extend(['-T', getTypeForScribeFile(scribefile)]) + for lib in includeLibs: + scribeArgs.extend(['-I', args.source_dir + '/libraries/' + lib + '/src/' + lib + '/']) + scribeArgs.extend(['-I', args.source_dir + '/libraries/' + lib + '/src/']) + scribeArgs.append(scribefile) + return scribeArgs + +def getDialectAndVariantHeaders(dialect, variant): + headerPath = args.source_dir + '/libraries/shaders/headers/' + variantHeader = headerPath + ('stereo.glsl' if (variant == 'stereo') else 'mono.glsl') + dialectHeader = headerPath + dialect + '/header.glsl' + return [dialectHeader, variantHeader] + +class ScribeDependenciesCache: + cache = {} + lock = Lock() + filename = '' + + def __init__(self, filename): + self.filename = filename + + def load(self): + jsonstr = '{}' + if (os.path.exists(self.filename)): + with open(self.filename) as f: + jsonstr = f.read() + self.cache = json.loads(jsonstr) + + def save(self): + with open(self.filename, "w") as f: + f.write(json.dumps(self.cache)) + + def get(self, scribefile, dialect, variant): + self.lock.acquire() + key = self.key(scribefile, dialect, variant) + try: + if key in self.cache: + return self.cache[key].copy() + finally: + self.lock.release() + return None + + def key(self, scribeFile, dialect, variant): + return ':'.join([scribeFile, dialect, variant]) + + def getOrGen(self, scribefile, includeLibs, dialect, variant): + result = self.get(scribefile, dialect, variant) + if (None == result): + result = self.gen(scribefile, includeLibs, dialect, variant) + return result + + def gen(self, scribefile, includeLibs, dialect, variant): + scribeArgs = getCommonScribeArgs(scribefile, includeLibs) + scribeArgs.extend(['-M']) + processResult = subprocess.run(scribeArgs, stdout=subprocess.PIPE) + if (0 != processResult.returncode): + raise RuntimeError("Unable to parse scribe dependencies") + result = processResult.stdout.decode("utf-8").splitlines(False) + result.append(scribefile) + result.extend(getDialectAndVariantHeaders(dialect, variant)) + key = self.key(scribefile, dialect, variant) + self.lock.acquire() + self.cache[key] = result.copy() + self.lock.release() + return result + +def getFileTimes(files): + if isinstance(files, str): + files = [files] + return list(map(lambda f: os.path.getmtime(f) if os.path.isfile(f) else -1, files)) + +def outOfDate(inputs, output): + oldestInput = max(getFileTimes(inputs)) + youngestOutput = min(getFileTimes(output)) + diff = youngestOutput - oldestInput + return oldestInput >= youngestOutput + +def executeSubprocess(processArgs): + processResult = subprocess.run(processArgs, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if (0 != processResult.returncode): + raise RuntimeError('Call to "{}" failed.\n\narguments:\n{}\n\nstdout:\n{}\n\nstderr:\n{}'.format( + processArgs[0], + ' '.join(processArgs[1:]), + processResult.stdout.decode('utf-8'), + processResult.stderr.decode('utf-8'))) + +folderMutex = Lock() + +def processCommand(line): + global args + global scribeDepCache + glslangExec = args.spirv_binaries + '/glslangValidator' + spirvCrossExec = args.spirv_binaries + '/spirv-cross' + spirvOptExec = args.spirv_binaries + '/spirv-opt' + params = line.split(';') + dialect = params.pop(0) + variant = params.pop(0) + scribeFile = args.source_dir + '/' + params.pop(0) + unoptGlslFile = args.source_dir + '/' + params.pop(0) + libs = params + + upoptSpirvFile = unoptGlslFile + '.spv' + spirvFile = unoptGlslFile + '.opt.spv' + reflectionFile = unoptGlslFile + '.json' + glslFile = unoptGlslFile + '.glsl' + outputFiles = [unoptGlslFile, spirvFile, reflectionFile, glslFile] + + scribeOutputDir = os.path.abspath(os.path.join(unoptGlslFile, os.pardir)) + + # Serialize checking and creation of the output directory to avoid occasional + # crashes + global folderMutex + folderMutex.acquire() + if not os.path.exists(scribeOutputDir): + os.makedirs(scribeOutputDir) + folderMutex.release() + + scribeDeps = scribeDepCache.getOrGen(scribeFile, libs, dialect, variant) + + # if the scribe sources (slv, slf, slh, etc), or the dialect/ variant headers are out of date + # regenerate the scribe GLSL output + if args.force or outOfDate(scribeDeps, outputFiles): + print('Processing file {} dialect {} variant {}'.format(scribeFile, dialect, variant)) + if args.dry_run: + return True + + scribeDepCache.gen(scribeFile, libs, dialect, variant) + scribeArgs = getCommonScribeArgs(scribeFile, libs) + headerFlag = '-H' + # using the old flag on Android builds for now + if (dialect == '310es'): headerFlag = '-h' + for header in getDialectAndVariantHeaders(dialect, variant): + scribeArgs.extend([headerFlag, header]) + scribeArgs.extend(['-o', unoptGlslFile]) + executeSubprocess(scribeArgs) + + # Generate the un-optimized output + executeSubprocess([glslangExec, '-V110', '-o', upoptSpirvFile, unoptGlslFile]) + + # Optimize the SPIRV + executeSubprocess([spirvOptExec, '-O', '-o', spirvFile, upoptSpirvFile]) + + # Generation JSON reflection + executeSubprocess([spirvCrossExec, '--reflect', 'json', '--output', reflectionFile, spirvFile]) + + # Generate the optimized GLSL output + spirvCrossDialect = dialect + # 310es causes spirv-cross to inject "#extension GL_OES_texture_buffer : require" into the output + if (dialect == '310es'): spirvCrossDialect = '320es' + spirvCrossArgs = [spirvCrossExec, '--output', glslFile, spirvFile, '--version', spirvCrossDialect] + if (dialect == '410'): spirvCrossArgs.append('--no-420pack-extension') + executeSubprocess(spirvCrossArgs) + else: + # This logic is necessary because cmake will agressively keep re-executing the shadergen + # code otherwise + Path(unoptGlslFile).touch() + Path(upoptSpirvFile).touch() + Path(spirvFile).touch() + Path(glslFile).touch() + Path(reflectionFile).touch() + return True + + + +def main(): + commands = args.commands.read().splitlines(False) + if args.debug: + for command in commands: + processCommand(command) + else: + workers = max(1, os.cpu_count() - 2) + with ThreadPoolExecutor(max_workers=workers) as executor: + for result in executor.map(processCommand, commands): + if not result: + raise RuntimeError("Failed to execute all subprocesses") + executor.shutdown() + + +parser = ArgumentParser(description='Generate shader artifacts.') +parser.add_argument('--commands', type=argparse.FileType('r'), help='list of commands to execute') +parser.add_argument('--spirv-binaries', type=str, help='location of the SPIRV binaries') +parser.add_argument('--build-dir', type=str, help='The build directory base path') +parser.add_argument('--source-dir', type=str, help='The root directory of the git repository') +parser.add_argument('--scribe', type=str, help='The scribe executable path') +parser.add_argument('--debug', action='store_true') +parser.add_argument('--force', action='store_true', help='Ignore timestamps and force regeneration of all files') +parser.add_argument('--dry-run', action='store_true', help='Report the files that would be process, but do not output') + +args = None +if len(sys.argv) == 1: + # for debugging + spirvPath = os.environ['VULKAN_SDK'] + '/bin' + #spirvPath = expanduser('~//VulkanSDK/1.1.82.1/x86_64/bin') + sourceDir = expanduser('~/git/hifi') + buildPath = sourceDir + '/build_noui' + scribePath = buildPath + '/tools/scribe/Release/scribe' + commandsPath = buildPath + '/libraries/shaders/shadergen.txt' + shaderDir = buildPath + '/libraries/shaders' + testArgs = '--commands {} --spirv-binaries {} --scribe {} --build-dir {} --source-dir {}'.format( + commandsPath, spirvPath, scribePath, shaderDir, sourceDir + ).split() + #testArgs.append('--debug') + #testArgs.append('--force') + #testArgs.append('--dry-run') + args = parser.parse_args(testArgs) +else: + args = parser.parse_args() + +scribeDepCache = ScribeDependenciesCache(args.build_dir + '/shaderDeps.json') +scribeDepCache.load() +main() +scribeDepCache.save() + diff --git a/tools/shreflect/CMakeLists.txt b/tools/shreflect/CMakeLists.txt deleted file mode 100644 index 0748f59d31..0000000000 --- a/tools/shreflect/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -set(TARGET_NAME shreflect) - -# don't use the setup_hifi_project macro as we don't want Qt or GLM dependencies -file(GLOB TARGET_SRCS src/*) -add_executable(${TARGET_NAME} ${TARGET_SRCS}) -target_json() - -if (WIN32) - set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF") -endif() diff --git a/tools/shreflect/src/main.cpp b/tools/shreflect/src/main.cpp deleted file mode 100644 index e13f937102..0000000000 --- a/tools/shreflect/src/main.cpp +++ /dev/null @@ -1,204 +0,0 @@ -// -// Bradley Austin Davis on 2018/05/24 -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using json = nlohmann::json; - -std::vector splitStringIntoLines(const std::string& s) { - std::stringstream ss(s); - std::vector result; - std::string line; - while (std::getline(ss, line, '\n')) { - result.push_back(line); - } - return result; -} - -std::string readFile(const std::string& file) { - std::ifstream t(file); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - return str; -} - -void writeFile(const std::string& file, const std::string& out) { - std::ofstream t(file, std::ios::trunc); - t << out; - t.close(); -} - -// Convert a Perl style multi-line commented regex into a C++ style regex -// All whitespace will be removed and lines with '#' comments will have the comments removed -std::string getUnformattedRegex(const std::string& formatted) { - static const std::regex WHITESPACE = std::regex("\\s+"); - static const std::string EMPTY; - std::string result; - result.reserve(formatted.size()); - auto lines = splitStringIntoLines(formatted); - for (auto line : lines) { - auto commentStart = line.find('#'); - if (std::string::npos != commentStart) { - line = line.substr(0, commentStart); - } - line = std::regex_replace(line, WHITESPACE, EMPTY); - result += line; - } - - return result; -} - -static std::string LAYOUT_REGEX_STRING{ R"REGEX( -^layout\( # BEGIN layout declaration block - (\s*std140\s*,\s*)? # Optional std140 marker - (binding|location) # binding / location - \s*=\s* - (?: - (\b\d+\b) # literal numeric binding like binding=1 - | - (\b[A-Z_0-9]+\b) # Preprocessor macro binding like binding=GPU_TEXTURE_FOO - ) -\)\s* # END layout declaration block -(?: - ( # Texture or simple uniform like `layout(binding=0) uniform sampler2D originalTexture;` - uniform\s+ - (\b\w+\b)\s+ - (\b\w+\b)\s* - (?:\[\d*\])? - (?:\s*=.*)? - \s*;.*$ - ) - | - ( # UBO or SSBO like `layout(std140, binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer {` - \b(uniform|buffer)\b\s+ - \b(\w+\b) - \s*\{.*$ - ) - | - ( # Input or output attribute like `layout(location=GPU_ATTR_POSITION) in vec4 inPosition;` - \b(in|out)\b\s+ - \b(\w+)\b\s+ - \b(\w+)\b\s*;\s*$ - ) -) -)REGEX" }; - -enum Groups { - STD140 = 1, - LOCATION_TYPE = 2, - LOCATION_LITERAL = 3, - LOCATION_DEFINE = 4, - DECL_SIMPLE = 5, - SIMPLE_TYPE = 6, - SIMPLE_NAME = 7, - DECL_STRUCT = 8, - STRUCT_TYPE = 9, - STRUCT_NAME = 10, - DECL_INOUT = 11, - INOUT_DIRECTION = 12, - INOUT_TYPE = 13, - INOUT_NAME = 14, -}; - -json reflectShader(const std::string& shaderPath) { - static const std::regex DEFINE("^#define\\s+([_A-Z0-9]+)\\s+(\\d+)\\s*$"); - static const std::regex LAYOUT_QUALIFIER{ getUnformattedRegex(LAYOUT_REGEX_STRING) }; - - - auto shaderSource = readFile(shaderPath); - std::vector lines = splitStringIntoLines(shaderSource); - using Map = std::unordered_map; - - json inputs; - json outputs; - json textures; - json textureTypes; - json uniforms; - json storageBuffers; - json uniformBuffers; - Map locationDefines; - for (const auto& line : lines) { - std::cmatch m; - if (std::regex_match(line.c_str(), m, DEFINE)) { - locationDefines[m[1].str()] = std::stoi(m[2].first); - } else if (std::regex_match(line.c_str(), m, LAYOUT_QUALIFIER)) { - int binding = -1; - if (m[LOCATION_LITERAL].matched) { - binding = std::stoi(m[LOCATION_LITERAL].str()); - } else { - binding = locationDefines[m[LOCATION_DEFINE].str()]; - } - if (m[DECL_SIMPLE].matched) { - auto name = m[SIMPLE_NAME].str(); - auto type = m[SIMPLE_TYPE].str(); - bool isTexture = 0 == type.find("sampler"); - auto& map = isTexture ? textures : uniforms; - map[name] = binding; - if (isTexture) { - textureTypes[name] = type; - } - } else if (m[DECL_STRUCT].matched) { - auto name = m[STRUCT_NAME].str(); - auto type = m[STRUCT_TYPE].str(); - auto& map = (type == "buffer") ? storageBuffers : uniformBuffers; - map[name] = binding; - } else if (m[DECL_INOUT].matched) { - auto name = m[INOUT_NAME].str(); - auto& map = (m[INOUT_DIRECTION].str() == "in") ? inputs : outputs; - map[name] = binding; - } - } - } - - json result; - if (!inputs.empty()) { - result["inputs"] = inputs; - } - if (!outputs.empty()) { - result["outputs"] = outputs; - } - if (!textures.empty()) { - result["textures"] = textures; - } - if (!textureTypes.empty()) { - result["texturesTypes"] = textureTypes; - } - if (!uniforms.empty()) { - result["uniforms"] = uniforms; - } - if (!storageBuffers.empty()) { - result["storageBuffers"] = storageBuffers; - } - if (!uniformBuffers.empty()) { - result["uniformBuffers"] = uniformBuffers; - } - - result["name"] = shaderPath; - - return result; -} - -int main (int argc, char** argv) { - auto path = std::string(argv[1]); - auto shaderReflection = reflectShader(path); - writeFile(path + ".json", shaderReflection.dump(4)); - return 0; -}