mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 07:47:30 +02:00
Merge branch 'master' into M17217-b
# Conflicts: # plugins/openvr/src/OpenVrDisplayPlugin.cpp
This commit is contained in:
commit
96767c1103
403 changed files with 6614 additions and 5921 deletions
|
@ -15,6 +15,7 @@ include("cmake/compiler.cmake")
|
||||||
|
|
||||||
if (BUILD_SCRIBE_ONLY)
|
if (BUILD_SCRIBE_ONLY)
|
||||||
add_subdirectory(tools/scribe)
|
add_subdirectory(tools/scribe)
|
||||||
|
add_subdirectory(tools/shader_reflect)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ android {
|
||||||
'-DANDROID_STL=c++_shared',
|
'-DANDROID_STL=c++_shared',
|
||||||
'-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake',
|
'-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake',
|
||||||
'-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe' + EXEC_SUFFIX,
|
'-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe' + EXEC_SUFFIX,
|
||||||
|
'-DNATIVE_SHREFLECT=' + HIFI_ANDROID_PRECOMPILED + '/shreflect' + EXEC_SUFFIX,
|
||||||
'-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED,
|
'-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED,
|
||||||
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
|
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
|
||||||
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
||||||
|
|
|
@ -164,18 +164,29 @@ def packages = [
|
||||||
|
|
||||||
|
|
||||||
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
||||||
|
|
||||||
def scribeFile='scribe_linux_x86_64'
|
def scribeFile='scribe_linux_x86_64'
|
||||||
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
||||||
def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G'
|
def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G'
|
||||||
|
|
||||||
|
def shreflectLocalFile='shreflect' + EXEC_SUFFIX
|
||||||
|
def shreflectFile='shreflect_linux_x86_64'
|
||||||
|
def shreflectChecksum='d6094a8580066c0b6f4e80b5adfb1d98'
|
||||||
|
def shreflectVersion='jnrpudh6fptIg6T2.Z6fgKP2ultAdKmE'
|
||||||
|
|
||||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||||
scribeFile = 'scribe_osx_x86_64'
|
scribeFile = 'scribe_osx_x86_64'
|
||||||
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
||||||
scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC'
|
scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC'
|
||||||
|
shreflectFile='shreflect_osx_x86_64'
|
||||||
|
shreflectChecksum='d613ef0703c21371fee93fd2e54b964f'
|
||||||
|
shreflectVersion='.rYNzjSFq6WtWDnE5KIKRIAGyJtr__ad'
|
||||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
scribeFile = 'scribe_win32_x86_64.exe'
|
scribeFile = 'scribe_win32_x86_64.exe'
|
||||||
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
||||||
scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7'
|
scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7'
|
||||||
|
shreflectFile='shreflect_win32_x86_64.exe'
|
||||||
|
shreflectChecksum='6f4a77b8cceb3f1bbc655132c3665060'
|
||||||
|
shreflectVersion='iIyCyza1nelkbI7ihybF59bBlwrfAC3D'
|
||||||
}
|
}
|
||||||
|
|
||||||
def options = [
|
def options = [
|
||||||
|
@ -450,11 +461,27 @@ task fixScribePermissions(type: Exec, dependsOn: verifyScribe) {
|
||||||
commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + scribeLocalFile
|
commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + scribeLocalFile
|
||||||
}
|
}
|
||||||
|
|
||||||
task setupScribe(dependsOn: verifyScribe) { }
|
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]) { }
|
||||||
|
|
||||||
// On Windows, we don't need to set the executable bit, but on OSX and Unix we do
|
// On Windows, we don't need to set the executable bit, but on OSX and Unix we do
|
||||||
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
|
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
setupScribe.dependsOn fixScribePermissions
|
setupScribe.dependsOn fixScribePermissions
|
||||||
|
setupScribe.dependsOn fixShreflectPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
task extractGvrBinaries(dependsOn: extractDependencies) {
|
task extractGvrBinaries(dependsOn: extractDependencies) {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if (NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||||
|
message( FATAL_ERROR "Only 64 bit builds supported." )
|
||||||
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if (NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
|
||||||
message( FATAL_ERROR "Only 64 bit builds supported." )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
|
||||||
if (NOT WINDOW_SDK_PATH)
|
if (NOT WINDOW_SDK_PATH)
|
||||||
|
@ -52,32 +54,27 @@ endif()
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
# assume that the toolchain selected for android has C++11 support
|
# assume that the toolchain selected for android has C++11 support
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||||
|
elseif(APPLE)
|
||||||
|
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14")
|
||||||
|
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
||||||
|
if (CMAKE_GENERATOR STREQUAL "Xcode")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||||
|
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "YES")
|
||||||
|
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Release] "dwarf-with-dsym")
|
||||||
|
set(CMAKE_XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING[variant=Release] "YES")
|
||||||
|
endif()
|
||||||
elseif ((NOT MSVC12) AND (NOT MSVC14))
|
elseif ((NOT MSVC12) AND (NOT MSVC14))
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
if (COMPILER_SUPPORTS_CXX14)
|
||||||
if (COMPILER_SUPPORTS_CXX11)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|
||||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||||
endif()
|
endif()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (CMAKE_GENERATOR STREQUAL "Xcode")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "YES")
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Release] "dwarf-with-dsym")
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING[variant=Release] "YES")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (NOT ANDROID_LIB_DIR)
|
if (NOT ANDROID_LIB_DIR)
|
||||||
set(ANDROID_LIB_DIR $ENV{ANDROID_LIB_DIR})
|
set(ANDROID_LIB_DIR $ENV{ANDROID_LIB_DIR})
|
||||||
|
@ -110,4 +107,4 @@ if (APPLE)
|
||||||
# set that as the SDK to use
|
# set that as the SDK to use
|
||||||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk)
|
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk)
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
22
cmake/externals/json/CMakeLists.txt
vendored
Normal file
22
cmake/externals/json/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
set(EXTERNAL_NAME json)
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(
|
||||||
|
${EXTERNAL_NAME}
|
||||||
|
URL https://hifi-public.s3.amazonaws.com/dependencies/json_3.1.2.zip
|
||||||
|
URL_MD5 94dbf6ea25a7569ddc0ab6e20862cf16
|
||||||
|
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||||
|
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTERNAL_ARGS}
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
LOG_DOWNLOAD 1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Hide this external target (for ide users)
|
||||||
|
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||||
|
|
||||||
|
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||||
|
|
||||||
|
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||||
|
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR} CACHE PATH "List of json include directories")
|
|
@ -8,6 +8,12 @@
|
||||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
#
|
#
|
||||||
|
|
||||||
|
function(global_append varName varValue)
|
||||||
|
get_property(LOCAL_LIST GLOBAL PROPERTY ${varName})
|
||||||
|
list(APPEND LOCAL_LIST ${varValue})
|
||||||
|
set_property(GLOBAL PROPERTY ${varName} ${LOCAL_LIST})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
function(AUTOSCRIBE_SHADER SHADER_FILE)
|
function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||||
# Grab include files
|
# Grab include files
|
||||||
foreach(includeFile ${ARGN})
|
foreach(includeFile ${ARGN})
|
||||||
|
@ -45,11 +51,8 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||||
elseif(${SHADER_EXT} STREQUAL .slg)
|
elseif(${SHADER_EXT} STREQUAL .slg)
|
||||||
set(SHADER_TYPE geom)
|
set(SHADER_TYPE geom)
|
||||||
endif()
|
endif()
|
||||||
set(SHADER_TARGET ${SHADER_TARGET}_${SHADER_TYPE})
|
file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}")
|
||||||
|
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_TARGET}.${SHADER_TYPE}")
|
||||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}")
|
|
||||||
set(SHADER_TARGET_HEADER ${SHADER_TARGET}.h)
|
|
||||||
set(SHADER_TARGET_SOURCE ${SHADER_TARGET}.cpp)
|
|
||||||
set(SCRIBE_COMMAND scribe)
|
set(SCRIBE_COMMAND scribe)
|
||||||
|
|
||||||
# Target dependant Custom rule on the SHADER_FILE
|
# Target dependant Custom rule on the SHADER_FILE
|
||||||
|
@ -63,65 +66,232 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
||||||
else ()
|
else ()
|
||||||
set(GLPROFILE PC_GL)
|
set(GLPROFILE PC_GL)
|
||||||
endif()
|
endif()
|
||||||
set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
set(SCRIBE_ARGS -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE})
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE}
|
OUTPUT ${SHADER_TARGET}
|
||||||
COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS}
|
COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS}
|
||||||
DEPENDS ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES} ${SHADER_FILE}
|
DEPENDS ${SHADER_FILE} ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES}
|
||||||
)
|
)
|
||||||
|
|
||||||
#output the generated file name
|
#output the generated file name
|
||||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} PARENT_SCOPE)
|
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||||
|
|
||||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET_HEADER})
|
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
macro(AUTOSCRIBE_APPEND_SHADER_SOURCES)
|
||||||
|
if (NOT("${ARGN}" STREQUAL ""))
|
||||||
|
set_property(GLOBAL PROPERTY ${TARGET_NAME}_SHADER_SOURCES "${ARGN}")
|
||||||
|
global_append(GLOBAL_SHADER_LIBS ${TARGET_NAME})
|
||||||
|
global_append(GLOBAL_SHADER_SOURCES "${ARGN}")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
macro(AUTOSCRIBE_SHADER_LIB)
|
macro(AUTOSCRIBE_SHADER_LIB)
|
||||||
set(HIFI_LIBRARIES_SHADER_INCLUDE_FILES "")
|
unset(HIFI_LIBRARIES_SHADER_INCLUDE_FILES)
|
||||||
|
set(SRC_FOLDER "${CMAKE_SOURCE_DIR}/libraries/${TARGET_NAME}/src")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SHADER_INCLUDE_FILES ${SRC_FOLDER}/*.slh)
|
||||||
|
file(GLOB_RECURSE SHADER_VERTEX_FILES ${SRC_FOLDER}/*.slv)
|
||||||
|
file(GLOB_RECURSE SHADER_FRAGMENT_FILES ${SRC_FOLDER}/*.slf)
|
||||||
|
file(GLOB_RECURSE SHADER_GEOMETRY_FILES ${SRC_FOLDER}/*.slg)
|
||||||
|
file(GLOB_RECURSE SHADER_COMPUTE_FILES ${SRC_FOLDER}/*.slc)
|
||||||
|
|
||||||
|
unset(SHADER_SOURCE_FILES)
|
||||||
|
list(APPEND SHADER_SOURCE_FILES ${SHADER_VERTEX_FILES})
|
||||||
|
list(APPEND SHADER_SOURCE_FILES ${SHADER_FRAGMENT_FILES})
|
||||||
|
list(APPEND SHADER_SOURCE_FILES ${SHADER_GEOMETRY_FILES})
|
||||||
|
list(APPEND SHADER_SOURCE_FILES ${SHADER_COMPUTE_FILES})
|
||||||
|
|
||||||
|
unset(LOCAL_SHADER_SOURCES)
|
||||||
|
list(APPEND LOCAL_SHADER_SOURCES ${SHADER_SOURCE_FILES})
|
||||||
|
list(APPEND LOCAL_SHADER_SOURCES ${SHADER_INCLUDE_FILES})
|
||||||
|
|
||||||
|
AUTOSCRIBE_APPEND_SHADER_SOURCES(${LOCAL_SHADER_SOURCES})
|
||||||
|
|
||||||
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}")
|
||||||
foreach(HIFI_LIBRARY ${ARGN})
|
foreach(HIFI_LIBRARY ${ARGN})
|
||||||
#if (NOT TARGET ${HIFI_LIBRARY})
|
|
||||||
# file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}/src/)
|
|
||||||
#endif ()
|
|
||||||
|
|
||||||
#file(GLOB_RECURSE HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src/*.slh)
|
|
||||||
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
|
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src)
|
||||||
endforeach()
|
endforeach()
|
||||||
#message("${TARGET_NAME} ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES}")
|
endmacro()
|
||||||
|
|
||||||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
macro(AUTOSCRIBE_PROGRAM)
|
||||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf src/*.slg)
|
set(oneValueArgs NAME VERTEX FRAGMENT GEOMETRY COMPUTE)
|
||||||
|
cmake_parse_arguments(AUTOSCRIBE_PROGRAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
if (NOT (DEFINED AUTOSCRIBE_PROGRAM_NAME))
|
||||||
|
message(FATAL_ERROR "Programs must have a name and both a vertex and fragment shader")
|
||||||
|
endif()
|
||||||
|
if (NOT (DEFINED AUTOSCRIBE_PROGRAM_VERTEX))
|
||||||
|
set(AUTOSCRIBE_PROGRAM_VERTEX ${AUTOSCRIBE_PROGRAM_NAME})
|
||||||
|
endif()
|
||||||
|
if (NOT (DEFINED AUTOSCRIBE_PROGRAM_FRAGMENT))
|
||||||
|
set(AUTOSCRIBE_PROGRAM_FRAGMENT ${AUTOSCRIBE_PROGRAM_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
#make the shader folder
|
if (NOT (${AUTOSCRIBE_PROGRAM_VERTEX} MATCHES ".*::.*"))
|
||||||
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders/${TARGET_NAME}")
|
set(AUTOSCRIBE_PROGRAM_VERTEX "vertex::${AUTOSCRIBE_PROGRAM_VERTEX}")
|
||||||
file(MAKE_DIRECTORY ${SHADERS_DIR})
|
endif()
|
||||||
|
if (NOT (${AUTOSCRIBE_PROGRAM_FRAGMENT} MATCHES ".*::.*"))
|
||||||
|
set(AUTOSCRIBE_PROGRAM_FRAGMENT "fragment::${AUTOSCRIBE_PROGRAM_FRAGMENT}")
|
||||||
|
endif()
|
||||||
|
|
||||||
#message("${TARGET_NAME} ${SHADER_INCLUDE_FILES}")
|
unset(AUTOSCRIBE_PROGRAM_MAP)
|
||||||
set(AUTOSCRIBE_SHADER_SRC "")
|
list(APPEND AUTOSCRIBE_PROGRAM_MAP AUTOSCRIBE_PROGRAM_VERTEX)
|
||||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
list(APPEND AUTOSCRIBE_PROGRAM_MAP ${AUTOSCRIBE_PROGRAM_VERTEX})
|
||||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
list(APPEND AUTOSCRIBE_PROGRAM_MAP AUTOSCRIBE_PROGRAM_FRAGMENT)
|
||||||
|
list(APPEND AUTOSCRIBE_PROGRAM_MAP ${AUTOSCRIBE_PROGRAM_FRAGMENT})
|
||||||
|
global_append(${TARGET_NAME}_PROGRAMS ${AUTOSCRIBE_PROGRAM_NAME})
|
||||||
|
set_property(GLOBAL PROPERTY ${AUTOSCRIBE_PROGRAM_NAME} "${AUTOSCRIBE_PROGRAM_MAP}")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(unpack_map)
|
||||||
|
set(MAP_VAR "${ARGN}")
|
||||||
|
list(LENGTH MAP_VAR MAP_SIZE)
|
||||||
|
MATH(EXPR MAP_ENTRY_RANGE "(${MAP_SIZE} / 2) - 1")
|
||||||
|
foreach(INDEX RANGE ${MAP_ENTRY_RANGE})
|
||||||
|
MATH(EXPR INDEX_NAME "${INDEX} * 2")
|
||||||
|
MATH(EXPR INDEX_VAL "${INDEX_NAME} + 1")
|
||||||
|
list(GET MAP_VAR ${INDEX_NAME} VAR_NAME)
|
||||||
|
list(GET MAP_VAR ${INDEX_VAL} VAR_VAL)
|
||||||
|
set(${VAR_NAME} ${VAR_VAL})
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(PROCESS_SHADER_FILE)
|
||||||
|
AUTOSCRIBE_SHADER(${SHADER} ${ALL_SHADER_HEADERS} ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES})
|
||||||
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE)
|
||||||
set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON)
|
set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON)
|
||||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
source_group("Compiled/${SHADER_LIB}" FILES ${AUTOSCRIBE_GENERATED_FILE})
|
||||||
endforeach()
|
set(REFLECTED_SHADER "${AUTOSCRIBE_GENERATED_FILE}.json")
|
||||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
source_group("Reflected/${SHADER_LIB}" FILES ${REFLECTED_SHADER})
|
||||||
|
list(APPEND COMPILED_SHADERS ${AUTOSCRIBE_GENERATED_FILE})
|
||||||
if (WIN32)
|
get_filename_component(ENUM_NAME ${SHADER} NAME_WE)
|
||||||
source_group("Shaders" FILES ${SHADER_INCLUDE_FILES})
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${ENUM_NAME} = ${SHADER_COUNT},\n")
|
||||||
source_group("Shaders" FILES ${SHADER_SOURCE_FILES})
|
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
|
||||||
source_group("Shaders\\generated" FILES ${AUTOSCRIBE_SHADER_SRC})
|
endmacro()
|
||||||
endif()
|
|
||||||
|
macro(AUTOSCRIBE_SHADER_FINISH)
|
||||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_INCLUDE_FILES})
|
get_property(GLOBAL_SHADER_LIBS GLOBAL PROPERTY GLOBAL_SHADER_LIBS)
|
||||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_SOURCE_FILES})
|
list(REMOVE_DUPLICATES GLOBAL_SHADER_LIBS)
|
||||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_SRC})
|
set(SHADER_COUNT 0)
|
||||||
|
set(PROGRAM_COUNT 0)
|
||||||
# Link library shaders, if they exist
|
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders")
|
||||||
include_directories("${SHADERS_DIR}")
|
set(SHADER_ENUMS "")
|
||||||
|
file(MAKE_DIRECTORY ${SHADERS_DIR})
|
||||||
# Add search directory to find gpu/Shader.h
|
|
||||||
include_directories("${HIFI_LIBRARY_DIR}/gpu/src")
|
unset(COMPILED_SHADERS)
|
||||||
|
foreach(SHADER_LIB ${GLOBAL_SHADER_LIBS})
|
||||||
|
get_property(LIB_SHADER_SOURCES GLOBAL PROPERTY ${SHADER_LIB}_SHADER_SOURCES)
|
||||||
|
get_property(LIB_PROGRAMS GLOBAL PROPERTY ${SHADER_LIB}_PROGRAMS)
|
||||||
|
list(REMOVE_DUPLICATES LIB_SHADER_SOURCES)
|
||||||
|
string(REGEX REPLACE "[-]" "_" SHADER_NAMESPACE ${SHADER_LIB})
|
||||||
|
list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES "${CMAKE_SOURCE_DIR}/libraries/${SHADER_LIB}/src")
|
||||||
|
|
||||||
|
unset(VERTEX_SHADERS)
|
||||||
|
unset(FRAGMENT_SHADERS)
|
||||||
|
unset(SHADER_HEADERS)
|
||||||
|
|
||||||
|
foreach(SHADER_FILE ${LIB_SHADER_SOURCES})
|
||||||
|
if (SHADER_FILE MATCHES ".*\\.slv")
|
||||||
|
list(APPEND VERTEX_SHADERS ${SHADER_FILE})
|
||||||
|
elseif (SHADER_FILE MATCHES ".*\\.slf")
|
||||||
|
list(APPEND FRAGMENT_SHADERS ${SHADER_FILE})
|
||||||
|
elseif (SHADER_FILE MATCHES ".*\\.slh")
|
||||||
|
list(APPEND SHADER_HEADERS ${SHADER_FILE})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if (DEFINED SHADER_HEADERS)
|
||||||
|
list(REMOVE_DUPLICATES SHADER_HEADERS)
|
||||||
|
source_group("${SHADER_LIB}/Headers" FILES ${SHADER_HEADERS})
|
||||||
|
list(APPEND ALL_SHADER_HEADERS ${SHADER_HEADERS})
|
||||||
|
list(APPEND ALL_SCRIBE_SHADERS ${SHADER_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace ${SHADER_NAMESPACE} {\n")
|
||||||
|
if (DEFINED VERTEX_SHADERS)
|
||||||
|
list(REMOVE_DUPLICATES VERTEX_SHADERS)
|
||||||
|
source_group("${SHADER_LIB}/Vertex" FILES ${VERTEX_SHADERS})
|
||||||
|
list(APPEND ALL_SCRIBE_SHADERS ${VERTEX_SHADERS})
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace vertex { enum {\n")
|
||||||
|
foreach(SHADER ${VERTEX_SHADERS})
|
||||||
|
process_shader_file()
|
||||||
|
endforeach()
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // vertex \n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED FRAGMENT_SHADERS)
|
||||||
|
list(REMOVE_DUPLICATES FRAGMENT_SHADERS)
|
||||||
|
source_group("${SHADER_LIB}/Fragment" FILES ${FRAGMENT_SHADERS})
|
||||||
|
list(APPEND ALL_SCRIBE_SHADERS ${FRAGMENT_SHADERS})
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace fragment { enum {\n")
|
||||||
|
foreach(SHADER ${FRAGMENT_SHADERS})
|
||||||
|
process_shader_file()
|
||||||
|
endforeach()
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // fragment \n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED LIB_PROGRAMS)
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace program { enum {\n")
|
||||||
|
foreach(LIB_PROGRAM ${LIB_PROGRAMS})
|
||||||
|
get_property(LIB_PROGRAM_MAP GLOBAL PROPERTY ${LIB_PROGRAM})
|
||||||
|
unpack_map(${LIB_PROGRAM_MAP})
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${LIB_PROGRAM} = (${AUTOSCRIBE_PROGRAM_VERTEX} << 16) | ${AUTOSCRIBE_PROGRAM_FRAGMENT},\n")
|
||||||
|
MATH(EXPR PROGRAM_COUNT "${PROGRAM_COUNT}+1")
|
||||||
|
list(APPEND SHADER_ALL_PROGRAMS "${SHADER_NAMESPACE}::program::${LIB_PROGRAM}")
|
||||||
|
endforeach()
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "}; } // program \n")
|
||||||
|
endif()
|
||||||
|
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "} // namespace ${SHADER_NAMESPACE}\n")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(SHADER_PROGRAMS_ARRAY "")
|
||||||
|
foreach(SHADER_PROGRAM ${SHADER_ALL_PROGRAMS})
|
||||||
|
string(CONCAT SHADER_PROGRAMS_ARRAY "${SHADER_PROGRAMS_ARRAY}" " ${SHADER_PROGRAM},\n")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(SHREFLECT_COMMAND shreflect)
|
||||||
|
set(SHREFLECT_DEPENDENCY shreflect)
|
||||||
|
if (ANDROID)
|
||||||
|
set(SHREFLECT_COMMAND ${NATIVE_SHREFLECT})
|
||||||
|
unset(SHREFLECT_DEPENDENCY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(SHADER_COUNT 0)
|
||||||
|
foreach(COMPILED_SHADER ${COMPILED_SHADERS})
|
||||||
|
set(REFLECTED_SHADER "${COMPILED_SHADER}.json")
|
||||||
|
list(APPEND COMPILED_SHADER_REFLECTIONS ${REFLECTED_SHADER})
|
||||||
|
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}\">${COMPILED_SHADER}</file>\n")
|
||||||
|
string(CONCAT SHADER_QRC "${SHADER_QRC}" "<file alias=\"${SHADER_COUNT}_reflection\">${REFLECTED_SHADER}</file>\n")
|
||||||
|
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${REFLECTED_SHADER}
|
||||||
|
COMMAND ${SHREFLECT_COMMAND} ${COMPILED_SHADER}
|
||||||
|
DEPENDS ${SHREFLECT_DEPENDENCY} ${COMPILED_SHADER}
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# 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 ${COMPILED_SHADER_REFLECTIONS})
|
||||||
|
set_target_properties(scribe_shaders PROPERTIES FOLDER "Shaders")
|
||||||
|
set_target_properties(compiled_shaders PROPERTIES FOLDER "Shaders")
|
||||||
|
set_target_properties(reflected_shaders PROPERTIES FOLDER "Shaders")
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
ShaderEnums.cpp.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/shaders/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
|
||||||
|
)
|
||||||
|
set(AUTOSCRIBE_SHADER_LIB_SRC "${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h;${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp")
|
||||||
|
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${COMPILED_SHADERS})
|
||||||
|
set(QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc)
|
||||||
|
get_property(GLOBAL_SHADER_SOURCES GLOBAL PROPERTY GLOBAL_SHADER_SOURCES)
|
||||||
|
list(REMOVE_DUPLICATES GLOBAL_SHADER_SOURCES)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
|
@ -19,12 +19,8 @@ function(LINK_HIFI_LIBRARIES)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||||
|
|
||||||
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
||||||
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}/shaders")
|
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}")
|
||||||
|
|
||||||
#add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
|
|
||||||
|
|
||||||
# link the actual library - it is static so don't bubble it up
|
# link the actual library - it is static so don't bubble it up
|
||||||
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
|
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
13
cmake/macros/TargetJson.cmake
Normal file
13
cmake/macros/TargetJson.cmake
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#
|
||||||
|
# Created by Bradley Austin Davis on 2018/07/22
|
||||||
|
# Copyright 2013-2018 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
|
||||||
|
#
|
||||||
|
macro(TARGET_JSON)
|
||||||
|
add_dependency_external_projects(json)
|
||||||
|
find_package(JSON REQUIRED)
|
||||||
|
message("JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIRS}")
|
||||||
|
target_include_directories(${TARGET_NAME} PUBLIC ${JSON_INCLUDE_DIRS})
|
||||||
|
endmacro()
|
19
cmake/modules/FindJSON.cmake
Normal file
19
cmake/modules/FindJSON.cmake
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#
|
||||||
|
# Created by Bradley Austin Davis on 2018/07/22
|
||||||
|
# Copyright 2013-2018 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
|
||||||
|
#
|
||||||
|
|
||||||
|
# setup hints for JSON search
|
||||||
|
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
|
||||||
|
hifi_library_search_hints("json")
|
||||||
|
|
||||||
|
# locate header
|
||||||
|
find_path(JSON_INCLUDE_DIRS "json/json.hpp" HINTS ${JSON_SEARCH_DIRS})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(JSON DEFAULT_MSG JSON_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
mark_as_advanced(JSON_INCLUDE_DIRS JSON_SEARCH_DIRS)
|
|
@ -46,6 +46,14 @@
|
||||||
"default": "40102",
|
"default": "40102",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"advanced": true
|
"advanced": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "enable_packet_verification",
|
||||||
|
"label": "Enable Packet Verification",
|
||||||
|
"help": "Enable secure checksums on communication that uses the High Fidelity protocol. Increases security with possibly a small performance penalty.",
|
||||||
|
"default": true,
|
||||||
|
"type": "checkbox",
|
||||||
|
"advanced": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -630,6 +630,7 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) {
|
||||||
|
|
||||||
void DomainServer::setupNodeListAndAssignments() {
|
void DomainServer::setupNodeListAndAssignments() {
|
||||||
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
||||||
|
static const QString ENABLE_PACKET_AUTHENTICATION = "metaverse.enable_packet_verification";
|
||||||
|
|
||||||
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
||||||
int domainServerPort = localPortValue.toInt();
|
int domainServerPort = localPortValue.toInt();
|
||||||
|
@ -696,6 +697,9 @@ void DomainServer::setupNodeListAndAssignments() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isAuthEnabled = _settingsManager.valueOrDefaultValueForKeyPath(ENABLE_PACKET_AUTHENTICATION).toBool();
|
||||||
|
nodeList->setAuthenticatePackets(isAuthEnabled);
|
||||||
|
|
||||||
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
||||||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
||||||
|
|
||||||
|
@ -1133,7 +1137,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
||||||
extendedHeaderStream << node->getUUID();
|
extendedHeaderStream << node->getUUID();
|
||||||
extendedHeaderStream << node->getLocalID();
|
extendedHeaderStream << node->getLocalID();
|
||||||
extendedHeaderStream << node->getPermissions();
|
extendedHeaderStream << node->getPermissions();
|
||||||
|
extendedHeaderStream << limitedNodeList->getAuthenticatePackets();
|
||||||
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
||||||
|
|
||||||
// always send the node their own UUID back
|
// always send the node their own UUID back
|
||||||
|
|
|
@ -214,6 +214,7 @@ link_hifi_libraries(
|
||||||
controllers plugins image trackers
|
controllers plugins image trackers
|
||||||
ui-plugins display-plugins input-plugins
|
ui-plugins display-plugins input-plugins
|
||||||
${PLATFORM_GL_BACKEND}
|
${PLATFORM_GL_BACKEND}
|
||||||
|
shaders
|
||||||
)
|
)
|
||||||
|
|
||||||
# include the binary directory of render-utils for shader includes
|
# include the binary directory of render-utils for shader includes
|
||||||
|
|
|
@ -62,6 +62,7 @@ Windows.ScrollingWindow {
|
||||||
url: "about:blank"
|
url: "about:blank"
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
|
profile: HFWebEngineProfile;
|
||||||
|
|
||||||
property string userScriptUrl: ""
|
property string userScriptUrl: ""
|
||||||
|
|
||||||
|
|
|
@ -299,7 +299,7 @@ Item {
|
||||||
anchors.fill: stackView
|
anchors.fill: stackView
|
||||||
id: controllerPrefereneces
|
id: controllerPrefereneces
|
||||||
objectName: "TabletControllerPreferences"
|
objectName: "TabletControllerPreferences"
|
||||||
showCategories: [( (HMD.active) ? "VR Movement" : "Movement"), "Game Controller", "Sixense Controllers", "Perception Neuron", "Leap Motion"]
|
showCategories: ["VR Movement", "Game Controller", "Sixense Controllers", "Perception Neuron", "Leap Motion"]
|
||||||
categoryProperties: {
|
categoryProperties: {
|
||||||
"VR Movement" : {
|
"VR Movement" : {
|
||||||
"User real-world height (meters)" : { "anchors.right" : "undefined" },
|
"User real-world height (meters)" : { "anchors.right" : "undefined" },
|
||||||
|
|
|
@ -2703,8 +2703,6 @@ void Application::initializeGL() {
|
||||||
// contexts
|
// contexts
|
||||||
_glWidget->makeCurrent();
|
_glWidget->makeCurrent();
|
||||||
gpu::Context::init<gpu::gl::GLBackend>();
|
gpu::Context::init<gpu::gl::GLBackend>();
|
||||||
qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK,
|
|
||||||
QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram)));
|
|
||||||
_glWidget->makeCurrent();
|
_glWidget->makeCurrent();
|
||||||
_gpuContext = std::make_shared<gpu::Context>();
|
_gpuContext = std::make_shared<gpu::Context>();
|
||||||
|
|
||||||
|
@ -4574,11 +4572,14 @@ void Application::idle() {
|
||||||
_lastTimeUpdated.start();
|
_lastTimeUpdated.start();
|
||||||
|
|
||||||
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
|
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
|
||||||
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
|
if (offscreenUi && offscreenUi->getWindow()) {
|
||||||
_keyboardMouseDevice->pluginFocusOutEvent();
|
auto activeFocusItem = offscreenUi->getWindow()->activeFocusItem();
|
||||||
_keyboardDeviceHasFocus = false;
|
if (_keyboardDeviceHasFocus && activeFocusItem != offscreenUi->getRootItem()) {
|
||||||
} else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) {
|
_keyboardMouseDevice->pluginFocusOutEvent();
|
||||||
_keyboardDeviceHasFocus = true;
|
_keyboardDeviceHasFocus = false;
|
||||||
|
} else if (activeFocusItem == offscreenUi->getRootItem()) {
|
||||||
|
_keyboardDeviceHasFocus = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkChangeCursor();
|
checkChangeCursor();
|
||||||
|
@ -6619,11 +6620,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
||||||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||||
LocationScriptingInterface::locationSetter);
|
LocationScriptingInterface::locationSetter);
|
||||||
|
|
||||||
|
bool clientScript = scriptEngine->isClientScript();
|
||||||
|
scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor);
|
||||||
#if !defined(Q_OS_ANDROID)
|
#if !defined(Q_OS_ANDROID)
|
||||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor);
|
||||||
#endif
|
#endif
|
||||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
scriptEngine->registerFunction("QmlFragment", clientScript ? QmlFragmentClass::constructor : QmlFragmentClass::restricted_constructor);
|
||||||
scriptEngine->registerFunction("QmlFragment", QmlFragmentClass::constructor);
|
|
||||||
|
|
||||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||||
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
|
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
|
||||||
|
|
|
@ -412,9 +412,6 @@ void AvatarManager::clearOtherAvatars() {
|
||||||
while (avatarIterator != _avatarHash.end()) {
|
while (avatarIterator != _avatarHash.end()) {
|
||||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
||||||
if (avatar != _myAvatar) {
|
if (avatar != _myAvatar) {
|
||||||
if (avatar->isInScene()) {
|
|
||||||
avatar->removeFromScene(avatar, scene, transaction);
|
|
||||||
}
|
|
||||||
handleRemovedAvatar(avatar);
|
handleRemovedAvatar(avatar);
|
||||||
avatarIterator = _avatarHash.erase(avatarIterator);
|
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1135,7 +1135,6 @@ void MyAvatar::saveData() {
|
||||||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||||
settings.setValue("userHeight", getUserHeight());
|
settings.setValue("userHeight", getUserHeight());
|
||||||
settings.setValue("flyingDesktop", getFlyingDesktopPref());
|
|
||||||
settings.setValue("flyingHMD", getFlyingHMDPref());
|
settings.setValue("flyingHMD", getFlyingHMDPref());
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
@ -1289,7 +1288,6 @@ void MyAvatar::loadData() {
|
||||||
|
|
||||||
// Flying preferences must be loaded before calling setFlyingEnabled()
|
// Flying preferences must be loaded before calling setFlyingEnabled()
|
||||||
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
||||||
setFlyingDesktopPref(firstRunVal.get() ? true : settings.value("flyingDesktop").toBool());
|
|
||||||
setFlyingHMDPref(firstRunVal.get() ? false : settings.value("flyingHMD").toBool());
|
setFlyingHMDPref(firstRunVal.get() ? false : settings.value("flyingHMD").toBool());
|
||||||
setFlyingEnabled(getFlyingEnabled());
|
setFlyingEnabled(getFlyingEnabled());
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,9 @@
|
||||||
#include <StencilMaskPass.h>
|
#include <StencilMaskPass.h>
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
#include "ParabolaPick.h"
|
#include "ParabolaPick.h"
|
||||||
|
|
||||||
#include "render-utils/parabola_vert.h"
|
|
||||||
#include "render-utils/parabola_frag.h"
|
|
||||||
|
|
||||||
const glm::vec4 ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_COLOR { 1.0f };
|
const glm::vec4 ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_COLOR { 1.0f };
|
||||||
const float ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_WIDTH { 0.01f };
|
const float ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_WIDTH { 0.01f };
|
||||||
const bool ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_ISVISIBLEINSECONDARYCAMERA { false };
|
const bool ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_ISVISIBLEINSECONDARYCAMERA { false };
|
||||||
|
@ -367,13 +365,7 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
|
||||||
|
|
||||||
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
|
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
|
||||||
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
|
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
|
||||||
auto vs = parabola_vert::getShader();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
|
||||||
auto ps = parabola_frag::getShader();
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("parabolaData"), 0));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* The Audio API features tools to help control audio contexts and settings.
|
* The <code>Audio</code> API provides facilities to interact with audio inputs and outputs and to play sounds.
|
||||||
*
|
*
|
||||||
* @namespace Audio
|
* @namespace Audio
|
||||||
*
|
*
|
||||||
|
@ -35,14 +35,23 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
* @hifi-server-entity
|
* @hifi-server-entity
|
||||||
* @hifi-assignment-client
|
* @hifi-assignment-client
|
||||||
*
|
*
|
||||||
* @property {boolean} muted
|
* @property {boolean} muted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||||
* @property {boolean} noiseReduction
|
* @property {boolean} noiseReduction - <code>true</code> if noise reduction is enabled, otherwise <code>false</code>. When
|
||||||
* @property {number} inputVolume
|
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
||||||
* @property {number} inputLevel <em>Read-only.</em>
|
* above the noise floor.
|
||||||
* @property {string} context <em>Read-only.</em>
|
* @property {number} inputLevel - The loudness of the audio input, range <code>0.0</code> (no sound) –
|
||||||
* @property {} devices <em>Read-only.</em>
|
* <code>1.0</code> (the onset of clipping). <em>Read-only.</em>
|
||||||
|
* @property {number} inputVolume - Adjusts the volume of the input audio; range <code>0.0</code> – <code>1.0</code>.
|
||||||
|
* If set to a value, the resulting value depends on the input device: for example, the volume can't be changed on some
|
||||||
|
* devices, and others might only support values of <code>0.0</code> and <code>1.0</code>.
|
||||||
|
* @property {boolean} isStereoInput - <code>true</code> if the input audio is being used in stereo, otherwise
|
||||||
|
* <code>false</code>. Some devices do not support stereo, in which case the value is always <code>false</code>.
|
||||||
|
* @property {string} context - The current context of the audio: either <code>"Desktop"</code> or <code>"HMD"</code>.
|
||||||
|
* <em>Read-only.</em>
|
||||||
|
* @property {object} devices <em>Read-only.</em> <strong>Deprecated:</strong> This property is deprecated and will be
|
||||||
|
* removed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
||||||
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
||||||
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
||||||
|
@ -69,45 +78,91 @@ public:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function Audio.setInputDevice
|
* @function Audio.setInputDevice
|
||||||
* @param {} device
|
* @param {object} device
|
||||||
* @param {boolean} isHMD
|
* @param {boolean} isHMD
|
||||||
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function Audio.setOutputDevice
|
* @function Audio.setOutputDevice
|
||||||
* @param {} device
|
* @param {object} device
|
||||||
* @param {boolean} isHMD
|
* @param {boolean} isHMD
|
||||||
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Enable or disable reverberation. Reverberation is done by the client, on the post-mix audio. The reverberation options
|
||||||
|
* come from either the domain's audio zone if used — configured on the server — or as scripted by
|
||||||
|
* {@link Audio.setReverbOptions|setReverbOptions}.
|
||||||
* @function Audio.setReverb
|
* @function Audio.setReverb
|
||||||
* @param {boolean} enable
|
* @param {boolean} enable - <code>true</code> to enable reverberation, <code>false</code> to disable.
|
||||||
*/
|
* @example <caption>Enable reverberation for a short while.</caption>
|
||||||
|
* var sound = SoundCache.getSound(Script.resourcesPath() + "sounds/sample.wav");
|
||||||
|
* var injector;
|
||||||
|
* var injectorOptions = {
|
||||||
|
* position: MyAvatar.position
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Script.setTimeout(function () {
|
||||||
|
* print("Reverb OFF");
|
||||||
|
* Audio.setReverb(false);
|
||||||
|
* injector = Audio.playSound(sound, injectorOptions);
|
||||||
|
* }, 1000);
|
||||||
|
*
|
||||||
|
* Script.setTimeout(function () {
|
||||||
|
* var reverbOptions = new AudioEffectOptions();
|
||||||
|
* reverbOptions.roomSize = 100;
|
||||||
|
* Audio.setReverbOptions(reverbOptions);
|
||||||
|
* print("Reverb ON");
|
||||||
|
* Audio.setReverb(true);
|
||||||
|
* }, 4000);
|
||||||
|
*
|
||||||
|
* Script.setTimeout(function () {
|
||||||
|
* print("Reverb OFF");
|
||||||
|
* Audio.setReverb(false);
|
||||||
|
* }, 8000); */
|
||||||
Q_INVOKABLE void setReverb(bool enable);
|
Q_INVOKABLE void setReverb(bool enable);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Configure reverberation options. Use {@link Audio.setReverb|setReverb} to enable or disable reverberation.
|
||||||
* @function Audio.setReverbOptions
|
* @function Audio.setReverbOptions
|
||||||
* @param {AudioEffectOptions} options
|
* @param {AudioEffectOptions} options - The reverberation options.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options);
|
Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format.
|
||||||
* @function Audio.startRecording
|
* @function Audio.startRecording
|
||||||
* @param {string} filename
|
* @param {string} filename - The path and name of the file to make the recording in. Should have a <code>.wav</code>
|
||||||
* @returns {boolean}
|
* extension. The file is overwritten if it already exists.
|
||||||
|
* @returns {boolean} <code>true</code> if the specified file could be opened and audio recording has started, otherwise
|
||||||
|
* <code>false</code>.
|
||||||
|
* @example <caption>Make a 10 second audio recording.</caption>
|
||||||
|
* var filename = File.getTempDir() + "/audio.wav";
|
||||||
|
* if (Audio.startRecording(filename)) {
|
||||||
|
* Script.setTimeout(function () {
|
||||||
|
* Audio.stopRecording();
|
||||||
|
* print("Audio recording made in: " + filename);
|
||||||
|
* }, 10000);
|
||||||
|
*
|
||||||
|
* } else {
|
||||||
|
* print("Could not make an audio recording in: " + filename);
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE bool startRecording(const QString& filename);
|
Q_INVOKABLE bool startRecording(const QString& filename);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Finish making an audio recording started with {@link Audio.startRecording|startRecording}.
|
||||||
* @function Audio.stopRecording
|
* @function Audio.stopRecording
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE void stopRecording();
|
Q_INVOKABLE void stopRecording();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Check whether an audio recording is currently being made.
|
||||||
* @function Audio.getRecording
|
* @function Audio.getRecording
|
||||||
* @returns {boolean}
|
* @returns {boolean} <code>true</code> if an audio recording is currently being made, otherwise <code>false</code>.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE bool getRecording();
|
Q_INVOKABLE bool getRecording();
|
||||||
|
|
||||||
|
@ -116,40 +171,54 @@ signals:
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function Audio.nop
|
* @function Audio.nop
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
|
* @deprecated This signal is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
void nop();
|
void nop();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Triggered when the audio input is muted or unmuted.
|
||||||
* @function Audio.mutedChanged
|
* @function Audio.mutedChanged
|
||||||
* @param {boolean} isMuted
|
* @param {boolean} isMuted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
|
* @example <caption>Report when audio input is muted or unmuted</caption>
|
||||||
|
* Audio.mutedChanged.connect(function (isMuted) {
|
||||||
|
* print("Audio muted: " + isMuted);
|
||||||
|
* });
|
||||||
*/
|
*/
|
||||||
void mutedChanged(bool isMuted);
|
void mutedChanged(bool isMuted);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Triggered when the audio input noise reduction is enabled or disabled.
|
||||||
* @function Audio.noiseReductionChanged
|
* @function Audio.noiseReductionChanged
|
||||||
* @param {boolean} isEnabled
|
* @param {boolean} isEnabled - <code>true</code> if audio input noise reduction is enabled, otherwise <code>false</code>.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
*/
|
*/
|
||||||
void noiseReductionChanged(bool isEnabled);
|
void noiseReductionChanged(bool isEnabled);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Triggered when the input audio volume changes.
|
||||||
* @function Audio.inputVolumeChanged
|
* @function Audio.inputVolumeChanged
|
||||||
* @param {number} volume
|
* @param {number} volume - The requested volume to be applied to the audio input, range <code>0.0</code> –
|
||||||
|
* <code>1.0</code>. The resulting value of <code>Audio.inputVolume</code> depends on the capabilities of the device:
|
||||||
|
* for example, the volume can't be changed on some devices, and others might only support values of <code>0.0</code>
|
||||||
|
* and <code>1.0</code>.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
*/
|
*/
|
||||||
void inputVolumeChanged(float volume);
|
void inputVolumeChanged(float volume);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Triggered when the input audio level changes.
|
||||||
* @function Audio.inputLevelChanged
|
* @function Audio.inputLevelChanged
|
||||||
* @param {number} level
|
* @param {number} level - The loudness of the input audio, range <code>0.0</code> (no sound) – <code>1.0</code> (the
|
||||||
|
* onset of clipping).
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
*/
|
*/
|
||||||
void inputLevelChanged(float level);
|
void inputLevelChanged(float level);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Triggered when the current context of the audio changes.
|
||||||
* @function Audio.contextChanged
|
* @function Audio.contextChanged
|
||||||
* @param {string} context
|
* @param {string} context - The current context of the audio: either <code>"Desktop"</code> or <code>"HMD"</code>.
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
*/
|
*/
|
||||||
void contextChanged(const QString& context);
|
void contextChanged(const QString& context);
|
||||||
|
@ -158,7 +227,7 @@ public slots:
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @function Audio.onContextChanged
|
* @function Audio.onContextChanged
|
||||||
* @returns {Signal}
|
* @deprecated This function is deprecated and will be removed.
|
||||||
*/
|
*/
|
||||||
void onContextChanged();
|
void onContextChanged();
|
||||||
|
|
||||||
|
|
|
@ -266,42 +266,6 @@ void setupPreferences() {
|
||||||
preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Deflection", getter, setter));
|
preferences->addPreference(new SliderPreference(FACE_TRACKING, "Eye Deflection", getter, setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString MOVEMENT{ "Movement" };
|
|
||||||
{
|
|
||||||
|
|
||||||
static const QString movementsControlChannel = QStringLiteral("Hifi-Advanced-Movement-Disabler");
|
|
||||||
auto getter = [=]()->bool { return myAvatar->useAdvancedMovementControls(); };
|
|
||||||
auto setter = [=](bool value) { myAvatar->setUseAdvancedMovementControls(value); };
|
|
||||||
preferences->addPreference(new CheckPreference(MOVEMENT,
|
|
||||||
QStringLiteral("Advanced movement for hand controllers"),
|
|
||||||
getter, setter));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
|
|
||||||
auto setter = [=](int value) { myAvatar->setSnapTurn(value == 0); };
|
|
||||||
auto preference = new RadioButtonsPreference(MOVEMENT, "Snap turn / Smooth turn", getter, setter);
|
|
||||||
QStringList items;
|
|
||||||
items << "Snap turn" << "Smooth turn";
|
|
||||||
preference->setItems(items);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto getter = [=]()->float { return myAvatar->getUserHeight(); };
|
|
||||||
auto setter = [=](float value) { myAvatar->setUserHeight(value); };
|
|
||||||
auto preference = new SpinnerPreference(MOVEMENT, "User real-world height (meters)", getter, setter);
|
|
||||||
preference->setMin(1.0f);
|
|
||||||
preference->setMax(2.2f);
|
|
||||||
preference->setDecimals(3);
|
|
||||||
preference->setStep(0.001f);
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto preference = new ButtonPreference(MOVEMENT, "RESET SENSORS", [] {
|
|
||||||
qApp->resetSensors();
|
|
||||||
});
|
|
||||||
preferences->addPreference(preference);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const QString VR_MOVEMENT{ "VR Movement" };
|
static const QString VR_MOVEMENT{ "VR Movement" };
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -315,7 +279,7 @@ void setupPreferences() {
|
||||||
{
|
{
|
||||||
auto getter = [=]()->bool { return myAvatar->getFlyingHMDPref(); };
|
auto getter = [=]()->bool { return myAvatar->getFlyingHMDPref(); };
|
||||||
auto setter = [=](bool value) { myAvatar->setFlyingHMDPref(value); };
|
auto setter = [=](bool value) { myAvatar->setFlyingHMDPref(value); };
|
||||||
preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping", getter, setter));
|
preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping (HMD)", getter, setter));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
|
auto getter = [=]()->int { return myAvatar->getSnapTurn() ? 0 : 1; };
|
||||||
|
|
|
@ -14,11 +14,7 @@
|
||||||
|
|
||||||
#include <StencilMaskPass.h>
|
#include <StencilMaskPass.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
#include "render-utils/drawWorkloadProxy_vert.h"
|
|
||||||
#include "render-utils/drawWorkloadView_vert.h"
|
|
||||||
#include "render-utils/drawWorkloadProxy_frag.h"
|
|
||||||
#include "render-utils/drawWorkloadView_frag.h"
|
|
||||||
|
|
||||||
|
|
||||||
void GameSpaceToRender::configure(const Config& config) {
|
void GameSpaceToRender::configure(const Config& config) {
|
||||||
|
@ -149,14 +145,7 @@ void GameWorkloadRenderItem::setAllViews(const workload::Views& views) {
|
||||||
|
|
||||||
const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
|
const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
|
||||||
if (!_drawAllProxiesPipeline) {
|
if (!_drawAllProxiesPipeline) {
|
||||||
auto vs = drawWorkloadProxy_vert::getShader();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadProxy);
|
||||||
auto ps = drawWorkloadProxy_frag::getShader();
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding("workloadProxiesBuffer", 0));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
/* state->setBlendFunction(true,
|
/* state->setBlendFunction(true,
|
||||||
|
@ -173,15 +162,7 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
|
||||||
|
|
||||||
const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
|
const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
|
||||||
if (!_drawAllViewsPipeline) {
|
if (!_drawAllViewsPipeline) {
|
||||||
auto vs = drawWorkloadView_vert::getShader();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadView);
|
||||||
auto ps = drawWorkloadView_frag::getShader();
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding("workloadViewsBuffer", 1));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding("drawMeshBuffer", 0));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
/* state->setBlendFunction(true,
|
/* state->setBlendFunction(true,
|
||||||
|
@ -192,6 +173,7 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
|
||||||
state->setCullMode(gpu::State::CULL_NONE);
|
state->setCullMode(gpu::State::CULL_NONE);
|
||||||
_drawAllViewsPipeline = gpu::Pipeline::create(program, state);
|
_drawAllViewsPipeline = gpu::Pipeline::create(program, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _drawAllViewsPipeline;
|
return _drawAllViewsPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1547,16 +1547,18 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
||||||
glm::vec3 backVector = oppositeArmPose.trans() - armPose.trans();
|
glm::vec3 backVector = oppositeArmPose.trans() - armPose.trans();
|
||||||
glm::vec3 backCenter = armPose.trans() + 0.5f * backVector;
|
glm::vec3 backCenter = armPose.trans() + 0.5f * backVector;
|
||||||
|
|
||||||
const float OVER_BACK_HEAD_PERCENTAGE = 0.2f;
|
glm::vec3 frontVector = glm::normalize(glm::cross(backVector, Vectors::UNIT_Y));
|
||||||
|
glm::vec3 topVector = glm::normalize(glm::cross(frontVector, backVector));
|
||||||
|
|
||||||
|
glm::vec3 centerToHand = handPose.trans() - backCenter;
|
||||||
|
glm::vec3 headCenter = backCenter + glm::length(backVector) * topVector;
|
||||||
|
|
||||||
glm::vec3 headCenter = backCenter + glm::vec3(0, OVER_BACK_HEAD_PERCENTAGE * backVector.length(), 0);
|
|
||||||
glm::vec3 frontVector = glm::normalize(glm::cross(backVector, glm::vec3(0, 1, 0)));
|
|
||||||
// Make sure is pointing forward
|
// Make sure is pointing forward
|
||||||
frontVector = frontVector.z < 0 ? -frontVector : frontVector;
|
frontVector = frontVector.z < 0 ? -frontVector : frontVector;
|
||||||
|
|
||||||
float horizontalModule = glm::dot(armToHand, glm::vec3(0, -1, 0));
|
float horizontalModule = glm::dot(centerToHand, -topVector);
|
||||||
glm::vec3 headForward = headCenter + horizontalModule * frontVector;
|
|
||||||
|
|
||||||
|
glm::vec3 headForward = headCenter + glm::max(0.0f, horizontalModule) * frontVector;
|
||||||
glm::vec3 armToHead = headForward - armPose.trans();
|
glm::vec3 armToHead = headForward - armPose.trans();
|
||||||
|
|
||||||
float armToHandDistance = glm::length(armToHand);
|
float armToHandDistance = glm::length(armToHand);
|
||||||
|
@ -1570,8 +1572,10 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
||||||
// How much the hand is reaching for the opposite side
|
// How much the hand is reaching for the opposite side
|
||||||
float oppositeProjection = glm::dot(armToHandDir, glm::normalize(backVector));
|
float oppositeProjection = glm::dot(armToHandDir, glm::normalize(backVector));
|
||||||
|
|
||||||
// Don't use pole vector when the hands are behind
|
bool isCrossed = glm::dot(centerToHand, backVector) > 0;
|
||||||
if (glm::dot(frontVector, armToHand) < 0 && oppositeProjection < 0.5f * armTotalDistance) {
|
bool isBehind = glm::dot(frontVector, armToHand) < 0;
|
||||||
|
// Don't use pole vector when the hands are behind the back and the arms are not crossed
|
||||||
|
if (isBehind && !isCrossed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1585,7 +1589,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
||||||
glm::vec3 correctionVector = glm::vec3(0, 0, 0);
|
glm::vec3 correctionVector = glm::vec3(0, 0, 0);
|
||||||
|
|
||||||
const float FORWARD_TRIGGER_PERCENTAGE = 0.2f;
|
const float FORWARD_TRIGGER_PERCENTAGE = 0.2f;
|
||||||
const float FORWARD_CORRECTOR_WEIGHT = 3.0f;
|
const float FORWARD_CORRECTOR_WEIGHT = 2.3f;
|
||||||
|
|
||||||
float elbowForwardTrigger = FORWARD_TRIGGER_PERCENTAGE * armToHandDistance;
|
float elbowForwardTrigger = FORWARD_TRIGGER_PERCENTAGE * armToHandDistance;
|
||||||
|
|
||||||
|
|
|
@ -59,28 +59,29 @@ static void setOption(QScriptValue arguments, const QString name, float defaultV
|
||||||
}
|
}
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Reverberation options that can be used to initialize an {@link AudioEffectOptions} object when created.
|
||||||
* @typedef {object} AudioEffectOptions.ReverbOptions
|
* @typedef {object} AudioEffectOptions.ReverbOptions
|
||||||
* @property {number} bandwidth
|
* @property {number} bandwidth=10000 - The corner frequency (Hz) of the low-pass filter at reverb input.
|
||||||
* @property {number} preDelay
|
* @property {number} preDelay=20 - The delay (milliseconds) between dry signal and the onset of early reflections.
|
||||||
* @property {number} lateDelay
|
* @property {number} lateDelay=0 - The delay (milliseconds) between early reflections and the onset of reverb tail.
|
||||||
* @property {number} reverbTime
|
* @property {number} reverbTime=2 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
|
||||||
* @property {number} earlyDiffusion
|
* @property {number} earlyDiffusion=100 - Adjusts the buildup of echo density in the early reflections, normally 100%.
|
||||||
* @property {number} lateDiffusion
|
* @property {number} lateDiffusion=100 - Adjusts the buildup of echo density in the reverb tail, normally 100%.
|
||||||
* @property {number} roomSize
|
* @property {number} roomSize=50 - The apparent room size, from small (0%) to large (100%).
|
||||||
* @property {number} density
|
* @property {number} density=100 - Adjusts the echo density in the reverb tail, normally 100%.
|
||||||
* @property {number} bassMult
|
* @property {number} bassMult=1.5 - Adjusts the bass-frequency reverb time, as multiple of reverbTime.
|
||||||
* @property {number} bassFreq
|
* @property {number} bassFreq=250 - The crossover frequency (Hz) for the onset of bassMult.
|
||||||
* @property {number} highGain
|
* @property {number} highGain=-6 - Reduces the high-frequency reverb time, as attenuation (dB).
|
||||||
* @property {number} highFreq
|
* @property {number} highFreq=3000 - The crossover frequency (Hz) for the onset of highGain.
|
||||||
* @property {number} modRate
|
* @property {number} modRate=2.3 - The rate of modulation (Hz) of the LFO-modulated delay lines.
|
||||||
* @property {number} modDepth
|
* @property {number} modDepth=50 - The depth of modulation (percent) of the LFO-modulated delay lines.
|
||||||
* @property {number} earlyGain
|
* @property {number} earlyGain=0 - Adjusts the relative level (dB) of the early reflections.
|
||||||
* @property {number} lateGain
|
* @property {number} lateGain=0 - Adjusts the relative level (dB) of the reverb tail.
|
||||||
* @property {number} earlyMixLeft
|
* @property {number} earlyMixLeft=20 - The apparent distance of the source (percent) in the early reflections.
|
||||||
* @property {number} earlyMixRight
|
* @property {number} earlyMixRight=20 - The apparent distance of the source (percent) in the early reflections.
|
||||||
* @property {number} lateMixLeft
|
* @property {number} lateMixLeft=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||||
* @property {number} lateMixRight
|
* @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||||
* @property {number} wetDryMix
|
* @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%).
|
||||||
*/
|
*/
|
||||||
AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) {
|
AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) {
|
||||||
setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth);
|
setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth);
|
||||||
|
|
|
@ -16,35 +16,39 @@
|
||||||
#include <QtScript/QScriptEngine>
|
#include <QtScript/QScriptEngine>
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Audio effect options used by the {@link Audio} API.
|
||||||
|
*
|
||||||
|
* <p>Create using <code>new AudioEffectOptions(reverbOptions)</code>.</p>
|
||||||
|
*
|
||||||
* @class AudioEffectOptions
|
* @class AudioEffectOptions
|
||||||
* @param {AudioEffectOptions.ReverbOptions} [reverbOptions=null]
|
* @param {AudioEffectOptions.ReverbOptions} [reverbOptions=null] - Reverberation options.
|
||||||
*
|
*
|
||||||
* @hifi-interface
|
* @hifi-interface
|
||||||
* @hifi-client-entity
|
* @hifi-client-entity
|
||||||
* @hifi-server-entity
|
* @hifi-server-entity
|
||||||
* @hifi-assignment-client
|
* @hifi-assignment-client
|
||||||
*
|
*
|
||||||
* @property {number} bandwidth=10000
|
* @property {number} bandwidth=10000 - The corner frequency (Hz) of the low-pass filter at reverb input.
|
||||||
* @property {number} preDelay=20
|
* @property {number} preDelay=20 - The delay (milliseconds) between dry signal and the onset of early reflections.
|
||||||
* @property {number} lateDelay=0
|
* @property {number} lateDelay=0 - The delay (milliseconds) between early reflections and the onset of reverb tail.
|
||||||
* @property {number} reverbTime=2
|
* @property {number} reverbTime=2 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
|
||||||
* @property {number} earlyDiffusion=100
|
* @property {number} earlyDiffusion=100 - Adjusts the buildup of echo density in the early reflections, normally 100%.
|
||||||
* @property {number} lateDiffusion=100
|
* @property {number} lateDiffusion=100 - Adjusts the buildup of echo density in the reverb tail, normally 100%.
|
||||||
* @property {number} roomSize=50
|
* @property {number} roomSize=50 - The apparent room size, from small (0%) to large (100%).
|
||||||
* @property {number} density=100
|
* @property {number} density=100 - Adjusts the echo density in the reverb tail, normally 100%.
|
||||||
* @property {number} bassMult=1.5
|
* @property {number} bassMult=1.5 - Adjusts the bass-frequency reverb time, as multiple of reverbTime.
|
||||||
* @property {number} bassFreq=250
|
* @property {number} bassFreq=250 - The crossover frequency (Hz) for the onset of bassMult.
|
||||||
* @property {number} highGain=-6
|
* @property {number} highGain=-6 - Reduces the high-frequency reverb time, as attenuation (dB).
|
||||||
* @property {number} highFreq=3000
|
* @property {number} highFreq=3000 - The crossover frequency (Hz) for the onset of highGain.
|
||||||
* @property {number} modRate=2.3
|
* @property {number} modRate=2.3 - The rate of modulation (Hz) of the LFO-modulated delay lines.
|
||||||
* @property {number} modDepth=50
|
* @property {number} modDepth=50 - The depth of modulation (percent) of the LFO-modulated delay lines.
|
||||||
* @property {number} earlyGain=0
|
* @property {number} earlyGain=0 - Adjusts the relative level (dB) of the early reflections.
|
||||||
* @property {number} lateGain=0
|
* @property {number} lateGain=0 - Adjusts the relative level (dB) of the reverb tail.
|
||||||
* @property {number} earlyMixLeft=20
|
* @property {number} earlyMixLeft=20 - The apparent distance of the source (percent) in the early reflections.
|
||||||
* @property {number} earlyMixRight=20
|
* @property {number} earlyMixRight=20 - The apparent distance of the source (percent) in the early reflections.
|
||||||
* @property {number} lateMixLeft=90
|
* @property {number} lateMixLeft=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||||
* @property {number} lateMixRight=90
|
* @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||||
* @property {number} wetDryMix=50
|
* @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AudioEffectOptions : public QObject {
|
class AudioEffectOptions : public QObject {
|
||||||
|
|
|
@ -840,7 +840,7 @@ static void nearFieldGainCorrection(float azimuth, float distance, float& gainL,
|
||||||
// normalized distance factor = [0,1] as distance = [HRTF_NEARFIELD_MAX,HRTF_HEAD_RADIUS]
|
// normalized distance factor = [0,1] as distance = [HRTF_NEARFIELD_MAX,HRTF_HEAD_RADIUS]
|
||||||
assert(distance < HRTF_NEARFIELD_MAX);
|
assert(distance < HRTF_NEARFIELD_MAX);
|
||||||
assert(distance > HRTF_HEAD_RADIUS);
|
assert(distance > HRTF_HEAD_RADIUS);
|
||||||
float d = (HRTF_NEARFIELD_MAX - distance) * ( 1.0f / (HRTF_NEARFIELD_MAX - HRTF_HEAD_RADIUS));
|
float d = (HRTF_NEARFIELD_MAX - distance) * (1.0f / (HRTF_NEARFIELD_MAX - HRTF_HEAD_RADIUS));
|
||||||
|
|
||||||
// angle of incidence at each ear
|
// angle of incidence at each ear
|
||||||
float angleL = azimuth + HALFPI;
|
float angleL = azimuth + HALFPI;
|
||||||
|
@ -919,6 +919,9 @@ static void azimuthToIndex(float azimuth, int& index0, int& index1, float& frac)
|
||||||
index1 = index0 + 1;
|
index1 = index0 + 1;
|
||||||
frac = azimuth - (float)index0;
|
frac = azimuth - (float)index0;
|
||||||
|
|
||||||
|
if (index0 >= HRTF_AZIMUTHS) {
|
||||||
|
index0 -= HRTF_AZIMUTHS;
|
||||||
|
}
|
||||||
if (index1 >= HRTF_AZIMUTHS) {
|
if (index1 >= HRTF_AZIMUTHS) {
|
||||||
index1 -= HRTF_AZIMUTHS;
|
index1 -= HRTF_AZIMUTHS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,23 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Configures how an audio injector plays its audio.
|
||||||
|
* @typedef {object} AudioInjector.AudioInjectorOptions
|
||||||
|
* @property {Vec3} position=Vec3.ZERO - The position in the domain to play the sound.
|
||||||
|
* @property {Quat} orientation=Quat.IDENTITY - The orientation in the domain to play the sound in.
|
||||||
|
* @property {number} volume=1.0 - Playback volume, between <code>0.0</code> and <code>1.0</code>.
|
||||||
|
* @property {number} pitch=1.0 - Alter the pitch of the sound, within +/- 2 octaves. The value is the relative sample rate to
|
||||||
|
* resample the sound at, range <code>0.0625</code> – <code>16.0</code>. A value of <code>0.0625</code> lowers the
|
||||||
|
* pitch by 2 octaves; <code>1.0</code> is no change in pitch; <code>16.0</code> raises the pitch by 2 octaves.
|
||||||
|
* @property {boolean} loop=false - If <code>true</code>, the sound is played repeatedly until playback is stopped.
|
||||||
|
* @property {number} secondOffset=0 - Starts playback from a specified time (seconds) within the sound file, ≥
|
||||||
|
* <code>0</code>.
|
||||||
|
* @property {boolean} localOnly=false - IF <code>true</code>, the sound is played back locally on the client rather than to
|
||||||
|
* others via the audio mixer.
|
||||||
|
* @property {boolean} ignorePenumbra=false - <strong>Deprecated:</strong> This property is deprecated and will be
|
||||||
|
* removed.
|
||||||
|
*/
|
||||||
void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) {
|
void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOptions& injectorOptions) {
|
||||||
if (!object.isObject()) {
|
if (!object.isObject()) {
|
||||||
qWarning() << "Audio injector options is not an object.";
|
qWarning() << "Audio injector options is not an object.";
|
||||||
|
|
|
@ -79,6 +79,14 @@ private:
|
||||||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* An audio resource, created by {@link SoundCache.getSound}, to be played back using {@link Audio.playSound}.
|
||||||
|
* <p>Supported formats:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>WAV: 16-bit uncompressed WAV at any sample rate, with 1 (mono), 2(stereo), or 4 (ambisonic) channels.</li>
|
||||||
|
* <li>MP3: Mono or stereo, at any sample rate.</li>
|
||||||
|
* <li>RAW: 48khz 16-bit mono or stereo. Filename must include <code>".stereo"</code> to be interpreted as stereo.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
* @class SoundObject
|
* @class SoundObject
|
||||||
*
|
*
|
||||||
* @hifi-interface
|
* @hifi-interface
|
||||||
|
@ -86,8 +94,9 @@ typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||||
* @hifi-server-entity
|
* @hifi-server-entity
|
||||||
* @hifi-assignment-client
|
* @hifi-assignment-client
|
||||||
*
|
*
|
||||||
* @property {boolean} downloaded
|
* @property {boolean} downloaded - <code>true</code> if the sound has been downloaded and is ready to be played, otherwise
|
||||||
* @property {number} duration
|
* <code>false</code>.
|
||||||
|
* @property {number} duration - The duration of the sound, in seconds.
|
||||||
*/
|
*/
|
||||||
class SoundScriptingInterface : public QObject {
|
class SoundScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -103,6 +112,7 @@ public:
|
||||||
float getDuration() { return _sound->getDuration(); }
|
float getDuration() { return _sound->getDuration(); }
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Triggered when the sound has been downloaded and is ready to be played.
|
||||||
* @function SoundObject.ready
|
* @function SoundObject.ready
|
||||||
* @returns {Signal}
|
* @returns {Signal}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -48,9 +48,11 @@ public:
|
||||||
SoundCacheScriptingInterface();
|
SoundCacheScriptingInterface();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
|
* Loads the content of an audio file into a {@link SoundObject}, ready for playback by {@link Audio.playSound}.
|
||||||
* @function SoundCache.getSound
|
* @function SoundCache.getSound
|
||||||
* @param {string} url
|
* @param {string} url - The URL of the audio file to load — Web, ATP, or file. See {@link SoundObject} for supported
|
||||||
* @returns {SoundObject}
|
* formats.
|
||||||
|
* @returns {SoundObject} The sound ready for playback.
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
set(TARGET_NAME display-plugins)
|
set(TARGET_NAME display-plugins)
|
||||||
AUTOSCRIBE_SHADER_LIB(gpu display-plugins)
|
AUTOSCRIBE_SHADER_LIB(gpu display-plugins)
|
||||||
setup_hifi_library(Gui)
|
setup_hifi_library(Gui)
|
||||||
link_hifi_libraries(shared plugins ui-plugins gl ui render-utils ${PLATFORM_GL_BACKEND})
|
link_hifi_libraries(shared shaders plugins ui-plugins gl ui render-utils ${PLATFORM_GL_BACKEND})
|
||||||
include_hifi_library_headers(gpu)
|
include_hifi_library_headers(gpu)
|
||||||
include_hifi_library_headers(model-networking)
|
include_hifi_library_headers(model-networking)
|
||||||
include_hifi_library_headers(networking)
|
include_hifi_library_headers(networking)
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
struct TextureData {
|
||||||
|
ivec2 textureSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140, binding=0) uniform textureDataBuffer {
|
||||||
|
TextureData textureData;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding=0) uniform sampler2D colorMap;
|
||||||
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
ivec2 texCoord = ivec2(floor(varTexCoord0 * textureData.textureSize));
|
||||||
|
texCoord.x /= 2;
|
||||||
|
int row = int(floor(gl_FragCoord.y));
|
||||||
|
if (row % 2 > 0) {
|
||||||
|
texCoord.x += (textureData.textureSize.x / 2);
|
||||||
|
}
|
||||||
|
outFragColor = vec4(pow(texelFetch(colorMap, texCoord, 0).rgb, vec3(2.2)), 1.0);
|
||||||
|
}
|
|
@ -30,7 +30,7 @@
|
||||||
#include <gl/OffscreenGLCanvas.h>
|
#include <gl/OffscreenGLCanvas.h>
|
||||||
|
|
||||||
#include <gpu/Texture.h>
|
#include <gpu/Texture.h>
|
||||||
#include <gpu/StandardShaderLib.h>
|
#include <shaders/Shaders.h>
|
||||||
#include <gpu/gl/GLShared.h>
|
#include <gpu/gl/GLShared.h>
|
||||||
#include <gpu/gl/GLBackend.h>
|
#include <gpu/gl/GLBackend.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
|
@ -44,33 +44,6 @@
|
||||||
#include "CompositorHelper.h"
|
#include "CompositorHelper.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
|
||||||
const char* SRGB_TO_LINEAR_FRAG = R"SCRIBE(
|
|
||||||
|
|
||||||
// OpenGLDisplayPlugin_present.frag
|
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
|
||||||
|
|
||||||
out vec4 outFragColor;
|
|
||||||
|
|
||||||
float sRGBFloatToLinear(float value) {
|
|
||||||
const float SRGB_ELBOW = 0.04045;
|
|
||||||
|
|
||||||
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 colorToLinearRGB(vec3 srgb) {
|
|
||||||
return vec3(sRGBFloatToLinear(srgb.r), sRGBFloatToLinear(srgb.g), sRGBFloatToLinear(srgb.b));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
outFragColor.a = 1.0;
|
|
||||||
outFragColor.rgb = colorToLinearRGB(texture(colorMap, varTexCoord0).rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
)SCRIBE";
|
|
||||||
|
|
||||||
extern QThread* RENDER_THREAD;
|
extern QThread* RENDER_THREAD;
|
||||||
|
|
||||||
class PresentThread : public QThread, public Dependency {
|
class PresentThread : public QThread, public Dependency {
|
||||||
|
@ -391,10 +364,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
||||||
|
|
||||||
if (!_presentPipeline) {
|
if (!_presentPipeline) {
|
||||||
{
|
{
|
||||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTexture);
|
||||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
gpu::Shader::makeProgram(*program);
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false));
|
||||||
state->setScissorEnable(true);
|
state->setScissorEnable(true);
|
||||||
|
@ -402,10 +372,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::SrgbToLinear);
|
||||||
auto ps = gpu::Shader::createPixel(std::string(SRGB_TO_LINEAR_FRAG));
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
gpu::Shader::makeProgram(*program);
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false));
|
||||||
state->setScissorEnable(true);
|
state->setScissorEnable(true);
|
||||||
|
@ -413,10 +380,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord);
|
||||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture);
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||||
gpu::Shader::makeProgram(*program);
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false));
|
||||||
state->setBlendFunction(true,
|
state->setBlendFunction(true,
|
||||||
|
@ -426,10 +392,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord);
|
||||||
auto ps = gpu::StandardShaderLib::getDrawTextureMirroredXPS();
|
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTextureMirroredX);
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||||
gpu::Shader::makeProgram(*program);
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false));
|
||||||
state->setBlendFunction(true,
|
state->setBlendFunction(true,
|
||||||
|
@ -439,10 +404,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawTransformUnitQuad);
|
||||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture);
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||||
gpu::Shader::makeProgram(*program);
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false));
|
||||||
state->setBlendFunction(true,
|
state->setBlendFunction(true,
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
// OpenGLDisplayPlugin_present.frag
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D colorMap;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 varTexCoord0;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
float sRGBFloatToLinear(float value) {
|
||||||
|
const float SRGB_ELBOW = 0.04045;
|
||||||
|
|
||||||
|
return (value <= SRGB_ELBOW) ? value / 12.92 : pow((value + 0.055) / 1.055, 2.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 colorToLinearRGB(vec3 srgb) {
|
||||||
|
return vec3(sRGBFloatToLinear(srgb.r), sRGBFloatToLinear(srgb.g), sRGBFloatToLinear(srgb.b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
outFragColor.a = 1.0;
|
||||||
|
outFragColor.rgb = colorToLinearRGB(texture(colorMap, varTexCoord0).rgb);
|
||||||
|
}
|
|
@ -24,8 +24,8 @@
|
||||||
#include <gl/GLWidget.h>
|
#include <gl/GLWidget.h>
|
||||||
#include <shared/NsightHelpers.h>
|
#include <shared/NsightHelpers.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
#include <gpu/StandardShaderLib.h>
|
|
||||||
#include <gpu/gl/GLBackend.h>
|
#include <gpu/gl/GLBackend.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
#include <TextureCache.h>
|
#include <TextureCache.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
|
@ -34,8 +34,6 @@
|
||||||
#include "../CompositorHelper.h"
|
#include "../CompositorHelper.h"
|
||||||
|
|
||||||
#include "DesktopPreviewProvider.h"
|
#include "DesktopPreviewProvider.h"
|
||||||
#include "render-utils/hmd_ui_vert.h"
|
|
||||||
#include "render-utils/hmd_ui_frag.h"
|
|
||||||
|
|
||||||
static const QString MONO_PREVIEW = "Mono Preview";
|
static const QString MONO_PREVIEW = "Mono Preview";
|
||||||
static const QString DISABLE_PREVIEW = "Disable Preview";
|
static const QString DISABLE_PREVIEW = "Disable Preview";
|
||||||
|
@ -409,12 +407,7 @@ void HmdDisplayPlugin::HUDRenderer::build() {
|
||||||
|
|
||||||
void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
|
void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
auto vs = hmd_ui_vert::getShader();
|
auto program = gpu::Shader::createProgram(shader::render_utils::program::hmd_ui);
|
||||||
auto ps = hmd_ui_frag::getShader();
|
|
||||||
auto program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
gpu::Shader::makeProgram(*program, gpu::Shader::BindingSet());
|
|
||||||
uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer");
|
|
||||||
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(true, true, gpu::LESS_EQUAL));
|
state->setDepthTest(gpu::State::DepthTest(true, true, gpu::LESS_EQUAL));
|
||||||
state->setBlendFunction(true,
|
state->setBlendFunction(true,
|
||||||
|
@ -437,9 +430,8 @@ std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDis
|
||||||
batch.setInputBuffer(gpu::Stream::POSITION, posView);
|
batch.setInputBuffer(gpu::Stream::POSITION, posView);
|
||||||
batch.setInputBuffer(gpu::Stream::TEXCOORD, uvView);
|
batch.setInputBuffer(gpu::Stream::TEXCOORD, uvView);
|
||||||
batch.setIndexBuffer(gpu::UINT16, indices, 0);
|
batch.setIndexBuffer(gpu::UINT16, indices, 0);
|
||||||
|
|
||||||
uniformsBuffer->setSubData(0, uniforms);
|
uniformsBuffer->setSubData(0, uniforms);
|
||||||
batch.setUniformBuffer(uniformsLocation, uniformsBuffer);
|
batch.setUniformBuffer(0, uniformsBuffer);
|
||||||
|
|
||||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||||
glm::mat4 modelTransform = compositorHelper->getUiTransform();
|
glm::mat4 modelTransform = compositorHelper->getUiTransform();
|
||||||
|
|
|
@ -102,7 +102,6 @@ private:
|
||||||
gpu::BufferPointer indices;
|
gpu::BufferPointer indices;
|
||||||
uint32_t indexCount { 0 };
|
uint32_t indexCount { 0 };
|
||||||
gpu::PipelinePointer pipeline;
|
gpu::PipelinePointer pipeline;
|
||||||
int32_t uniformsLocation { -1 };
|
|
||||||
|
|
||||||
gpu::BufferPointer uniformsBuffer;
|
gpu::BufferPointer uniformsBuffer;
|
||||||
|
|
||||||
|
|
|
@ -8,48 +8,17 @@
|
||||||
|
|
||||||
#include "InterleavedStereoDisplayPlugin.h"
|
#include "InterleavedStereoDisplayPlugin.h"
|
||||||
|
|
||||||
#include <gpu/StandardShaderLib.h>
|
|
||||||
#include <gpu/Pipeline.h>
|
#include <gpu/Pipeline.h>
|
||||||
#include <gpu/Batch.h>
|
#include <gpu/Batch.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
static const char* INTERLEAVED_SRGB_TO_LINEAR_FRAG = R"SCRIBE(
|
|
||||||
|
|
||||||
struct TextureData {
|
|
||||||
ivec2 textureSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std140) uniform textureDataBuffer {
|
|
||||||
TextureData textureData;
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
|
||||||
|
|
||||||
out vec4 outFragColor;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
ivec2 texCoord = ivec2(floor(varTexCoord0 * textureData.textureSize));
|
|
||||||
texCoord.x /= 2;
|
|
||||||
int row = int(floor(gl_FragCoord.y));
|
|
||||||
if (row % 2 > 0) {
|
|
||||||
texCoord.x += (textureData.textureSize.x / 2);
|
|
||||||
}
|
|
||||||
outFragColor = vec4(pow(texelFetch(colorMap, texCoord, 0).rgb, vec3(2.2)), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
)SCRIBE";
|
|
||||||
|
|
||||||
const QString InterleavedStereoDisplayPlugin::NAME("3D TV - Interleaved");
|
const QString InterleavedStereoDisplayPlugin::NAME("3D TV - Interleaved");
|
||||||
|
|
||||||
void InterleavedStereoDisplayPlugin::customizeContext() {
|
void InterleavedStereoDisplayPlugin::customizeContext() {
|
||||||
StereoDisplayPlugin::customizeContext();
|
StereoDisplayPlugin::customizeContext();
|
||||||
if (!_interleavedPresentPipeline) {
|
if (!_interleavedPresentPipeline) {
|
||||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::InterleavedSrgbToLinear);
|
||||||
auto ps = gpu::Shader::createPixel(std::string(INTERLEAVED_SRGB_TO_LINEAR_FRAG));
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
gpu::Shader::makeProgram(*program);
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false));
|
||||||
_interleavedPresentPipeline = gpu::Pipeline::create(program, state);
|
_interleavedPresentPipeline = gpu::Pipeline::create(program, state);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
set(TARGET_NAME entities-renderer)
|
set(TARGET_NAME entities-renderer)
|
||||||
AUTOSCRIBE_SHADER_LIB(gpu graphics procedural render render-utils)
|
|
||||||
setup_hifi_library(Network Script)
|
setup_hifi_library(Network Script)
|
||||||
link_hifi_libraries(shared workload gpu procedural graphics model-networking script-engine render render-utils image qml ui pointers)
|
link_hifi_libraries(shared workload gpu shaders procedural graphics model-networking script-engine render render-utils image qml ui pointers)
|
||||||
include_hifi_library_headers(networking)
|
include_hifi_library_headers(networking)
|
||||||
include_hifi_library_headers(gl)
|
include_hifi_library_headers(gl)
|
||||||
include_hifi_library_headers(ktx)
|
include_hifi_library_headers(ktx)
|
||||||
|
@ -18,3 +17,4 @@ include_hifi_library_headers(graphics-scripting) # for Forward.h
|
||||||
|
|
||||||
target_bullet()
|
target_bullet()
|
||||||
target_polyvox()
|
target_polyvox()
|
||||||
|
|
||||||
|
|
|
@ -336,6 +336,11 @@ bool EntityRenderer::needsRenderUpdate() const {
|
||||||
if (_needsRenderUpdate) {
|
if (_needsRenderUpdate) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isFading()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (_prevIsTransparent != isTransparent()) {
|
if (_prevIsTransparent != isTransparent()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -380,6 +385,10 @@ void EntityRenderer::updateModelTransformAndBound() {
|
||||||
void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) {
|
void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) {
|
||||||
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
|
if (isFading()) {
|
||||||
|
emit requestRenderUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
auto transparent = isTransparent();
|
auto transparent = isTransparent();
|
||||||
if (_prevIsTransparent && !transparent) {
|
if (_prevIsTransparent && !transparent) {
|
||||||
_isFading = false;
|
_isFading = false;
|
||||||
|
|
|
@ -13,9 +13,8 @@
|
||||||
#include <StencilMaskPass.h>
|
#include <StencilMaskPass.h>
|
||||||
|
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
#include "textured_particle_vert.h"
|
|
||||||
#include "textured_particle_frag.h"
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
@ -23,8 +22,6 @@ using namespace render::entities;
|
||||||
static uint8_t CUSTOM_PIPELINE_NUMBER = 0;
|
static uint8_t CUSTOM_PIPELINE_NUMBER = 0;
|
||||||
static gpu::Stream::FormatPointer _vertexFormat;
|
static gpu::Stream::FormatPointer _vertexFormat;
|
||||||
static std::weak_ptr<gpu::Pipeline> _texturedPipeline;
|
static std::weak_ptr<gpu::Pipeline> _texturedPipeline;
|
||||||
// FIXME: This is interfering with the uniform buffers in DeferredLightingEffect.cpp, so use 12 to avoid collisions
|
|
||||||
static int32_t PARTICLE_UNIFORM_SLOT { 12 };
|
|
||||||
|
|
||||||
static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) {
|
static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) {
|
||||||
auto texturedPipeline = _texturedPipeline.lock();
|
auto texturedPipeline = _texturedPipeline.lock();
|
||||||
|
@ -36,17 +33,8 @@ static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, co
|
||||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||||
PrepareStencil::testMask(*state);
|
PrepareStencil::testMask(*state);
|
||||||
|
|
||||||
auto vertShader = textured_particle_vert::getShader();
|
auto program = gpu::Shader::createProgram(shader::entities_renderer::program::textured_particle);
|
||||||
auto fragShader = textured_particle_frag::getShader();
|
|
||||||
|
|
||||||
auto program = gpu::Shader::createProgram(vertShader, fragShader);
|
|
||||||
_texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state);
|
_texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state);
|
||||||
|
|
||||||
batch.runLambda([program] {
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("particleBuffer"), PARTICLE_UNIFORM_SLOT));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<render::ShapePipeline>(texturedPipeline, nullptr, nullptr, nullptr);
|
return std::make_shared<render::ShapePipeline>(texturedPipeline, nullptr, nullptr, nullptr);
|
||||||
|
@ -346,7 +334,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
||||||
transform.setRotation(_renderTransform.getRotation());
|
transform.setRotation(_renderTransform.getRotation());
|
||||||
});
|
});
|
||||||
batch.setModelTransform(transform);
|
batch.setModelTransform(transform);
|
||||||
batch.setUniformBuffer(PARTICLE_UNIFORM_SLOT, _uniformBuffer);
|
batch.setUniformBuffer(0, _uniformBuffer);
|
||||||
batch.setInputFormat(_vertexFormat);
|
batch.setInputFormat(_vertexFormat);
|
||||||
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(GpuParticle));
|
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(GpuParticle));
|
||||||
|
|
||||||
|
|
|
@ -17,18 +17,13 @@
|
||||||
#include <TextureCache.h>
|
#include <TextureCache.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
//#define POLYLINE_ENTITY_USE_FADE_EFFECT
|
//#define POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||||
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||||
# include <FadeEffect.h>
|
# include <FadeEffect.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "paintStroke_vert.h"
|
|
||||||
#include "paintStroke_frag.h"
|
|
||||||
|
|
||||||
#include "paintStroke_fade_vert.h"
|
|
||||||
#include "paintStroke_fade_frag.h"
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
|
@ -48,29 +43,12 @@ struct PolyLineUniforms {
|
||||||
|
|
||||||
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch) {
|
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch) {
|
||||||
if (!polylinePipeline) {
|
if (!polylinePipeline) {
|
||||||
auto VS = paintStroke_vert::getShader();
|
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke);
|
||||||
auto PS = paintStroke_frag::getShader();
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS);
|
|
||||||
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||||
auto fadeVS = gpu::Shader::createVertex(std::string(paintStroke_fade_vert));
|
auto fadeVS = gpu::Shader::createVertex(std::string(paintStroke_fade_vert));
|
||||||
auto fadePS = gpu::Shader::createPixel(std::string(paintStroke_fade_frag));
|
auto fadePS = gpu::Shader::createPixel(std::string(paintStroke_fade_frag));
|
||||||
gpu::ShaderPointer fadeProgram = gpu::Shader::createProgram(fadeVS, fadePS);
|
gpu::ShaderPointer fadeProgram = gpu::Shader::createProgram(fadeVS, fadePS);
|
||||||
#endif
|
#endif
|
||||||
batch.runLambda([program
|
|
||||||
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
|
||||||
, fadeProgram
|
|
||||||
#endif
|
|
||||||
] {
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("originalTexture"), PAINTSTROKE_TEXTURE_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("polyLineBuffer"), PAINTSTROKE_UNIFORM_SLOT));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), PAINTSTROKE_TEXTURE_SLOT + 1));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), PAINTSTROKE_UNIFORM_SLOT + 1));
|
|
||||||
gpu::Shader::makeProgram(*fadeProgram, slotBindings);
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
PrepareStencil::testMask(*state);
|
PrepareStencil::testMask(*state);
|
||||||
|
|
|
@ -25,14 +25,15 @@
|
||||||
#include <EntityEditPacketSender.h>
|
#include <EntityEditPacketSender.h>
|
||||||
#include <PhysicalEntitySimulation.h>
|
#include <PhysicalEntitySimulation.h>
|
||||||
#include <StencilMaskPass.h>
|
#include <StencilMaskPass.h>
|
||||||
|
#include <graphics/ShaderConstants.h>
|
||||||
|
#include <render/ShapePipeline.h>
|
||||||
|
|
||||||
|
#include "entities-renderer/ShaderConstants.h"
|
||||||
|
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
|
|
||||||
#include "polyvox_vert.h"
|
|
||||||
#include "polyvox_frag.h"
|
|
||||||
#include "polyvox_fade_vert.h"
|
|
||||||
#include "polyvox_fade_frag.h"
|
|
||||||
|
|
||||||
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
|
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
|
||||||
# include <FadeEffect.h>
|
# include <FadeEffect.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,11 +73,6 @@
|
||||||
|
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
|
|
||||||
#include "polyvox_vert.h"
|
|
||||||
#include "polyvox_frag.h"
|
|
||||||
#include "polyvox_fade_vert.h"
|
|
||||||
#include "polyvox_fade_frag.h"
|
|
||||||
|
|
||||||
#include "RenderablePolyVoxEntityItem.h"
|
#include "RenderablePolyVoxEntityItem.h"
|
||||||
#include "EntityEditPacketSender.h"
|
#include "EntityEditPacketSender.h"
|
||||||
#include "PhysicalEntitySimulation.h"
|
#include "PhysicalEntitySimulation.h"
|
||||||
|
@ -1564,7 +1560,6 @@ scriptable::ScriptableModelBase RenderablePolyVoxEntityItem::getScriptableModel(
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
static const int MATERIAL_GPU_SLOT { 3 };
|
|
||||||
static uint8_t CUSTOM_PIPELINE_NUMBER;
|
static uint8_t CUSTOM_PIPELINE_NUMBER;
|
||||||
static gpu::PipelinePointer _pipelines[2];
|
static gpu::PipelinePointer _pipelines[2];
|
||||||
static gpu::PipelinePointer _wireframePipelines[2];
|
static gpu::PipelinePointer _wireframePipelines[2];
|
||||||
|
@ -1572,17 +1567,8 @@ static gpu::Stream::FormatPointer _vertexFormat;
|
||||||
|
|
||||||
ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) {
|
ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, gpu::Batch& batch) {
|
||||||
if (!_pipelines[0]) {
|
if (!_pipelines[0]) {
|
||||||
gpu::ShaderPointer vertexShaders[2] = { polyvox_vert::getShader(), polyvox_fade_vert::getShader() };
|
using namespace shader::entities_renderer::program;
|
||||||
gpu::ShaderPointer pixelShaders[2] = { polyvox_frag::getShader(), polyvox_fade_frag::getShader() };
|
int programsIds[2] = { polyvox, polyvox_fade };
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
|
|
||||||
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), 3));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setCullMode(gpu::State::CULL_BACK);
|
state->setCullMode(gpu::State::CULL_BACK);
|
||||||
|
@ -1597,12 +1583,7 @@ ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const Sha
|
||||||
|
|
||||||
// Two sets of pipelines: normal and fading
|
// Two sets of pipelines: normal and fading
|
||||||
for (auto i = 0; i < 2; i++) {
|
for (auto i = 0; i < 2; i++) {
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShaders[i], pixelShaders[i]);
|
gpu::ShaderPointer program = gpu::Shader::createProgram(programsIds[i]);
|
||||||
|
|
||||||
batch.runLambda([program, slotBindings] {
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
});
|
|
||||||
|
|
||||||
_pipelines[i] = gpu::Pipeline::create(program, state);
|
_pipelines[i] = gpu::Pipeline::create(program, state);
|
||||||
_wireframePipelines[i] = gpu::Pipeline::create(program, wireframeState);
|
_wireframePipelines[i] = gpu::Pipeline::create(program, wireframeState);
|
||||||
}
|
}
|
||||||
|
@ -1737,8 +1718,7 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int voxelVolumeSizeLocation = args->_shapePipeline->pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize");
|
batch._glUniform3f(entities_renderer::slot::uniform::PolyvoxVoxelSize, _lastVoxelVolumeSize.x, _lastVoxelVolumeSize.y, _lastVoxelVolumeSize.z);
|
||||||
batch._glUniform3f(voxelVolumeSizeLocation, _lastVoxelVolumeSize.x, _lastVoxelVolumeSize.y, _lastVoxelVolumeSize.z);
|
|
||||||
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_mesh->getNumIndices(), 0);
|
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_mesh->getNumIndices(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,7 @@
|
||||||
#include <StencilMaskPass.h>
|
#include <StencilMaskPass.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
#include "render-utils/simple_vert.h"
|
|
||||||
#include "render-utils/simple_frag.h"
|
|
||||||
#include "render-utils/simple_transparent_frag.h"
|
|
||||||
#include "render-utils/forward_simple_frag.h"
|
|
||||||
#include "render-utils/forward_simple_transparent_frag.h"
|
|
||||||
|
|
||||||
#include "RenderPipelines.h"
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
|
@ -37,12 +32,12 @@ static const float SPHERE_ENTITY_SCALE = 0.5f;
|
||||||
|
|
||||||
|
|
||||||
ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
||||||
_procedural._vertexSource = simple_vert::getSource();
|
_procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple);
|
||||||
// FIXME: Setup proper uniform slots and use correct pipelines for forward rendering
|
// FIXME: Setup proper uniform slots and use correct pipelines for forward rendering
|
||||||
_procedural._opaquefragmentSource = simple_frag::getSource();
|
_procedural._opaquefragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple);
|
||||||
// FIXME: Transparent procedural entities only seem to work if they use the opaque pipelines
|
// FIXME: Transparent procedural entities only seem to work if they use the opaque pipelines
|
||||||
//_procedural._transparentfragmentSource = simple_transparent_frag::getSource();
|
//_procedural._transparentfragmentSource = simple_transparent_frag::getSource();
|
||||||
_procedural._transparentfragmentSource = simple_frag::getSource();
|
_procedural._transparentfragmentSource = _procedural._opaquefragmentSource;
|
||||||
_procedural._opaqueState->setCullMode(gpu::State::CULL_NONE);
|
_procedural._opaqueState->setCullMode(gpu::State::CULL_NONE);
|
||||||
_procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
_procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
|
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
|
||||||
|
@ -216,7 +211,14 @@ ShapeKey ShapeEntityRenderer::getShapeKey() {
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
} else {
|
} else {
|
||||||
return Parent::getShapeKey();
|
ShapeKey::Builder builder;
|
||||||
|
if (_procedural.isReady()) {
|
||||||
|
builder.withOwnPipeline();
|
||||||
|
}
|
||||||
|
if (isTransparent()) {
|
||||||
|
builder.withTranslucent();
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// <!
|
||||||
|
// Created by Bradley Austin Davis on 2018/05/25
|
||||||
|
// Copyright 2013-2018 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
|
||||||
|
// !>
|
||||||
|
|
||||||
|
// <@if not ENTITIES_SHADER_CONSTANTS_H@>
|
||||||
|
// <@def ENTITIES_SHADER_CONSTANTS_H@>
|
||||||
|
|
||||||
|
// Hack comment to absorb the extra '//' scribe prepends
|
||||||
|
|
||||||
|
#ifndef ENTITIES_SHADER_CONSTANTS_H
|
||||||
|
#define ENTITIES_SHADER_CONSTANTS_H
|
||||||
|
|
||||||
|
// Polyvox
|
||||||
|
#define ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE 0
|
||||||
|
#define ENTITIES_TEXTURE_POLYVOX_XMAP 0
|
||||||
|
#define ENTITIES_TEXTURE_POLYVOX_YMAP 1
|
||||||
|
#define ENTITIES_TEXTURE_POLYVOX_ZMAP 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// <!
|
||||||
|
|
||||||
|
namespace entities_renderer { namespace slot {
|
||||||
|
|
||||||
|
namespace uniform {
|
||||||
|
enum Uniform {
|
||||||
|
PolyvoxVoxelSize = ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace buffer {
|
||||||
|
enum Buffer {
|
||||||
|
};
|
||||||
|
} // namespace buffer
|
||||||
|
|
||||||
|
namespace texture {
|
||||||
|
enum Texture {
|
||||||
|
PolyvoxXMap = ENTITIES_TEXTURE_POLYVOX_XMAP,
|
||||||
|
PolyvoxYMap = ENTITIES_TEXTURE_POLYVOX_YMAP,
|
||||||
|
PolyvoxZMap = ENTITIES_TEXTURE_POLYVOX_ZMAP,
|
||||||
|
};
|
||||||
|
} // namespace texture
|
||||||
|
|
||||||
|
} } // namespace entities::slot
|
||||||
|
|
||||||
|
// !>
|
||||||
|
// Hack Comment
|
||||||
|
|
||||||
|
#endif // ENTITIES_SHADER_CONSTANTS_H
|
||||||
|
|
||||||
|
// <@if 1@>
|
||||||
|
// Trigger Scribe include
|
||||||
|
// <@endif@> <!def that !>
|
||||||
|
|
||||||
|
// <@endif@>
|
||||||
|
|
||||||
|
// Hack Comment
|
|
@ -16,18 +16,18 @@
|
||||||
|
|
||||||
|
|
||||||
// the albedo texture
|
// the albedo texture
|
||||||
uniform sampler2D originalTexture;
|
layout(binding=0) uniform sampler2D originalTexture;
|
||||||
|
|
||||||
// the interpolated normal
|
// the interpolated normal
|
||||||
in vec3 interpolatedNormal;
|
layout(location=0) in vec3 interpolatedNormal;
|
||||||
in vec2 varTexcoord;
|
layout(location=1) in vec2 varTexcoord;
|
||||||
in vec4 varColor;
|
layout(location=2) in vec4 varColor;
|
||||||
|
|
||||||
struct PolyLineUniforms {
|
struct PolyLineUniforms {
|
||||||
vec3 color;
|
vec3 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform polyLineBuffer {
|
layout(binding=0) uniform polyLineBuffer {
|
||||||
PolyLineUniforms polyline;
|
PolyLineUniforms polyline;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,12 @@
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
// the interpolated normal
|
// the interpolated normal
|
||||||
out vec3 interpolatedNormal;
|
layout(location=0) out vec3 interpolatedNormal;
|
||||||
|
|
||||||
//the diffuse texture
|
//the diffuse texture
|
||||||
out vec2 varTexcoord;
|
layout(location=1) out vec2 varTexcoord;
|
||||||
|
|
||||||
out vec4 varColor;
|
layout(location=2) out vec4 varColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
// paintStroke_fade.slf
|
// paintStroke_fade.frag
|
||||||
// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Olivier Prat on 19/07/17.
|
// Created by Olivier Prat on 19/07/17.
|
||||||
|
@ -18,19 +18,19 @@
|
||||||
<$declareFadeFragment()$>
|
<$declareFadeFragment()$>
|
||||||
|
|
||||||
// the albedo texture
|
// the albedo texture
|
||||||
uniform sampler2D originalTexture;
|
layout(binding=0) uniform sampler2D originalTexture;
|
||||||
|
|
||||||
// the interpolated normal
|
// the interpolated normal
|
||||||
in vec3 interpolatedNormal;
|
layout(location=0) in vec3 interpolatedNormal;
|
||||||
in vec2 varTexcoord;
|
layout(location=1) in vec2 varTexcoord;
|
||||||
in vec4 varColor;
|
layout(location=2) in vec4 varColor;
|
||||||
in vec4 _worldPosition;
|
layout(location=3) in vec4 _worldPosition;
|
||||||
|
|
||||||
struct PolyLineUniforms {
|
struct PolyLineUniforms {
|
||||||
vec3 color;
|
vec3 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform polyLineBuffer {
|
layout(binding=0) uniform polyLineBuffer {
|
||||||
PolyLineUniforms polyline;
|
PolyLineUniforms polyline;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
// paintStroke_fade.slv
|
// paintStroke_fade.vert
|
||||||
// vertex shader
|
// vertex shader
|
||||||
//
|
//
|
||||||
// Created by Olivier Prat on 19/07/17.
|
// Created by Olivier Prat on 19/07/17.
|
||||||
|
@ -18,13 +18,13 @@
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
// the interpolated normal
|
// the interpolated normal
|
||||||
out vec3 interpolatedNormal;
|
layout(location=0) out vec3 interpolatedNormal;
|
||||||
|
|
||||||
//the diffuse texture
|
//the diffuse texture
|
||||||
out vec2 varTexcoord;
|
layout(location=1) out vec2 varTexcoord;
|
||||||
|
|
||||||
out vec4 varColor;
|
layout(location=2) out vec4 varColor;
|
||||||
out vec4 _worldPosition;
|
layout(location=3) out vec4 _worldPosition;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,17 @@
|
||||||
|
|
||||||
<@include graphics/Material.slh@>
|
<@include graphics/Material.slh@>
|
||||||
<@include DeferredBufferWrite.slh@>
|
<@include DeferredBufferWrite.slh@>
|
||||||
|
<@include render-utils/ShaderConstants.h@>
|
||||||
|
<@include entities-renderer/ShaderConstants.h@>
|
||||||
|
|
||||||
in vec3 _normal;
|
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal;
|
||||||
in vec4 _position;
|
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position;
|
||||||
in vec4 _worldPosition;
|
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition;
|
||||||
|
|
||||||
uniform sampler2D xMap;
|
layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
|
||||||
uniform sampler2D yMap;
|
layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
|
||||||
uniform sampler2D zMap;
|
layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
|
||||||
uniform vec3 voxelVolumeSize;
|
layout(location=ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE) uniform vec3 voxelVolumeSize;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
|
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
<@include gpu/Inputs.slh@>
|
<@include gpu/Inputs.slh@>
|
||||||
|
|
||||||
<@include gpu/Transform.slh@>
|
<@include gpu/Transform.slh@>
|
||||||
|
<@include render-utils/ShaderConstants.h@>
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
out vec4 _position;
|
layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec4 _position;
|
||||||
out vec4 _worldPosition;
|
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _worldPosition;
|
||||||
out vec3 _normal;
|
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) out vec3 _normal;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// standard transform
|
// standard transform
|
||||||
|
|
|
@ -13,18 +13,21 @@
|
||||||
|
|
||||||
<@include graphics/Material.slh@>
|
<@include graphics/Material.slh@>
|
||||||
<@include DeferredBufferWrite.slh@>
|
<@include DeferredBufferWrite.slh@>
|
||||||
|
<@include render-utils/ShaderConstants.h@>
|
||||||
|
<@include entities-renderer/ShaderConstants.h@>
|
||||||
|
|
||||||
<@include Fade.slh@>
|
<@include Fade.slh@>
|
||||||
|
|
||||||
in vec3 _normal;
|
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal;
|
||||||
in vec4 _position;
|
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position;
|
||||||
in vec4 _worldPosition;
|
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition;
|
||||||
in vec4 _worldFadePosition;
|
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _worldFadePosition;
|
||||||
|
|
||||||
uniform sampler2D xMap;
|
layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
|
||||||
uniform sampler2D yMap;
|
layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
|
||||||
uniform sampler2D zMap;
|
layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
|
||||||
uniform vec3 voxelVolumeSize;
|
|
||||||
|
layout(location=ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE) uniform vec3 voxelVolumeSize;
|
||||||
|
|
||||||
// Declare after all samplers to prevent sampler location mix up with voxel shading (sampler locations are hardcoded in RenderablePolyVoxEntityItem)
|
// Declare after all samplers to prevent sampler location mix up with voxel shading (sampler locations are hardcoded in RenderablePolyVoxEntityItem)
|
||||||
<$declareFadeFragment()$>
|
<$declareFadeFragment()$>
|
||||||
|
|
|
@ -12,15 +12,15 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
<@include gpu/Inputs.slh@>
|
<@include gpu/Inputs.slh@>
|
||||||
|
|
||||||
<@include gpu/Transform.slh@>
|
<@include gpu/Transform.slh@>
|
||||||
|
<@include render-utils/ShaderConstants.h@>
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
out vec4 _position;
|
layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec4 _position;
|
||||||
out vec4 _worldPosition;
|
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _worldPosition;
|
||||||
out vec4 _worldFadePosition;
|
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) out vec3 _normal;
|
||||||
out vec3 _normal;
|
layout(location=RENDER_UTILS_ATTR_POSITION_ES) out vec4 _worldFadePosition;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// standard transform
|
// standard transform
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<@include gpu/Config.slh@>
|
<@include gpu/Config.slh@>
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
// fragment shader
|
//
|
||||||
|
// textured_particle.frag
|
||||||
//
|
//
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
|
@ -9,12 +10,12 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
layout(binding=0) uniform sampler2D colorMap;
|
||||||
|
|
||||||
in vec4 varColor;
|
layout(location=0) in vec4 varColor;
|
||||||
in vec2 varTexcoord;
|
layout(location=1) in vec2 varTexcoord;
|
||||||
|
|
||||||
out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = texture(colorMap, varTexcoord.xy) * varColor;
|
outFragColor = texture(colorMap, varTexcoord.xy) * varColor;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
// particle vertex shader
|
// texture_particle.vert
|
||||||
//
|
//
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
|
@ -43,15 +43,15 @@ struct ParticleUniforms {
|
||||||
vec2 spare;
|
vec2 spare;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std140) uniform particleBuffer {
|
layout(std140, binding=0) uniform particleBuffer {
|
||||||
ParticleUniforms particle;
|
ParticleUniforms particle;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(location=0) in vec3 inPosition;
|
layout(location=0) in vec3 inPosition;
|
||||||
layout(location=2) in vec2 inColor; // This is actual Lifetime + Seed
|
layout(location=2) in vec2 inColor; // This is actual Lifetime + Seed
|
||||||
|
|
||||||
out vec4 varColor;
|
layout(location=0) out vec4 varColor;
|
||||||
out vec2 varTexcoord;
|
layout(location=1) out vec2 varTexcoord;
|
||||||
|
|
||||||
float bezierInterpolate(float y1, float y2, float y3, float u) {
|
float bezierInterpolate(float y1, float y2, float y3, float u) {
|
||||||
// https://en.wikipedia.org/wiki/Bezier_curve
|
// https://en.wikipedia.org/wiki/Bezier_curve
|
||||||
|
|
|
@ -269,7 +269,9 @@ void Context::create() {
|
||||||
#if defined(USE_GLES)
|
#if defined(USE_GLES)
|
||||||
_version = 0x0200;
|
_version = 0x0200;
|
||||||
#else
|
#else
|
||||||
if (GLAD_GL_VERSION_4_5) {
|
if (gl::disableGl45()) {
|
||||||
|
_version = 0x0401;
|
||||||
|
} else if (GLAD_GL_VERSION_4_5) {
|
||||||
_version = 0x0405;
|
_version = 0x0405;
|
||||||
} else if (GLAD_GL_VERSION_4_3) {
|
} else if (GLAD_GL_VERSION_4_3) {
|
||||||
_version = 0x0403;
|
_version = 0x0403;
|
||||||
|
|
|
@ -24,6 +24,26 @@ size_t evalGLFormatSwapchainPixelSize(const QSurfaceFormat& format) {
|
||||||
return pixelSize;
|
return pixelSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool gl::disableGl45() {
|
||||||
|
#if defined(USE_GLES)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
static const QString DEBUG_FLAG("HIFI_DISABLE_OPENGL_45");
|
||||||
|
static bool disableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||||
|
return disableOpenGL45;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl::getTargetVersion(int& major, int& minor) {
|
||||||
|
#if defined(USE_GLES)
|
||||||
|
major = 3;
|
||||||
|
minor = 2;
|
||||||
|
#else
|
||||||
|
major = 4;
|
||||||
|
minor = disableGl45() ? 1 : 5;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
||||||
static QSurfaceFormat format;
|
static QSurfaceFormat format;
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
|
@ -40,7 +60,10 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
||||||
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||||
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
|
format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS);
|
||||||
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
|
format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS);
|
||||||
setGLFormatVersion(format);
|
int major, minor;
|
||||||
|
::gl::getTargetVersion(major, minor);
|
||||||
|
format.setMajorVersion(major);
|
||||||
|
format.setMinorVersion(minor);
|
||||||
QSurfaceFormat::setDefaultFormat(format);
|
QSurfaceFormat::setDefaultFormat(format);
|
||||||
});
|
});
|
||||||
return format;
|
return format;
|
||||||
|
|
|
@ -26,15 +26,6 @@ class QOpenGLDebugMessage;
|
||||||
class QSurfaceFormat;
|
class QSurfaceFormat;
|
||||||
class QGLFormat;
|
class QGLFormat;
|
||||||
|
|
||||||
template<class F>
|
|
||||||
// https://bugreports.qt.io/browse/QTBUG-64703 prevents us from using "defined(QT_OPENGL_ES_3_1)"
|
|
||||||
#if defined(USE_GLES)
|
|
||||||
void setGLFormatVersion(F& format, int major = 3, int minor = 2)
|
|
||||||
#else
|
|
||||||
void setGLFormatVersion(F& format, int major = 4, int minor = 5)
|
|
||||||
#endif
|
|
||||||
{ format.setVersion(major, minor); }
|
|
||||||
|
|
||||||
size_t evalGLFormatSwapchainPixelSize(const QSurfaceFormat& format);
|
size_t evalGLFormatSwapchainPixelSize(const QSurfaceFormat& format);
|
||||||
|
|
||||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
||||||
|
@ -50,6 +41,9 @@ namespace gl {
|
||||||
|
|
||||||
bool checkGLErrorDebug(const char* name);
|
bool checkGLErrorDebug(const char* name);
|
||||||
|
|
||||||
|
bool disableGl45();
|
||||||
|
|
||||||
|
void getTargetVersion(int& major, int& minor);
|
||||||
} // namespace gl
|
} // namespace gl
|
||||||
|
|
||||||
#define CHECK_GL_ERROR() ::gl::checkGLErrorDebug(__FUNCTION__)
|
#define CHECK_GL_ERROR() ::gl::checkGLErrorDebug(__FUNCTION__)
|
||||||
|
|
|
@ -13,32 +13,194 @@
|
||||||
using namespace gl;
|
using namespace gl;
|
||||||
|
|
||||||
void Uniform::load(GLuint glprogram, int index) {
|
void Uniform::load(GLuint glprogram, int index) {
|
||||||
|
this->index = index;
|
||||||
const GLint NAME_LENGTH = 256;
|
const GLint NAME_LENGTH = 256;
|
||||||
GLchar glname[NAME_LENGTH];
|
GLchar glname[NAME_LENGTH];
|
||||||
GLint length = 0;
|
GLint length = 0;
|
||||||
glGetActiveUniform(glprogram, index, NAME_LENGTH, &length, &size, &type, glname);
|
glGetActiveUniform(glprogram, index, NAME_LENGTH, &length, &size, &type, glname);
|
||||||
|
// Length does NOT include the null terminator
|
||||||
|
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetActiveUniform.xhtml
|
||||||
name = std::string(glname, length);
|
name = std::string(glname, length);
|
||||||
location = glGetUniformLocation(glprogram, glname);
|
binding = glGetUniformLocation(glprogram, glname);
|
||||||
}
|
}
|
||||||
|
|
||||||
Uniforms gl::loadUniforms(GLuint glprogram) {
|
bool isTextureType(GLenum type) {
|
||||||
|
switch (type) {
|
||||||
|
#ifndef USE_GLES
|
||||||
|
case GL_SAMPLER_1D:
|
||||||
|
case GL_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_SAMPLER_1D_SHADOW:
|
||||||
|
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||||
|
#endif
|
||||||
|
case GL_SAMPLER_2D:
|
||||||
|
case GL_SAMPLER_3D:
|
||||||
|
case GL_SAMPLER_CUBE:
|
||||||
|
case GL_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||||
|
case GL_SAMPLER_2D_SHADOW:
|
||||||
|
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||||
|
case GL_SAMPLER_BUFFER:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniforms Uniform::load(GLuint glprogram, const std::function<bool(const Uniform&)>& filter) {
|
||||||
|
Uniforms result;
|
||||||
GLint uniformsCount = 0;
|
GLint uniformsCount = 0;
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||||
|
result.reserve(uniformsCount);
|
||||||
Uniforms result;
|
|
||||||
result.resize(uniformsCount);
|
|
||||||
for (int i = 0; i < uniformsCount; i++) {
|
for (int i = 0; i < uniformsCount; i++) {
|
||||||
result[i].load(glprogram, i);
|
result.emplace_back(glprogram, i);
|
||||||
|
}
|
||||||
|
result.erase(std::remove_if(result.begin(), result.end(), filter), result.end());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Uniforms Uniform::loadTextures(GLuint glprogram) {
|
||||||
|
return load(glprogram, [](const Uniform& uniform) -> bool {
|
||||||
|
if (std::string::npos != uniform.name.find('.')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::string::npos != uniform.name.find('[')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!isTextureType(uniform.type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniforms Uniform::load(GLuint glprogram) {
|
||||||
|
return load(glprogram, [](const Uniform& uniform) -> bool {
|
||||||
|
if (std::string::npos != uniform.name.find('.')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::string::npos != uniform.name.find('[')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isTextureType(uniform.type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniforms Uniform::load(GLuint glprogram, const std::vector<GLuint>& indices) {
|
||||||
|
Uniforms result;
|
||||||
|
result.reserve(indices.size());
|
||||||
|
for (const auto& i : indices) {
|
||||||
|
if (i == GL_INVALID_INDEX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.emplace_back(glprogram, i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniform Uniform::loadByName(GLuint glprogram, const std::string& name) {
|
||||||
|
GLuint index;
|
||||||
|
const char* nameCStr = name.c_str();
|
||||||
|
glGetUniformIndices(glprogram, 1, &nameCStr, &index);
|
||||||
|
Uniform result;
|
||||||
|
if (index != GL_INVALID_INDEX) {
|
||||||
|
result.load(glprogram, index);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Uniforms Uniform::load(GLuint glprogram, const std::vector<const char*>& cnames) {
|
||||||
|
GLsizei count = static_cast<GLsizei>(cnames.size());
|
||||||
|
if (0 == count) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<GLuint> indices;
|
||||||
|
indices.resize(count);
|
||||||
|
glGetUniformIndices(glprogram, count, cnames.data(), indices.data());
|
||||||
|
return load(glprogram, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename C, typename F>
|
||||||
|
std::vector<const char*> toCNames(const C& container, F lambda) {
|
||||||
|
std::vector<const char*> result;
|
||||||
|
result.reserve(container.size());
|
||||||
|
std::transform(container.begin(), container.end(), std::back_inserter(result), lambda);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniforms Uniform::load(GLuint glprogram, const std::vector<std::string>& names) {
|
||||||
|
auto cnames = toCNames(names, [](const std::string& name) { return name.c_str(); });
|
||||||
|
return load(glprogram, cnames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniformBlock::load(GLuint glprogram, int index) {
|
||||||
|
this->index = index;
|
||||||
|
GLint length = 0;
|
||||||
|
|
||||||
|
// Length DOES include the null terminator
|
||||||
|
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetActiveUniformBlock.xhtml
|
||||||
|
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
|
||||||
|
if (length > 1) {
|
||||||
|
std::vector<char> nameBuffer;
|
||||||
|
nameBuffer.resize(length);
|
||||||
|
glGetActiveUniformBlockName(glprogram, index, length, nullptr, nameBuffer.data());
|
||||||
|
name = std::string(nameBuffer.data(), length - 1);
|
||||||
|
}
|
||||||
|
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding);
|
||||||
|
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformBlocks UniformBlock::load(GLuint glprogram) {
|
||||||
|
GLint buffersCount = -1;
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
||||||
|
|
||||||
|
// fast exit
|
||||||
|
if (buffersCount <= 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformBlocks uniformBlocks;
|
||||||
|
for (int i = 0; i < buffersCount; ++i) {
|
||||||
|
uniformBlocks.emplace_back(glprogram, i);
|
||||||
|
}
|
||||||
|
return uniformBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::load(GLuint glprogram, int index) {
|
||||||
|
const GLint NAME_LENGTH = 256;
|
||||||
|
GLchar name[NAME_LENGTH];
|
||||||
|
GLint length = 0;
|
||||||
|
// Length does NOT include the null terminator
|
||||||
|
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetActiveAttrib.xhtml
|
||||||
|
glGetActiveAttrib(glprogram, index, NAME_LENGTH, &length, &size, &type, name);
|
||||||
|
if (length > 0) {
|
||||||
|
this->name = std::string(name, length);
|
||||||
|
}
|
||||||
|
binding = glGetAttribLocation(glprogram, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs Input::load(GLuint glprogram) {
|
||||||
|
Inputs result;
|
||||||
|
GLint count;
|
||||||
|
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
result.emplace_back(glprogram, i);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
bool gl::compileShader(GLenum shaderDomain,
|
bool gl::compileShader(GLenum shaderDomain,
|
||||||
const std::string& shaderSource,
|
const std::string& shaderSource,
|
||||||
GLuint& shaderObject,
|
GLuint& shaderObject,
|
||||||
GLuint& programObject,
|
GLuint& programObject,
|
||||||
std::string& message) {
|
std::string& message) {
|
||||||
return compileShader(shaderDomain, std::vector<std::string>{ shaderSource }, shaderObject, programObject, message);
|
return compileShader(shaderDomain, std::vector<std::string>{ shaderSource }, shaderObject, programObject, message);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -49,15 +211,15 @@ bool gl::compileShader(GLenum shaderDomain, const std::string& shaderSource, GLu
|
||||||
|
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
bool gl::compileShader(GLenum shaderDomain,
|
bool gl::compileShader(GLenum shaderDomain,
|
||||||
const std::string& shaderSource,
|
const std::string& shaderSource,
|
||||||
GLuint& shaderObject,
|
GLuint& shaderObject,
|
||||||
GLuint& programObject,
|
GLuint& programObject,
|
||||||
std::string& message) {
|
std::string& message) {
|
||||||
#else
|
#else
|
||||||
bool gl::compileShader(GLenum shaderDomain,
|
bool gl::compileShader(GLenum shaderDomain,
|
||||||
const std::vector<std::string>& shaderSources,
|
const std::vector<std::string>& shaderSources,
|
||||||
GLuint& shaderObject,
|
GLuint& shaderObject,
|
||||||
std::string& message) {
|
std::string& message) {
|
||||||
#endif
|
#endif
|
||||||
if (shaderSources.empty()) {
|
if (shaderSources.empty()) {
|
||||||
qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
|
||||||
|
@ -85,57 +247,28 @@ bool gl::compileShader(GLenum shaderDomain,
|
||||||
GLint compiled = 0;
|
GLint compiled = 0;
|
||||||
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
|
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
|
||||||
|
|
||||||
GLint infoLength = 0;
|
getShaderInfoLog(glshader, message);
|
||||||
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
// if compilation fails
|
||||||
|
if (!compiled) {
|
||||||
if ((infoLength > 0) || !compiled) {
|
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
|
||||||
char* temp = new char[infoLength];
|
int lineNumber = 0;
|
||||||
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
|
for (const auto& s : cstrs) {
|
||||||
|
QString str(s);
|
||||||
message = std::string(temp);
|
QStringList lines = str.split("\n");
|
||||||
|
for (auto& line : lines) {
|
||||||
// if compilation fails
|
qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
|
||||||
if (!compiled) {
|
|
||||||
// save the source code to a temp file so we can debug easily
|
|
||||||
/*
|
|
||||||
std::ofstream filestream;
|
|
||||||
filestream.open("debugshader.glsl");
|
|
||||||
if (filestream.is_open()) {
|
|
||||||
filestream << srcstr[0];
|
|
||||||
filestream << srcstr[1];
|
|
||||||
filestream.close();
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
filestream.open("debugshader.glsl.info.txt");
|
|
||||||
if (filestream.is_open()) {
|
|
||||||
filestream << std::string(temp);
|
|
||||||
filestream.close();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
|
|
||||||
int lineNumber = 0;
|
|
||||||
for (const auto& s : cstrs) {
|
|
||||||
QString str(s);
|
|
||||||
QStringList lines = str.split("\n");
|
|
||||||
for (auto& line : lines) {
|
|
||||||
qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qCCritical(glLogging) << "GLShader::compileShader - errors:";
|
|
||||||
qCCritical(glLogging) << temp;
|
|
||||||
|
|
||||||
delete[] temp;
|
|
||||||
glDeleteShader(glshader);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
qCCritical(glLogging) << "GLShader::compileShader - errors:";
|
||||||
|
qCCritical(glLogging) << message.c_str();
|
||||||
|
glDeleteShader(glshader);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.empty()) {
|
||||||
// Compilation success
|
// Compilation success
|
||||||
qCWarning(glLogging) << "GLShader::compileShader - Success:";
|
qCWarning(glLogging) << "GLShader::compileShader - Success:";
|
||||||
qCWarning(glLogging) << temp;
|
qCWarning(glLogging) << message.c_str();
|
||||||
delete[] temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
|
@ -193,7 +326,47 @@ bool gl::compileShader(GLenum shaderDomain,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint gl::compileProgram(const std::vector<GLuint>& glshaders, std::string& message, CachedShader& cachedShader) {
|
void gl::getShaderInfoLog(GLuint glshader, std::string& message) {
|
||||||
|
std::string result;
|
||||||
|
GLint infoLength = 0;
|
||||||
|
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
||||||
|
if (infoLength > 0) {
|
||||||
|
char* temp = new char[infoLength];
|
||||||
|
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
|
||||||
|
message = std::string(temp);
|
||||||
|
delete[] temp;
|
||||||
|
} else {
|
||||||
|
message.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl::getProgramInfoLog(GLuint glprogram, std::string& message) {
|
||||||
|
std::string result;
|
||||||
|
GLint infoLength = 0;
|
||||||
|
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
||||||
|
if (infoLength > 0) {
|
||||||
|
char* temp = new char[infoLength];
|
||||||
|
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
||||||
|
message = std::string(temp);
|
||||||
|
delete[] temp;
|
||||||
|
} else {
|
||||||
|
message.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl::getProgramBinary(GLuint glprogram, CachedShader& cachedShader) {
|
||||||
|
GLint binaryLength = 0;
|
||||||
|
glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||||
|
if (binaryLength > 0) {
|
||||||
|
cachedShader.binary.resize(binaryLength);
|
||||||
|
glGetProgramBinary(glprogram, binaryLength, NULL, &cachedShader.format, cachedShader.binary.data());
|
||||||
|
} else {
|
||||||
|
cachedShader.binary.clear();
|
||||||
|
cachedShader.format = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint gl::buildProgram(const std::vector<GLuint>& glshaders) {
|
||||||
// A brand new program:
|
// A brand new program:
|
||||||
GLuint glprogram = glCreateProgram();
|
GLuint glprogram = glCreateProgram();
|
||||||
if (!glprogram) {
|
if (!glprogram) {
|
||||||
|
@ -201,80 +374,55 @@ GLuint gl::compileProgram(const std::vector<GLuint>& glshaders, std::string& mes
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool binaryLoaded = false;
|
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
||||||
|
// Create the program from the sub shaders
|
||||||
if (glshaders.empty() && cachedShader) {
|
for (auto so : glshaders) {
|
||||||
glProgramBinary(glprogram, cachedShader.format, cachedShader.binary.data(), (GLsizei)cachedShader.binary.size());
|
glAttachShader(glprogram, so);
|
||||||
binaryLoaded = true;
|
|
||||||
} else {
|
|
||||||
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
|
||||||
// Create the program from the sub shaders
|
|
||||||
for (auto so : glshaders) {
|
|
||||||
glAttachShader(glprogram, so);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link!
|
|
||||||
glLinkProgram(glprogram);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint linked = 0;
|
|
||||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
|
||||||
|
|
||||||
GLint infoLength = 0;
|
|
||||||
glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
|
|
||||||
|
|
||||||
if ((infoLength > 0) || !linked) {
|
|
||||||
char* temp = new char[infoLength];
|
|
||||||
glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
|
|
||||||
|
|
||||||
message = std::string(temp);
|
|
||||||
|
|
||||||
if (!linked) {
|
|
||||||
/*
|
|
||||||
// save the source code to a temp file so we can debug easily
|
|
||||||
std::ofstream filestream;
|
|
||||||
filestream.open("debugshader.glsl");
|
|
||||||
if (filestream.is_open()) {
|
|
||||||
filestream << shaderSource->source;
|
|
||||||
filestream.close();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
|
|
||||||
qCDebug(glLogging) << temp;
|
|
||||||
|
|
||||||
delete[] temp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
filestream.open("debugshader.glsl.info.txt");
|
|
||||||
if (filestream.is_open()) {
|
|
||||||
filestream << std::string(temp);
|
|
||||||
filestream.close();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
glDeleteProgram(glprogram);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
qCDebug(glLogging) << "GLShader::compileProgram - success:";
|
|
||||||
qCDebug(glLogging) << temp;
|
|
||||||
delete[] temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If linked get the binaries
|
|
||||||
if (linked && !binaryLoaded) {
|
|
||||||
GLint binaryLength = 0;
|
|
||||||
glGetProgramiv(glprogram, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
|
||||||
if (binaryLength > 0) {
|
|
||||||
cachedShader.binary.resize(binaryLength);
|
|
||||||
glGetProgramBinary(glprogram, binaryLength, NULL, &cachedShader.format, cachedShader.binary.data());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return glprogram;
|
return glprogram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLuint gl::buildProgram(const CachedShader& cachedShader) {
|
||||||
|
// A brand new program:
|
||||||
|
GLuint glprogram = glCreateProgram();
|
||||||
|
if (!glprogram) {
|
||||||
|
qCDebug(glLogging) << "GLShader::compileProgram - failed to create the gl program object";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
glProgramBinary(glprogram, cachedShader.format, cachedShader.binary.data(), (GLsizei)cachedShader.binary.size());
|
||||||
|
GLint linked = 0;
|
||||||
|
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||||
|
if (!linked) {
|
||||||
|
glDeleteProgram(glprogram);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return glprogram;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool gl::linkProgram(GLuint glprogram, std::string& message) {
|
||||||
|
glLinkProgram(glprogram);
|
||||||
|
|
||||||
|
GLint linked = 0;
|
||||||
|
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||||
|
::gl::getProgramInfoLog(glprogram, message);
|
||||||
|
if (!linked) {
|
||||||
|
qCDebug(glLogging) << "GLShader::compileProgram - failed to LINK the gl program object :";
|
||||||
|
qCDebug(glLogging) << message.c_str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.empty()) {
|
||||||
|
qCDebug(glLogging) << "GLShader::compileProgram - success:";
|
||||||
|
qCDebug(glLogging) << message.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const QString& getShaderCacheFile() {
|
const QString& getShaderCacheFile() {
|
||||||
static const QString SHADER_CACHE_FOLDER{ "shaders" };
|
static const QString SHADER_CACHE_FOLDER{ "shaders" };
|
||||||
static const QString SHADER_CACHE_FILE_NAME{ "cache.json" };
|
static const QString SHADER_CACHE_FILE_NAME{ "cache.json" };
|
||||||
|
@ -287,6 +435,7 @@ static const char* SHADER_JSON_SOURCE_KEY = "source";
|
||||||
static const char* SHADER_JSON_DATA_KEY = "data";
|
static const char* SHADER_JSON_DATA_KEY = "data";
|
||||||
|
|
||||||
void gl::loadShaderCache(ShaderCache& cache) {
|
void gl::loadShaderCache(ShaderCache& cache) {
|
||||||
|
#if !defined(DISABLE_QML)
|
||||||
QString shaderCacheFile = getShaderCacheFile();
|
QString shaderCacheFile = getShaderCacheFile();
|
||||||
if (QFileInfo(shaderCacheFile).exists()) {
|
if (QFileInfo(shaderCacheFile).exists()) {
|
||||||
QString json = FileUtils::readFile(shaderCacheFile);
|
QString json = FileUtils::readFile(shaderCacheFile);
|
||||||
|
@ -302,6 +451,7 @@ void gl::loadShaderCache(ShaderCache& cache) {
|
||||||
cachedShader.source = programObject[SHADER_JSON_SOURCE_KEY].toString().toStdString();
|
cachedShader.source = programObject[SHADER_JSON_SOURCE_KEY].toString().toStdString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl::saveShaderCache(const ShaderCache& cache) {
|
void gl::saveShaderCache(const ShaderCache& cache) {
|
||||||
|
|
|
@ -12,50 +12,114 @@
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
|
|
||||||
struct Uniform {
|
struct ShaderBinding {
|
||||||
std::string name;
|
int index;
|
||||||
GLint size{ -1 };
|
std::string name;
|
||||||
GLenum type{ GL_FLOAT };
|
GLint size{ -1 };
|
||||||
GLint location{ -1 };
|
GLint binding{ -1 };
|
||||||
void load(GLuint glprogram, int index);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
using Uniforms = std::vector<Uniform>;
|
struct Uniform : public ShaderBinding {
|
||||||
|
Uniform(){};
|
||||||
|
Uniform(GLint program, int index) { load(program, index); };
|
||||||
|
using Vector = std::vector<Uniform>;
|
||||||
|
GLenum type{ GL_FLOAT };
|
||||||
|
|
||||||
Uniforms loadUniforms(GLuint glprogram);
|
void load(GLuint glprogram, int index);
|
||||||
|
// Incredibly slow on mac, DO NOT USE
|
||||||
|
static Vector load(GLuint glprogram, const std::function<bool(const Uniform&)>& filter);
|
||||||
|
static Vector loadTextures(GLuint glprogram);
|
||||||
|
static Vector load(GLuint glprogram);
|
||||||
|
static Vector load(GLuint glprogram, const std::vector<GLuint>& indices);
|
||||||
|
static Vector load(GLuint glprogram, const std::vector<const char*>& names);
|
||||||
|
static Vector load(GLuint glprogram, const std::vector<std::string>& names);
|
||||||
|
static Uniform loadByName(GLuint glprogram, const std::string& names);
|
||||||
|
|
||||||
struct CachedShader {
|
template <typename C>
|
||||||
GLenum format{ 0 };
|
static Vector loadByName(GLuint glprogram, const C& names) {
|
||||||
std::string source;
|
if (names.empty()) {
|
||||||
std::vector<char> binary;
|
return {};
|
||||||
inline operator bool() const {
|
|
||||||
return format != 0 && !binary.empty();
|
|
||||||
}
|
}
|
||||||
};
|
std::vector<const char*> cnames;
|
||||||
|
cnames.reserve(names.size());
|
||||||
|
for (const auto& name : names) {
|
||||||
|
cnames.push_back(name.c_str());
|
||||||
|
}
|
||||||
|
return load(glprogram, cnames);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using ShaderCache = std::unordered_map<std::string, CachedShader>;
|
using Uniforms = Uniform::Vector;
|
||||||
|
|
||||||
std::string getShaderHash(const std::string& shaderSource);
|
struct UniformBlock : public ShaderBinding {
|
||||||
void loadShaderCache(ShaderCache& cache);
|
UniformBlock(){};
|
||||||
void saveShaderCache(const ShaderCache& cache);
|
UniformBlock(GLint program, int index) { load(program, index); };
|
||||||
|
|
||||||
|
using Vector = std::vector<UniformBlock>;
|
||||||
|
void load(GLuint glprogram, int index);
|
||||||
|
static Vector load(GLuint glprogram);
|
||||||
|
};
|
||||||
|
|
||||||
|
using UniformBlocks = UniformBlock::Vector;
|
||||||
|
|
||||||
|
struct Input : public ShaderBinding {
|
||||||
|
Input(){};
|
||||||
|
Input(GLint program, int index) { load(program, index); };
|
||||||
|
using Vector = std::vector<Uniform>;
|
||||||
|
GLenum type{ GL_FLOAT };
|
||||||
|
|
||||||
|
void load(GLuint glprogram, int index);
|
||||||
|
static Vector load(GLuint glprogram);
|
||||||
|
};
|
||||||
|
|
||||||
|
using Inputs = Input::Vector;
|
||||||
|
|
||||||
|
struct CachedShader {
|
||||||
|
GLenum format{ 0 };
|
||||||
|
std::string source;
|
||||||
|
std::vector<char> binary;
|
||||||
|
inline operator bool() const { return format != 0 && !binary.empty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using ShaderCache = std::unordered_map<std::string, CachedShader>;
|
||||||
|
|
||||||
|
std::string getShaderHash(const std::string& shaderSource);
|
||||||
|
void loadShaderCache(ShaderCache& cache);
|
||||||
|
void saveShaderCache(const ShaderCache& cache);
|
||||||
|
|
||||||
#ifdef SEPARATE_PROGRAM
|
#ifdef SEPARATE_PROGRAM
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, GLuint &shaderObject, GLuint &programObject, std::string& message);
|
bool compileShader(GLenum shaderDomain,
|
||||||
bool compileShader(GLenum shaderDomain, const std::vector<std::string>& shaderSources, GLuint &shaderObject, GLuint &programObject, std::string& message);
|
const std::string& shaderSource,
|
||||||
|
GLuint& shaderObject,
|
||||||
|
GLuint& programObject,
|
||||||
|
std::string& message);
|
||||||
|
bool compileShader(GLenum shaderDomain,
|
||||||
|
const std::vector<std::string>& shaderSources,
|
||||||
|
GLuint& shaderObject,
|
||||||
|
GLuint& programObject,
|
||||||
|
std::string& message);
|
||||||
#else
|
#else
|
||||||
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, GLuint &shaderObject, std::string& message);
|
bool compileShader(GLenum shaderDomain, const std::string& shaderSource, GLuint& shaderObject, std::string& message);
|
||||||
bool compileShader(GLenum shaderDomain, const std::vector<std::string>& shaderSources, GLuint &shaderObject, std::string& message);
|
bool compileShader(GLenum shaderDomain,
|
||||||
|
const std::vector<std::string>& shaderSources,
|
||||||
|
GLuint& shaderObject,
|
||||||
|
std::string& message);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& message, CachedShader& binary);
|
GLuint buildProgram(const std::vector<GLuint>& glshaders);
|
||||||
|
GLuint buildProgram(const CachedShader& binary);
|
||||||
}
|
bool linkProgram(GLuint glprogram, std::string& message);
|
||||||
|
void getShaderInfoLog(GLuint glshader, std::string& message);
|
||||||
|
void getProgramInfoLog(GLuint glprogram, std::string& message);
|
||||||
|
void getProgramBinary(GLuint glprogram, CachedShader& cachedShader);
|
||||||
|
} // namespace gl
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -100,11 +100,33 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||||
(&::gpu::gl::GLBackend::do_popProfileRange),
|
(&::gpu::gl::GLBackend::do_popProfileRange),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define GL_GET_INTEGER(NAME) glGetIntegerv(GL_##NAME, &const_cast<GLint&>(NAME));
|
||||||
|
|
||||||
|
GLint GLBackend::MAX_TEXTURE_IMAGE_UNITS{ 0 };
|
||||||
|
GLint GLBackend::MAX_UNIFORM_BUFFER_BINDINGS{ 0 };
|
||||||
|
GLint GLBackend::MAX_COMBINED_UNIFORM_BLOCKS{ 0 };
|
||||||
|
GLint GLBackend::MAX_COMBINED_TEXTURE_IMAGE_UNITS{ 0 };
|
||||||
|
GLint GLBackend::MAX_UNIFORM_BLOCK_SIZE{ 0 };
|
||||||
|
GLint GLBackend::UNIFORM_BUFFER_OFFSET_ALIGNMENT{ 1 };
|
||||||
|
|
||||||
void GLBackend::init() {
|
void GLBackend::init() {
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [] {
|
std::call_once(once, [] {
|
||||||
|
|
||||||
|
|
||||||
QString vendor{ (const char*)glGetString(GL_VENDOR) };
|
QString vendor{ (const char*)glGetString(GL_VENDOR) };
|
||||||
QString renderer{ (const char*)glGetString(GL_RENDERER) };
|
QString renderer{ (const char*)glGetString(GL_RENDERER) };
|
||||||
|
|
||||||
|
// Textures
|
||||||
|
GL_GET_INTEGER(MAX_TEXTURE_IMAGE_UNITS);
|
||||||
|
GL_GET_INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
|
||||||
|
|
||||||
|
// Uniform blocks
|
||||||
|
GL_GET_INTEGER(MAX_UNIFORM_BUFFER_BINDINGS);
|
||||||
|
GL_GET_INTEGER(MAX_COMBINED_UNIFORM_BLOCKS);
|
||||||
|
GL_GET_INTEGER(MAX_UNIFORM_BLOCK_SIZE);
|
||||||
|
GL_GET_INTEGER(UNIFORM_BUFFER_OFFSET_ALIGNMENT);
|
||||||
|
|
||||||
qCDebug(gpugllogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
|
qCDebug(gpugllogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
|
||||||
qCDebug(gpugllogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
qCDebug(gpugllogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||||
qCDebug(gpugllogging) << "GL Vendor: " << vendor;
|
qCDebug(gpugllogging) << "GL Vendor: " << vendor;
|
||||||
|
@ -115,15 +137,26 @@ void GLBackend::init() {
|
||||||
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
|
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
|
||||||
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
|
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
|
||||||
qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
|
qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
|
||||||
|
qCDebug(gpugllogging) << "Limits:";
|
||||||
|
qCDebug(gpugllogging) << "\tmax textures:" << MAX_TEXTURE_IMAGE_UNITS;
|
||||||
|
qCDebug(gpugllogging) << "\tmax texture binding:" << MAX_COMBINED_TEXTURE_IMAGE_UNITS;
|
||||||
|
qCDebug(gpugllogging) << "\tmax uniforms:" << MAX_UNIFORM_BUFFER_BINDINGS;
|
||||||
|
qCDebug(gpugllogging) << "\tmax uniform binding:" << MAX_COMBINED_UNIFORM_BLOCKS;
|
||||||
|
qCDebug(gpugllogging) << "\tmax uniform size:" << MAX_UNIFORM_BLOCK_SIZE;
|
||||||
|
qCDebug(gpugllogging) << "\tuniform alignment:" << UNIFORM_BUFFER_OFFSET_ALIGNMENT;
|
||||||
#if !defined(USE_GLES)
|
#if !defined(USE_GLES)
|
||||||
qCDebug(gpugllogging, "V-Sync is %s\n", (::gl::getSwapInterval() > 0 ? "ON" : "OFF"));
|
qCDebug(gpugllogging, "V-Sync is %s\n", (::gl::getSwapInterval() > 0 ? "ON" : "OFF"));
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLBackend::GLBackend(bool syncCache) {
|
||||||
|
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||||
|
initShaderBinaryCache();
|
||||||
|
}
|
||||||
|
|
||||||
GLBackend::GLBackend() {
|
GLBackend::GLBackend() {
|
||||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
|
|
||||||
initShaderBinaryCache();
|
initShaderBinaryCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,17 +419,11 @@ void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: As long as we have gl calls explicitely issued from interface
|
// TODO: As long as we have gl calls explicitely issued from interface
|
||||||
// code, we need to be able to record and batch these calls. THe long
|
// code, we need to be able to record and batch these calls. THe long
|
||||||
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
// term strategy is to get rid of any GL calls in favor of the HIFI GPU API
|
||||||
|
|
||||||
// As long as we don;t use several versions of shaders we can avoid this more complex code path
|
|
||||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
|
||||||
#define GET_UNIFORM_LOCATION(shaderUniformLoc) ((_pipeline._programShader) ? _pipeline._programShader->getUniformLocation(shaderUniformLoc, (GLShader::Version) isStereo()) : -1)
|
|
||||||
#else
|
|
||||||
#define GET_UNIFORM_LOCATION(shaderUniformLoc) shaderUniformLoc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) {
|
||||||
if (_pipeline._program == 0) {
|
if (_pipeline._program == 0) {
|
||||||
// We should call updatePipeline() to bind the program but we are not doing that
|
// We should call updatePipeline() to bind the program but we are not doing that
|
||||||
|
@ -405,8 +432,9 @@ void GLBackend::do_glUniform1i(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 1]._int);
|
||||||
glUniform1i(
|
glUniform1i(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
|
location,
|
||||||
batch._params[paramOffset + 0]._int);
|
batch._params[paramOffset + 0]._int);
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
@ -419,8 +447,9 @@ void GLBackend::do_glUniform1f(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 1]._int);
|
||||||
glUniform1f(
|
glUniform1f(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
|
location,
|
||||||
batch._params[paramOffset + 0]._float);
|
batch._params[paramOffset + 0]._float);
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
@ -432,8 +461,9 @@ void GLBackend::do_glUniform2f(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||||
glUniform2f(
|
glUniform2f(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
location,
|
||||||
batch._params[paramOffset + 1]._float,
|
batch._params[paramOffset + 1]._float,
|
||||||
batch._params[paramOffset + 0]._float);
|
batch._params[paramOffset + 0]._float);
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
|
@ -446,8 +476,9 @@ void GLBackend::do_glUniform3f(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 3]._int);
|
||||||
glUniform3f(
|
glUniform3f(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
location,
|
||||||
batch._params[paramOffset + 2]._float,
|
batch._params[paramOffset + 2]._float,
|
||||||
batch._params[paramOffset + 1]._float,
|
batch._params[paramOffset + 1]._float,
|
||||||
batch._params[paramOffset + 0]._float);
|
batch._params[paramOffset + 0]._float);
|
||||||
|
@ -461,8 +492,9 @@ void GLBackend::do_glUniform4f(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 4]._int);
|
||||||
glUniform4f(
|
glUniform4f(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 4]._int),
|
location,
|
||||||
batch._params[paramOffset + 3]._float,
|
batch._params[paramOffset + 3]._float,
|
||||||
batch._params[paramOffset + 2]._float,
|
batch._params[paramOffset + 2]._float,
|
||||||
batch._params[paramOffset + 1]._float,
|
batch._params[paramOffset + 1]._float,
|
||||||
|
@ -477,8 +509,9 @@ void GLBackend::do_glUniform3fv(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||||
glUniform3fv(
|
glUniform3fv(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
location,
|
||||||
batch._params[paramOffset + 1]._uint,
|
batch._params[paramOffset + 1]._uint,
|
||||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||||
|
|
||||||
|
@ -493,7 +526,7 @@ void GLBackend::do_glUniform4fv(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
|
||||||
GLint location = GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int);
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||||
GLsizei count = batch._params[paramOffset + 1]._uint;
|
GLsizei count = batch._params[paramOffset + 1]._uint;
|
||||||
const GLfloat* value = (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint);
|
const GLfloat* value = (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint);
|
||||||
glUniform4fv(location, count, value);
|
glUniform4fv(location, count, value);
|
||||||
|
@ -508,8 +541,9 @@ void GLBackend::do_glUniform4iv(const Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||||
glUniform4iv(
|
glUniform4iv(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
location,
|
||||||
batch._params[paramOffset + 1]._uint,
|
batch._params[paramOffset + 1]._uint,
|
||||||
(const GLint*)batch.readData(batch._params[paramOffset + 0]._uint));
|
(const GLint*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||||
|
|
||||||
|
@ -524,8 +558,9 @@ void GLBackend::do_glUniformMatrix3fv(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 3]._int);
|
||||||
glUniformMatrix3fv(
|
glUniformMatrix3fv(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
location,
|
||||||
batch._params[paramOffset + 2]._uint,
|
batch._params[paramOffset + 2]._uint,
|
||||||
batch._params[paramOffset + 1]._uint,
|
batch._params[paramOffset + 1]._uint,
|
||||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||||
|
@ -540,8 +575,9 @@ void GLBackend::do_glUniformMatrix4fv(const Batch& batch, size_t paramOffset) {
|
||||||
}
|
}
|
||||||
updatePipeline();
|
updatePipeline();
|
||||||
|
|
||||||
|
GLint location = getRealUniformLocation(batch._params[paramOffset + 3]._int);
|
||||||
glUniformMatrix4fv(
|
glUniformMatrix4fv(
|
||||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
location,
|
||||||
batch._params[paramOffset + 2]._uint,
|
batch._params[paramOffset + 2]._uint,
|
||||||
batch._params[paramOffset + 1]._uint,
|
batch._params[paramOffset + 1]._uint,
|
||||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||||
|
|
|
@ -68,7 +68,29 @@ protected:
|
||||||
explicit GLBackend(bool syncCache);
|
explicit GLBackend(bool syncCache);
|
||||||
GLBackend();
|
GLBackend();
|
||||||
public:
|
public:
|
||||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
|
|
||||||
|
#if defined(USE_GLES)
|
||||||
|
// https://www.khronos.org/registry/OpenGL-Refpages/es3/html/glGet.xhtml
|
||||||
|
static const GLint MIN_REQUIRED_TEXTURE_IMAGE_UNITS = 16;
|
||||||
|
static const GLint MIN_REQUIRED_COMBINED_UNIFORM_BLOCKS = 60;
|
||||||
|
static const GLint MIN_REQUIRED_COMBINED_TEXTURE_IMAGE_UNITS = 48;
|
||||||
|
static const GLint MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS = 72;
|
||||||
|
static const GLint MIN_REQUIRED_UNIFORM_LOCATIONS = 1024;
|
||||||
|
#else
|
||||||
|
// https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml
|
||||||
|
static const GLint MIN_REQUIRED_TEXTURE_IMAGE_UNITS = 16;
|
||||||
|
static const GLint MIN_REQUIRED_COMBINED_UNIFORM_BLOCKS = 70;
|
||||||
|
static const GLint MIN_REQUIRED_COMBINED_TEXTURE_IMAGE_UNITS = 48;
|
||||||
|
static const GLint MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS = 36;
|
||||||
|
static const GLint MIN_REQUIRED_UNIFORM_LOCATIONS = 1024;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static GLint MAX_TEXTURE_IMAGE_UNITS;
|
||||||
|
static GLint MAX_UNIFORM_BUFFER_BINDINGS;
|
||||||
|
static GLint MAX_COMBINED_UNIFORM_BLOCKS;
|
||||||
|
static GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS;
|
||||||
|
static GLint MAX_UNIFORM_BLOCK_SIZE;
|
||||||
|
static GLint UNIFORM_BUFFER_OFFSET_ALIGNMENT;
|
||||||
|
|
||||||
virtual ~GLBackend();
|
virtual ~GLBackend();
|
||||||
|
|
||||||
|
@ -107,7 +129,6 @@ public:
|
||||||
|
|
||||||
// Texture Tables offers 2 dedicated slot (taken from the ubo slots)
|
// Texture Tables offers 2 dedicated slot (taken from the ubo slots)
|
||||||
static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2;
|
static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2;
|
||||||
static const int RESOURCE_TABLE_TEXTURE_SLOT_OFFSET = TRANSFORM_CAMERA_SLOT + 1;
|
|
||||||
size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; }
|
size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; }
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,6 +259,7 @@ public:
|
||||||
bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); }
|
bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual GLint getRealUniformLocation(GLint location) const;
|
||||||
|
|
||||||
void recycle() const override;
|
void recycle() const override;
|
||||||
|
|
||||||
|
@ -247,7 +269,6 @@ protected:
|
||||||
|
|
||||||
static const size_t INVALID_OFFSET = (size_t)-1;
|
static const size_t INVALID_OFFSET = (size_t)-1;
|
||||||
bool _inRenderTransferPass { false };
|
bool _inRenderTransferPass { false };
|
||||||
int32_t _uboAlignment { 0 };
|
|
||||||
int _currentDraw { -1 };
|
int _currentDraw { -1 };
|
||||||
|
|
||||||
std::list<std::string> profileRanges;
|
std::list<std::string> profileRanges;
|
||||||
|
@ -394,10 +415,24 @@ protected:
|
||||||
virtual void transferTransformState(const Batch& batch) const = 0;
|
virtual void transferTransformState(const Batch& batch) const = 0;
|
||||||
|
|
||||||
struct UniformStageState {
|
struct UniformStageState {
|
||||||
std::array<BufferPointer, MAX_NUM_UNIFORM_BUFFERS> _buffers;
|
struct BufferState {
|
||||||
//Buffers _buffers { };
|
BufferPointer buffer;
|
||||||
|
GLintptr offset{ 0 };
|
||||||
|
GLsizeiptr size{ 0 };
|
||||||
|
BufferState(const BufferPointer& buffer = nullptr, GLintptr offset = 0, GLsizeiptr size = 0);
|
||||||
|
bool operator ==(BufferState& other) const {
|
||||||
|
return offset == other.offset && size == other.size && buffer == other.buffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// MAX_NUM_UNIFORM_BUFFERS-1 is the max uniform index BATCHES are allowed to set, but
|
||||||
|
// MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS is used here because the backend sets some
|
||||||
|
// internal UBOs for things like camera correction
|
||||||
|
std::array<BufferState, MIN_REQUIRED_UNIFORM_BUFFER_BINDINGS> _buffers;
|
||||||
} _uniform;
|
} _uniform;
|
||||||
|
|
||||||
|
// Helper function that provides common code
|
||||||
|
void bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GLintptr offset = 0, GLsizeiptr size = 0);
|
||||||
void releaseUniformBuffer(uint32_t slot);
|
void releaseUniformBuffer(uint32_t slot);
|
||||||
void resetUniformStage();
|
void resetUniformStage();
|
||||||
|
|
||||||
|
@ -410,6 +445,7 @@ protected:
|
||||||
// do_setResourceTextureTable (in non-bindless mode)
|
// do_setResourceTextureTable (in non-bindless mode)
|
||||||
void bindResourceTexture(uint32_t slot, const TexturePointer& texture);
|
void bindResourceTexture(uint32_t slot, const TexturePointer& texture);
|
||||||
|
|
||||||
|
|
||||||
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
|
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
|
||||||
void releaseResourceTexture(uint32_t slot);
|
void releaseResourceTexture(uint32_t slot);
|
||||||
|
|
||||||
|
@ -436,7 +472,7 @@ protected:
|
||||||
PipelinePointer _pipeline;
|
PipelinePointer _pipeline;
|
||||||
|
|
||||||
GLuint _program { 0 };
|
GLuint _program { 0 };
|
||||||
GLint _cameraCorrectionLocation { -1 };
|
bool _cameraCorrection { false };
|
||||||
GLShader* _programShader { nullptr };
|
GLShader* _programShader { nullptr };
|
||||||
bool _invalidProgram { false };
|
bool _invalidProgram { false };
|
||||||
|
|
||||||
|
@ -457,6 +493,7 @@ protected:
|
||||||
} _pipeline;
|
} _pipeline;
|
||||||
|
|
||||||
// Backend dependant compilation of the shader
|
// Backend dependant 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* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler);
|
||||||
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
||||||
virtual std::string getBackendShaderHeader() const = 0;
|
virtual std::string getBackendShaderHeader() const = 0;
|
||||||
|
@ -467,7 +504,6 @@ protected:
|
||||||
// The program string returned can be used as a key for a cache of shader binaries
|
// 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
|
// 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, int version) final;
|
||||||
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
|
||||||
class ElementResource {
|
class ElementResource {
|
||||||
public:
|
public:
|
||||||
gpu::Element _element;
|
gpu::Element _element;
|
||||||
|
@ -475,15 +511,6 @@ protected:
|
||||||
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
||||||
};
|
};
|
||||||
ElementResource getFormatFromGLUniform(GLenum gltype);
|
ElementResource getFormatFromGLUniform(GLenum gltype);
|
||||||
static const GLint UNUSED_SLOT {-1};
|
|
||||||
static bool isUnusedSlot(GLint binding) { return (binding == UNUSED_SLOT); }
|
|
||||||
virtual int makeUniformSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings,
|
|
||||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
|
||||||
virtual int makeUniformBlockSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
|
||||||
virtual int makeResourceBufferSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers) = 0;
|
|
||||||
virtual int makeInputSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
|
|
||||||
virtual int makeOutputSlots(const ShaderObject& program, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
|
|
||||||
|
|
||||||
|
|
||||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||||
void syncOutputStateCache();
|
void syncOutputStateCache();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
#include "GLBackend.h"
|
#include "GLBackend.h"
|
||||||
#include <gpu/TextureTable.h>
|
#include <gpu/TextureTable.h>
|
||||||
|
#include <gpu/ShaderConstants.h>
|
||||||
|
|
||||||
#include "GLShared.h"
|
#include "GLShared.h"
|
||||||
#include "GLPipeline.h"
|
#include "GLPipeline.h"
|
||||||
|
@ -36,7 +37,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
_pipeline._pipeline.reset();
|
_pipeline._pipeline.reset();
|
||||||
|
|
||||||
_pipeline._program = 0;
|
_pipeline._program = 0;
|
||||||
_pipeline._cameraCorrectionLocation = -1;
|
_pipeline._cameraCorrection = false;
|
||||||
_pipeline._programShader = nullptr;
|
_pipeline._programShader = nullptr;
|
||||||
_pipeline._invalidProgram = true;
|
_pipeline._invalidProgram = true;
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
_pipeline._program = glprogram;
|
_pipeline._program = glprogram;
|
||||||
_pipeline._programShader = pipelineObject->_program;
|
_pipeline._programShader = pipelineObject->_program;
|
||||||
_pipeline._invalidProgram = true;
|
_pipeline._invalidProgram = true;
|
||||||
_pipeline._cameraCorrectionLocation = pipelineObject->_cameraCorrection;
|
_pipeline._cameraCorrection = pipelineObject->_cameraCorrection;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now for the state
|
// Now for the state
|
||||||
|
@ -78,16 +79,13 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||||
// THis should be done on Pipeline::update...
|
// THis should be done on Pipeline::update...
|
||||||
if (_pipeline._invalidProgram) {
|
if (_pipeline._invalidProgram) {
|
||||||
glUseProgram(_pipeline._program);
|
glUseProgram(_pipeline._program);
|
||||||
if (_pipeline._cameraCorrectionLocation != -1) {
|
if (_pipeline._cameraCorrection) {
|
||||||
gl::GLBuffer* cameraCorrectionBuffer = nullptr;
|
|
||||||
if (_transform._viewCorrectionEnabled) {
|
|
||||||
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer);
|
|
||||||
} else {
|
|
||||||
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBufferIdentity._buffer);
|
|
||||||
}
|
|
||||||
// Invalidate uniform buffer cache slot
|
// Invalidate uniform buffer cache slot
|
||||||
_uniform._buffers[_pipeline._cameraCorrectionLocation].reset();
|
_uniform._buffers[gpu::slot::buffer::CameraCorrection] = {};
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection));
|
auto& cameraCorrectionBuffer = _transform._viewCorrectionEnabled ?
|
||||||
|
_pipeline._cameraCorrectionBuffer._buffer :
|
||||||
|
_pipeline._cameraCorrectionBufferIdentity._buffer;
|
||||||
|
bindUniformBuffer(gpu::slot::buffer::CameraCorrection, cameraCorrectionBuffer, 0, sizeof(CameraCorrection));
|
||||||
}
|
}
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
_pipeline._invalidProgram = false;
|
_pipeline._invalidProgram = false;
|
||||||
|
@ -138,15 +136,18 @@ void GLBackend::resetPipelineStage() {
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLBackend::UniformStageState::BufferState::BufferState(const BufferPointer& buffer, GLintptr offset, GLsizeiptr size)
|
||||||
|
: buffer(buffer), offset(offset), size(size) {}
|
||||||
|
|
||||||
void GLBackend::releaseUniformBuffer(uint32_t slot) {
|
void GLBackend::releaseUniformBuffer(uint32_t slot) {
|
||||||
auto& buf = _uniform._buffers[slot];
|
auto& buf = _uniform._buffers[slot];
|
||||||
if (buf) {
|
if (buf.buffer) {
|
||||||
auto* object = Backend::getGPUObject<GLBuffer>(*buf);
|
auto* object = Backend::getGPUObject<GLBuffer>(*buf.buffer);
|
||||||
if (object) {
|
if (object) {
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
buf.reset();
|
buf = UniformStageState::BufferState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +157,33 @@ void GLBackend::resetUniformStage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLBackend::bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GLintptr offset, GLsizeiptr size) {
|
||||||
|
if (!buffer) {
|
||||||
|
releaseUniformBuffer(slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformStageState::BufferState bufferState{ buffer, offset, size };
|
||||||
|
|
||||||
|
// check cache before thinking
|
||||||
|
if (_uniform._buffers[slot] == bufferState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync BufferObject
|
||||||
|
auto* object = syncGPUObject(*bufferState.buffer);
|
||||||
|
if (object) {
|
||||||
|
glBindBufferRange(GL_UNIFORM_BUFFER, slot, object->_buffer, bufferState.offset, bufferState.size);
|
||||||
|
|
||||||
|
_uniform._buffers[slot] = bufferState;
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
|
} else {
|
||||||
|
releaseUniformBuffer(slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
|
void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||||
if (slot > (GLuint)MAX_NUM_UNIFORM_BUFFERS) {
|
if (slot > (GLuint)MAX_NUM_UNIFORM_BUFFERS) {
|
||||||
|
@ -163,31 +191,12 @@ void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
|
||||||
<< " which doesn't exist. MaxNumUniformBuffers = " << getMaxNumUniformBuffers();
|
<< " which doesn't exist. MaxNumUniformBuffers = " << getMaxNumUniformBuffers();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||||
|
|
||||||
if (!uniformBuffer) {
|
bindUniformBuffer(slot, uniformBuffer, rangeStart, rangeSize);
|
||||||
releaseUniformBuffer(slot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check cache before thinking
|
|
||||||
if (_uniform._buffers[slot] == uniformBuffer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync BufferObject
|
|
||||||
auto* object = syncGPUObject(*uniformBuffer);
|
|
||||||
if (object) {
|
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, object->_buffer, rangeStart, rangeSize);
|
|
||||||
|
|
||||||
_uniform._buffers[slot] = uniformBuffer;
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
} else {
|
|
||||||
releaseUniformBuffer(slot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLBackend::releaseResourceTexture(uint32_t slot) {
|
void GLBackend::releaseResourceTexture(uint32_t slot) {
|
||||||
|
|
|
@ -13,7 +13,6 @@ using namespace gpu;
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
using CachedShader = ::gl::CachedShader;
|
using CachedShader = ::gl::CachedShader;
|
||||||
|
|
||||||
|
|
||||||
// Shader domain
|
// Shader domain
|
||||||
static const size_t NUM_SHADER_DOMAINS = 3;
|
static const size_t NUM_SHADER_DOMAINS = 3;
|
||||||
static_assert(Shader::Type::NUM_DOMAINS == NUM_SHADER_DOMAINS, "GL shader domains must equal defined GPU shader domains");
|
static_assert(Shader::Type::NUM_DOMAINS == NUM_SHADER_DOMAINS, "GL shader domains must equal defined GPU shader domains");
|
||||||
|
@ -178,24 +177,22 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GLuint glprogram = 0;
|
GLuint glprogram = 0;
|
||||||
|
|
||||||
// If we have a cached binary program, try to load it instead of compiling the individual shaders
|
// If we have a cached binary program, try to load it instead of compiling the individual shaders
|
||||||
if (cachedBinary) {
|
if (cachedBinary) {
|
||||||
glprogram = ::gl::compileProgram({}, compilationLogs[version].message, cachedBinary);
|
glprogram = ::gl::buildProgram(cachedBinary);
|
||||||
if (0 != glprogram) {
|
if (0 != glprogram) {
|
||||||
++gpuBinaryShadersLoaded;
|
++gpuBinaryShadersLoaded;
|
||||||
}
|
} else {
|
||||||
}
|
cachedBinary = CachedShader();
|
||||||
|
|
||||||
// If we have no program, then either no cached binary, or the binary failed to load (perhaps a GPU driver update invalidated the cache)
|
|
||||||
if (0 == glprogram) {
|
|
||||||
cachedBinary = CachedShader();
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||||
_shaderBinaryCache._binaries.erase(hash);
|
_shaderBinaryCache._binaries.erase(hash);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have no program, then either no cached binary, or the binary failed to load
|
||||||
|
// (perhaps a GPU driver update invalidated the cache)
|
||||||
|
if (0 == glprogram) {
|
||||||
// Let's go through every shaders and make sure they are ready to go
|
// Let's go through every shaders and make sure they are ready to go
|
||||||
std::vector<GLuint> shaderGLObjects;
|
std::vector<GLuint> shaderGLObjects;
|
||||||
shaderGLObjects.reserve(program.getShaders().size());
|
shaderGLObjects.reserve(program.getShaders().size());
|
||||||
|
@ -212,8 +209,16 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, cachedBinary);
|
glprogram = ::gl::buildProgram(shaderGLObjects);
|
||||||
if (cachedBinary) {
|
|
||||||
|
if (!::gl::linkProgram(glprogram, compilationLogs[version].message)) {
|
||||||
|
glDeleteProgram(glprogram);
|
||||||
|
glprogram = 0;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cachedBinary) {
|
||||||
|
::gl::getProgramBinary(glprogram, cachedBinary);
|
||||||
cachedBinary.source = programSource;
|
cachedBinary.source = programSource;
|
||||||
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||||
_shaderBinaryCache._binaries[hash] = cachedBinary;
|
_shaderBinaryCache._binaries[hash] = cachedBinary;
|
||||||
|
@ -228,7 +233,7 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
||||||
|
|
||||||
compilationLogs[version].compiled = true;
|
compilationLogs[version].compiled = true;
|
||||||
programObject.glprogram = glprogram;
|
programObject.glprogram = glprogram;
|
||||||
makeProgramBindings(programObject);
|
postLinkProgram(programObject, program);
|
||||||
}
|
}
|
||||||
// Compilation feedback
|
// Compilation feedback
|
||||||
program.setCompilationLogs(compilationLogs);
|
program.setCompilationLogs(compilationLogs);
|
||||||
|
@ -236,10 +241,45 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
||||||
// So far so good, the program versions have all been created successfully
|
// So far so good, the program versions have all been created successfully
|
||||||
GLShader* object = new GLShader(this->shared_from_this());
|
GLShader* object = new GLShader(this->shared_from_this());
|
||||||
object->_shaderObjects = programObjects;
|
object->_shaderObjects = programObjects;
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const GLint INVALID_UNIFORM_INDEX = -1;
|
||||||
|
|
||||||
|
GLint GLBackend::getRealUniformLocation(GLint location) const {
|
||||||
|
auto& shader = _pipeline._programShader->_shaderObjects[(GLShader::Version)isStereo()];
|
||||||
|
auto itr = shader.uniformRemap.find(location);
|
||||||
|
if (itr == shader.uniformRemap.end()) {
|
||||||
|
// This shouldn't happen, because we use reflection to determine all the possible
|
||||||
|
// uniforms. If someone is requesting a uniform that isn't in the remapping structure
|
||||||
|
// that's a bug from the calling code, because it means that location wasn't in the
|
||||||
|
// reflection
|
||||||
|
qWarning() << "Unexpected location requested for shader";
|
||||||
|
return INVALID_UNIFORM_INDEX;
|
||||||
|
}
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Pre-initialize all the uniforms with an invalid location
|
||||||
|
for (const auto& entry : expectedLocationsByName) {
|
||||||
|
uniformRemap[entry.second] = INVALID_UNIFORM_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now load up all the actual found uniform location
|
||||||
|
for (const auto& uniform : uniforms) {
|
||||||
|
const auto& name = uniform.name;
|
||||||
|
const auto& expectedLocation = expectedLocationsByName.at(name);
|
||||||
|
const auto& location = uniform.binding;
|
||||||
|
uniformRemap[expectedLocation] = location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) {
|
GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) {
|
||||||
switch (gltype) {
|
switch (gltype) {
|
||||||
|
@ -405,197 +445,8 @@ GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) {
|
||||||
//{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
//{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
||||||
//{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
//{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
||||||
//{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
//{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int GLBackend::makeUniformSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,
|
|
||||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
|
||||||
auto& glprogram = shaderProgram.glprogram;
|
|
||||||
|
|
||||||
for (const auto& uniform : shaderProgram.uniforms) {
|
|
||||||
const auto& type = uniform.type;
|
|
||||||
const auto& location = uniform.location;
|
|
||||||
const auto& size = uniform.size;
|
|
||||||
const auto& name = uniform.name;
|
|
||||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
|
||||||
|
|
||||||
// Try to make sense of the gltype
|
|
||||||
auto elementResource = getFormatFromGLUniform(type);
|
|
||||||
|
|
||||||
// The uniform as a standard var type
|
|
||||||
if (location != INVALID_UNIFORM_LOCATION) {
|
|
||||||
auto sname = uniform.name;
|
|
||||||
// Let's make sure the name doesn't contains an array element
|
|
||||||
auto foundBracket = sname.find_first_of('[');
|
|
||||||
if (foundBracket != std::string::npos) {
|
|
||||||
// std::string arrayname = sname.substr(0, foundBracket);
|
|
||||||
|
|
||||||
if (sname[foundBracket + 1] == '0') {
|
|
||||||
sname = sname.substr(0, foundBracket);
|
|
||||||
} else {
|
|
||||||
// skip this uniform since it's not the first element of an array
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elementResource._resource == Resource::BUFFER) {
|
|
||||||
uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource));
|
|
||||||
} else {
|
|
||||||
// For texture/Sampler, the location is the actual binding value
|
|
||||||
GLint binding = -1;
|
|
||||||
glGetUniformiv(glprogram, location, &binding);
|
|
||||||
|
|
||||||
auto requestedBinding = slotBindings.find(std::string(sname));
|
|
||||||
if (requestedBinding != slotBindings.end()) {
|
|
||||||
if (binding != (*requestedBinding)._location) {
|
|
||||||
binding = (*requestedBinding)._location;
|
|
||||||
for (auto i = 0; i < size; i++) {
|
|
||||||
// If we are working with an array of textures, reserve for each elemet
|
|
||||||
glProgramUniform1i(glprogram, location+i, binding+i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
|
||||||
samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<uint32_t>(shaderProgram.uniforms.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLBackend::makeUniformBlockSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
|
||||||
const auto& glprogram = shaderProgram.glprogram;
|
|
||||||
GLint buffersCount = 0;
|
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
|
|
||||||
|
|
||||||
// fast exit
|
|
||||||
if (buffersCount == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint maxNumUniformBufferSlots = 0;
|
|
||||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots);
|
|
||||||
std::vector<GLint> uniformBufferSlotMap(maxNumUniformBufferSlots, -1);
|
|
||||||
|
|
||||||
struct UniformBlockInfo {
|
|
||||||
using Vector = std::vector<UniformBlockInfo>;
|
|
||||||
const GLuint index{ 0 };
|
|
||||||
const std::string name;
|
|
||||||
GLint binding{ -1 };
|
|
||||||
GLint size{ 0 };
|
|
||||||
|
|
||||||
static std::string getName(GLuint glprogram, GLuint i) {
|
|
||||||
static const GLint NAME_LENGTH = 256;
|
|
||||||
GLint length = 0;
|
|
||||||
GLchar nameBuffer[NAME_LENGTH];
|
|
||||||
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
|
|
||||||
glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer);
|
|
||||||
return std::string(nameBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) {
|
|
||||||
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding);
|
|
||||||
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
UniformBlockInfo::Vector uniformBlocks;
|
|
||||||
uniformBlocks.reserve(buffersCount);
|
|
||||||
for (int i = 0; i < buffersCount; i++) {
|
|
||||||
uniformBlocks.push_back(UniformBlockInfo(glprogram, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : uniformBlocks) {
|
|
||||||
auto requestedBinding = slotBindings.find(info.name);
|
|
||||||
if (requestedBinding != slotBindings.end()) {
|
|
||||||
info.binding = (*requestedBinding)._location;
|
|
||||||
glUniformBlockBinding(glprogram, info.index, info.binding);
|
|
||||||
uniformBufferSlotMap[info.binding] = info.index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : uniformBlocks) {
|
|
||||||
if (slotBindings.count(info.name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the binding is 0, or the binding maps to an already used binding
|
|
||||||
if (info.binding == 0 || !isUnusedSlot(uniformBufferSlotMap[info.binding])) {
|
|
||||||
// If no binding was assigned then just do it finding a free slot
|
|
||||||
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), GLBackend::isUnusedSlot);
|
|
||||||
if (slotIt != uniformBufferSlotMap.end()) {
|
|
||||||
info.binding = slotIt - uniformBufferSlotMap.begin();
|
|
||||||
glUniformBlockBinding(glprogram, info.index, info.binding);
|
|
||||||
} else {
|
|
||||||
// This should neve happen, an active ubo cannot find an available slot among the max available?!
|
|
||||||
info.binding = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uniformBufferSlotMap[info.binding] = info.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : uniformBlocks) {
|
|
||||||
static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
|
|
||||||
buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size));
|
|
||||||
}
|
|
||||||
return buffersCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLBackend::makeInputSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
|
||||||
const auto& glprogram = shaderProgram.glprogram;
|
|
||||||
GLint inputsCount = 0;
|
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < inputsCount; i++) {
|
|
||||||
const GLint NAME_LENGTH = 256;
|
|
||||||
GLchar name[NAME_LENGTH];
|
|
||||||
GLint length = 0;
|
|
||||||
GLint size = 0;
|
|
||||||
GLenum type = 0;
|
|
||||||
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
|
||||||
|
|
||||||
GLint binding = glGetAttribLocation(glprogram, name);
|
|
||||||
|
|
||||||
auto elementResource = getFormatFromGLUniform(type);
|
|
||||||
inputs.insert(Shader::Slot(name, binding, elementResource._element, -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GLBackend::makeOutputSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
|
|
||||||
/* GLint outputsCount = 0;
|
|
||||||
|
|
||||||
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < inputsCount; i++) {
|
|
||||||
const GLint NAME_LENGTH = 256;
|
|
||||||
GLchar name[NAME_LENGTH];
|
|
||||||
GLint length = 0;
|
|
||||||
GLint size = 0;
|
|
||||||
GLenum type = 0;
|
|
||||||
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
|
||||||
|
|
||||||
auto element = getFormatFromGLUniform(type);
|
|
||||||
outputs.insert(Shader::Slot(name, i, element));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return 0; //inputsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLBackend::makeProgramBindings(ShaderObject& shaderObject) {
|
|
||||||
if (!shaderObject.glprogram) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void GLBackend::initShaderBinaryCache() {
|
void GLBackend::initShaderBinaryCache() {
|
||||||
GLint numBinFormats = 0;
|
GLint numBinFormats = 0;
|
||||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
|
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numBinFormats);
|
||||||
|
|
|
@ -168,9 +168,8 @@ void GLBackend::TransformStageState::update(size_t commandIndex, const StereoSta
|
||||||
|
|
||||||
void GLBackend::TransformStageState::bindCurrentCamera(int eye) const {
|
void GLBackend::TransformStageState::bindCurrentCamera(int eye) const {
|
||||||
if (_currentCameraOffset != INVALID_OFFSET) {
|
if (_currentCameraOffset != INVALID_OFFSET) {
|
||||||
static_assert(TRANSFORM_CAMERA_SLOT >= MAX_NUM_UNIFORM_BUFFERS, "TransformCamera may overlap pipeline uniform buffer slots. Invalidate uniform buffer slot cache for safety (call _uniform._buffers[TRANSFORM_CAMERA_SLOT].reset()).");
|
static_assert(slot::buffer::Buffer::CameraTransform >= MAX_NUM_UNIFORM_BUFFERS, "TransformCamera may overlap pipeline uniform buffer slots. Invalidate uniform buffer slot cache for safety (call _uniform._buffers[TRANSFORM_CAMERA_SLOT].reset()).");
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize,
|
glBindBufferRange(GL_UNIFORM_BUFFER, slot::buffer::Buffer::CameraTransform, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize, sizeof(CameraBufferElement));
|
||||||
sizeof(CameraBufferElement));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "GLShader.h"
|
#include "GLShader.h"
|
||||||
#include "GLState.h"
|
#include "GLState.h"
|
||||||
|
#include "GLBackend.h"
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
|
@ -51,7 +52,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) {
|
||||||
// Special case for view correction matrices, any pipeline that declares the correction buffer
|
// Special case for view correction matrices, any pipeline that declares the correction buffer
|
||||||
// uniform will automatically have it provided without any client code necessary.
|
// uniform will automatically have it provided without any client code necessary.
|
||||||
// Required for stable lighting in the HMD.
|
// Required for stable lighting in the HMD.
|
||||||
object->_cameraCorrection = shader->getUniformBuffers().findLocation("cameraCorrectionBuffer");
|
object->_cameraCorrection = shader->getUniformBuffers().isValid(gpu::slot::buffer::CameraCorrection);
|
||||||
object->_program = programObject;
|
object->_program = programObject;
|
||||||
object->_state = stateObject;
|
object->_state = stateObject;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ public:
|
||||||
GLState* _state { nullptr };
|
GLState* _state { nullptr };
|
||||||
// Bit of a hack, any pipeline can need the camera correction buffer at execution time, so
|
// Bit of a hack, any pipeline can need the camera correction buffer at execution time, so
|
||||||
// we store whether a given pipeline has declared the uniform buffer for it.
|
// we store whether a given pipeline has declared the uniform buffer for it.
|
||||||
int32 _cameraCorrection { -1 };
|
bool _cameraCorrection{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -56,52 +56,5 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader:
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
|
||||||
|
|
||||||
// First make sure the Shader has been compiled
|
|
||||||
GLShader* object = sync(backend, shader, handler);
|
|
||||||
if (!object) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply bindings to all program versions and generate list of slots from default version
|
|
||||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
|
||||||
auto& shaderObject = object->_shaderObjects[version];
|
|
||||||
if (shaderObject.glprogram) {
|
|
||||||
shaderObject.uniforms = ::gl::loadUniforms(shaderObject.glprogram);
|
|
||||||
Shader::SlotSet buffers;
|
|
||||||
backend.makeUniformBlockSlots(shaderObject, slotBindings, buffers);
|
|
||||||
|
|
||||||
Shader::SlotSet uniforms;
|
|
||||||
Shader::SlotSet textures;
|
|
||||||
Shader::SlotSet samplers;
|
|
||||||
backend.makeUniformSlots(shaderObject, slotBindings, uniforms, textures, samplers);
|
|
||||||
|
|
||||||
Shader::SlotSet resourceBuffers;
|
|
||||||
backend.makeResourceBufferSlots(shaderObject, slotBindings, resourceBuffers);
|
|
||||||
|
|
||||||
Shader::SlotSet inputs;
|
|
||||||
backend.makeInputSlots(shaderObject, slotBindings, inputs);
|
|
||||||
|
|
||||||
Shader::SlotSet outputs;
|
|
||||||
backend.makeOutputSlots(shaderObject, slotBindings, outputs);
|
|
||||||
|
|
||||||
// Define the public slots only from the default version
|
|
||||||
if (version == 0) {
|
|
||||||
shader.defineSlots(uniforms, buffers, resourceBuffers, textures, samplers, inputs, outputs);
|
|
||||||
} // else
|
|
||||||
{
|
|
||||||
GLShader::UniformMapping mapping;
|
|
||||||
for (auto srcUniform : shader.getUniforms()) {
|
|
||||||
mapping[srcUniform._location] = uniforms.findLocation(srcUniform._name);
|
|
||||||
}
|
|
||||||
object->_uniformMappings.push_back(mapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,18 +14,16 @@
|
||||||
namespace gpu { namespace gl {
|
namespace gpu { namespace gl {
|
||||||
|
|
||||||
struct ShaderObject {
|
struct ShaderObject {
|
||||||
using Uniforms = ::gl::Uniforms;
|
|
||||||
GLuint glshader { 0 };
|
GLuint glshader { 0 };
|
||||||
GLuint glprogram { 0 };
|
GLuint glprogram { 0 };
|
||||||
GLint transformCameraSlot { -1 };
|
|
||||||
GLint transformObjectSlot { -1 };
|
using LocationMap = std::unordered_map <GLuint, GLuint>;
|
||||||
Uniforms uniforms;
|
LocationMap uniformRemap;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GLShader : public GPUObject {
|
class GLShader : public GPUObject {
|
||||||
public:
|
public:
|
||||||
static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
|
static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);
|
||||||
static bool makeProgram(GLBackend& backend, Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler);
|
|
||||||
|
|
||||||
enum Version {
|
enum Version {
|
||||||
Mono = 0,
|
Mono = 0,
|
||||||
|
@ -44,22 +42,11 @@ public:
|
||||||
~GLShader();
|
~GLShader();
|
||||||
|
|
||||||
ShaderObjects _shaderObjects;
|
ShaderObjects _shaderObjects;
|
||||||
UniformMappingVersions _uniformMappings;
|
|
||||||
|
|
||||||
GLuint getProgram(Version version = Mono) const {
|
GLuint getProgram(Version version = Mono) const {
|
||||||
return _shaderObjects[version].glprogram;
|
return _shaderObjects[version].glprogram;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLint getUniformLocation(GLint srcLoc, Version version = Mono) const {
|
|
||||||
// This check protect against potential invalid src location for this shader, if unknown then return -1.
|
|
||||||
const auto& mapping = _uniformMappings[version];
|
|
||||||
auto found = mapping.find(srcLoc);
|
|
||||||
if (found == mapping.end()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return found->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::weak_ptr<GLBackend> _backend;
|
const std::weak_ptr<GLBackend> _backend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -129,9 +129,10 @@ void GLBackend::killTextureManagementStage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TexturePointer> GLTextureTransferEngine::getAllTextures() {
|
std::vector<TexturePointer> GLTextureTransferEngine::getAllTextures() {
|
||||||
std::remove_if(_registeredTextures.begin(), _registeredTextures.end(), [&](const std::weak_ptr<Texture>& weak) -> bool {
|
auto expiredBegin = std::remove_if(_registeredTextures.begin(), _registeredTextures.end(), [&](const std::weak_ptr<Texture>& weak) -> bool {
|
||||||
return weak.expired();
|
return weak.expired();
|
||||||
});
|
});
|
||||||
|
_registeredTextures.erase(expiredBegin, _registeredTextures.end());
|
||||||
|
|
||||||
std::vector<TexturePointer> result;
|
std::vector<TexturePointer> result;
|
||||||
result.reserve(_registeredTextures.size());
|
result.reserve(_registeredTextures.size());
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include <shared/GlobalAppProperties.h>
|
#include <shared/GlobalAppProperties.h>
|
||||||
#include <gl/QOpenGLContextWrapper.h>
|
#include <gl/QOpenGLContextWrapper.h>
|
||||||
|
#include <gl/GLHelpers.h>
|
||||||
#include <gpu/gl/GLShader.h>
|
#include <gpu/gl/GLShader.h>
|
||||||
|
|
||||||
#include "../gl41/GL41Backend.h"
|
#include "../gl41/GL41Backend.h"
|
||||||
|
@ -24,9 +25,6 @@
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
|
|
||||||
static const QString DEBUG_FLAG("HIFI_DISABLE_OPENGL_45");
|
|
||||||
static bool disableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
|
||||||
|
|
||||||
static GLBackend* INSTANCE{ nullptr };
|
static GLBackend* INSTANCE{ nullptr };
|
||||||
|
|
||||||
BackendPointer GLBackend::createBackend() {
|
BackendPointer GLBackend::createBackend() {
|
||||||
|
@ -34,7 +32,7 @@ BackendPointer GLBackend::createBackend() {
|
||||||
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
|
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
|
||||||
auto version = QOpenGLContextWrapper::currentContextVersion();
|
auto version = QOpenGLContextWrapper::currentContextVersion();
|
||||||
std::shared_ptr<GLBackend> result;
|
std::shared_ptr<GLBackend> result;
|
||||||
if (!disableOpenGL45 && version >= 0x0405) {
|
if (!::gl::disableGl45() && version >= 0x0405) {
|
||||||
qCDebug(gpugllogging) << "Using OpenGL 4.5 backend";
|
qCDebug(gpugllogging) << "Using OpenGL 4.5 backend";
|
||||||
result = std::make_shared<gpu::gl45::GL45Backend>();
|
result = std::make_shared<gpu::gl45::GL45Backend>();
|
||||||
} else {
|
} else {
|
||||||
|
@ -57,7 +55,3 @@ GLBackend& getBackend() {
|
||||||
}
|
}
|
||||||
return *INSTANCE;
|
return *INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
|
||||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,11 +19,7 @@
|
||||||
#define GPU_CORE_41 410
|
#define GPU_CORE_41 410
|
||||||
#define GPU_CORE_43 430
|
#define GPU_CORE_43 430
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
#define GPU_INPUT_PROFILE GPU_CORE_41
|
#define GPU_INPUT_PROFILE GPU_CORE_41
|
||||||
#else
|
|
||||||
#define GPU_INPUT_PROFILE GPU_CORE_43
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace gpu { namespace gl41 {
|
namespace gpu { namespace gl41 {
|
||||||
|
|
||||||
|
@ -35,7 +31,6 @@ class GL41Backend : public GLBackend {
|
||||||
friend class Context;
|
friend class Context;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const GLint TRANSFORM_OBJECT_SLOT { 31 };
|
|
||||||
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
|
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
|
||||||
static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 };
|
static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 };
|
||||||
static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 };
|
static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 };
|
||||||
|
@ -172,9 +167,8 @@ protected:
|
||||||
void do_blit(const Batch& batch, size_t paramOffset) override;
|
void do_blit(const Batch& batch, size_t paramOffset) override;
|
||||||
|
|
||||||
std::string getBackendShaderHeader() const override;
|
std::string getBackendShaderHeader() const override;
|
||||||
void makeProgramBindings(ShaderObject& shaderObject) override;
|
|
||||||
int makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
|
||||||
|
|
||||||
|
void postLinkProgram(ShaderObject& programObject, const Shader& program) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -22,90 +22,54 @@ std::string GL41Backend::getBackendShaderHeader() const {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GL41Backend::makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& program) const {
|
||||||
GLint ssboCount = 0;
|
Parent::postLinkProgram(programObject, program);
|
||||||
const auto& glprogram = shaderProgram.glprogram;
|
const auto& glprogram = programObject.glprogram;
|
||||||
for (const auto& uniform : shaderProgram.uniforms) {
|
// For the UBOs, use glUniformBlockBinding to fixup the locations based on the reflection
|
||||||
const auto& name = uniform.name;
|
{
|
||||||
const auto& type = uniform.type;
|
const auto expectedUbos = program.getUniformBuffers().getLocationsByName();
|
||||||
const auto& location = uniform.location;
|
auto ubos = ::gl::UniformBlock::load(glprogram);
|
||||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
for (const auto& ubo : ubos) {
|
||||||
|
const auto& name = ubo.name;
|
||||||
// Try to make sense of the gltype
|
if (0 == expectedUbos.count(name)) {
|
||||||
auto elementResource = getFormatFromGLUniform(type);
|
continue;
|
||||||
|
|
||||||
// The uniform as a standard var type
|
|
||||||
if (location != INVALID_UNIFORM_LOCATION) {
|
|
||||||
|
|
||||||
if (elementResource._resource == Resource::BUFFER) {
|
|
||||||
if (elementResource._element.getSemantic() == gpu::RESOURCE_BUFFER) {
|
|
||||||
// Let's make sure the name doesn't contains an array element
|
|
||||||
std::string sname(name);
|
|
||||||
auto foundBracket = sname.find_first_of('[');
|
|
||||||
if (foundBracket != std::string::npos) {
|
|
||||||
// std::string arrayname = sname.substr(0, foundBracket);
|
|
||||||
|
|
||||||
if (sname[foundBracket + 1] == '0') {
|
|
||||||
sname = sname.substr(0, foundBracket);
|
|
||||||
} else {
|
|
||||||
// skip this uniform since it's not the first element of an array
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For texture/Sampler, the location is the actual binding value
|
|
||||||
GLint binding = -1;
|
|
||||||
glGetUniformiv(glprogram, location, &binding);
|
|
||||||
|
|
||||||
if (binding == GL41Backend::TRANSFORM_OBJECT_SLOT) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto requestedBinding = slotBindings.find(std::string(sname));
|
|
||||||
if (requestedBinding != slotBindings.end()) {
|
|
||||||
GLint requestedLoc = (*requestedBinding)._location + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT;
|
|
||||||
if (binding != requestedLoc) {
|
|
||||||
binding = requestedLoc;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding += GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT;
|
|
||||||
}
|
|
||||||
glProgramUniform1i(glprogram, location, binding);
|
|
||||||
|
|
||||||
ssboCount++;
|
|
||||||
resourceBuffers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const auto& targetLocation = expectedUbos.at(name);
|
||||||
|
glUniformBlockBinding(glprogram, ubo.index, targetLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssboCount;
|
// For the Textures, use glUniform1i to fixup the active texture slots based on the reflection
|
||||||
|
{
|
||||||
|
const auto expectedTextures = program.getTextures().getLocationsByName();
|
||||||
|
for (const auto& expectedTexture : expectedTextures) {
|
||||||
|
auto location = glGetUniformLocation(glprogram, expectedTexture.first.c_str());
|
||||||
|
if (location < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
glProgramUniform1i(glprogram, location, expectedTexture.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
for (const auto& resourceBuffer : resourceBufferUniforms) {
|
||||||
|
const auto& targetBinding = expectedResourceBuffers.at(resourceBuffer.name);
|
||||||
|
glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for the transformObjectBuffer, which is filtered out of the reflection data at shader load time
|
||||||
|
//
|
||||||
|
{
|
||||||
|
static const std::string TRANSFORM_OBJECT_BUFFER = "transformObjectBuffer";
|
||||||
|
const auto uniform = ::gl::Uniform::loadByName(glprogram, TRANSFORM_OBJECT_BUFFER);
|
||||||
|
if (-1 != uniform.binding) {
|
||||||
|
glProgramUniform1i(glprogram, uniform.binding, ::gpu::slot::texture::ObjectTransforms);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL41Backend::makeProgramBindings(ShaderObject& shaderObject) {
|
|
||||||
if (!shaderObject.glprogram) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
GLuint glprogram = shaderObject.glprogram;
|
|
||||||
GLint loc = -1;
|
|
||||||
|
|
||||||
GLBackend::makeProgramBindings(shaderObject);
|
|
||||||
|
|
||||||
// now assign the ubo binding, then DON't relink!
|
|
||||||
|
|
||||||
//Check for gpu specific uniform slotBindings
|
|
||||||
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glProgramUniform1i(glprogram, loc, GL41Backend::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = GL41Backend::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
|
|
||||||
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ void GL41Backend::initTransform() {
|
||||||
glGenTextures(1, &_transform._objectBufferTexture);
|
glGenTextures(1, &_transform._objectBufferTexture);
|
||||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||||
while (_transform._cameraUboSize < cameraSize) {
|
while (_transform._cameraUboSize < cameraSize) {
|
||||||
_transform._cameraUboSize += _uboAlignment;
|
_transform._cameraUboSize += UNIFORM_BUFFER_OFFSET_ALIGNMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ void GL41Backend::transferTransformState(const Batch& batch) const {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + GL41Backend::TRANSFORM_OBJECT_SLOT);
|
glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms);
|
||||||
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
||||||
if (!batch._objects.empty()) {
|
if (!batch._objects.empty()) {
|
||||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
|
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
|
||||||
|
|
|
@ -18,8 +18,26 @@ Q_LOGGING_CATEGORY(gpugl45logging, "hifi.gpu.gl45")
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
using namespace gpu::gl45;
|
using namespace gpu::gl45;
|
||||||
|
|
||||||
|
GLint GL45Backend::MAX_COMBINED_SHADER_STORAGE_BLOCKS{ 0 };
|
||||||
|
GLint GL45Backend::MAX_UNIFORM_LOCATIONS{ 0 };
|
||||||
|
|
||||||
|
static void staticInit() {
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [&] {
|
||||||
|
glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &GL45Backend::MAX_COMBINED_SHADER_STORAGE_BLOCKS);
|
||||||
|
glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &GL45Backend::MAX_UNIFORM_LOCATIONS);
|
||||||
|
});
|
||||||
|
}
|
||||||
const std::string GL45Backend::GL45_VERSION { "GL45" };
|
const std::string GL45Backend::GL45_VERSION { "GL45" };
|
||||||
|
|
||||||
|
GL45Backend::GL45Backend(bool syncCache) : Parent(syncCache) {
|
||||||
|
staticInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
GL45Backend::GL45Backend() : Parent() {
|
||||||
|
staticInit();
|
||||||
|
}
|
||||||
|
|
||||||
void GL45Backend::recycle() const {
|
void GL45Backend::recycle() const {
|
||||||
Parent::recycle();
|
Parent::recycle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,18 +33,14 @@ class GL45Backend : public GLBackend {
|
||||||
friend class Context;
|
friend class Context;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static GLint MAX_COMBINED_SHADER_STORAGE_BLOCKS;
|
||||||
|
static GLint MAX_UNIFORM_LOCATIONS;
|
||||||
#if GPU_BINDLESS_TEXTURES
|
#if GPU_BINDLESS_TEXTURES
|
||||||
virtual bool supportsBindless() const override { return true; }
|
virtual bool supportsBindless() const override { return true; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
explicit GL45Backend(bool syncCache);
|
||||||
static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot
|
GL45Backend();
|
||||||
#else
|
|
||||||
static const GLint TRANSFORM_OBJECT_SLOT { 31 }; // TBO binding slot
|
|
||||||
#endif
|
|
||||||
|
|
||||||
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
|
|
||||||
GL45Backend() : Parent() {}
|
|
||||||
virtual ~GL45Backend() {
|
virtual ~GL45Backend() {
|
||||||
// call resetStages here rather than in ~GLBackend dtor because it will call releaseResourceBuffer
|
// call resetStages here rather than in ~GLBackend dtor because it will call releaseResourceBuffer
|
||||||
// which is pure virtual from GLBackend's dtor.
|
// which is pure virtual from GLBackend's dtor.
|
||||||
|
@ -273,8 +269,6 @@ protected:
|
||||||
|
|
||||||
// Shader Stage
|
// Shader Stage
|
||||||
std::string getBackendShaderHeader() const override;
|
std::string getBackendShaderHeader() const override;
|
||||||
void makeProgramBindings(ShaderObject& shaderObject) override;
|
|
||||||
int makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
|
||||||
|
|
||||||
// Texture Management Stage
|
// Texture Management Stage
|
||||||
void initTextureManagementStage() override;
|
void initTextureManagementStage() override;
|
||||||
|
|
|
@ -26,152 +26,3 @@ std::string GL45Backend::getBackendShaderHeader() const {
|
||||||
);
|
);
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GL45Backend::makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
|
||||||
const auto& glprogram = shaderProgram.glprogram;
|
|
||||||
GLint buffersCount = 0;
|
|
||||||
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &buffersCount);
|
|
||||||
|
|
||||||
// fast exit
|
|
||||||
if (buffersCount == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint maxNumResourceBufferSlots = 0;
|
|
||||||
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxNumResourceBufferSlots);
|
|
||||||
std::vector<GLint> resourceBufferSlotMap(maxNumResourceBufferSlots, -1);
|
|
||||||
|
|
||||||
struct ResourceBlockInfo {
|
|
||||||
using Vector = std::vector<ResourceBlockInfo>;
|
|
||||||
const GLuint index{ 0 };
|
|
||||||
const std::string name;
|
|
||||||
GLint binding{ -1 };
|
|
||||||
GLint size{ 0 };
|
|
||||||
|
|
||||||
static std::string getName(GLuint glprogram, GLuint i) {
|
|
||||||
static const GLint NAME_LENGTH = 256;
|
|
||||||
GLint length = 0;
|
|
||||||
GLchar nameBuffer[NAME_LENGTH];
|
|
||||||
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, i, NAME_LENGTH, &length, nameBuffer);
|
|
||||||
return std::string(nameBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) {
|
|
||||||
GLenum props[2] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE};
|
|
||||||
glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, i, 2, props, 2, nullptr, &binding);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ResourceBlockInfo::Vector resourceBlocks;
|
|
||||||
resourceBlocks.reserve(buffersCount);
|
|
||||||
for (int i = 0; i < buffersCount; i++) {
|
|
||||||
resourceBlocks.push_back(ResourceBlockInfo(glprogram, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : resourceBlocks) {
|
|
||||||
auto requestedBinding = slotBindings.find(info.name);
|
|
||||||
if (requestedBinding != slotBindings.end()) {
|
|
||||||
info.binding = (*requestedBinding)._location;
|
|
||||||
glShaderStorageBlockBinding(glprogram, info.index, info.binding);
|
|
||||||
resourceBufferSlotMap[info.binding] = info.index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : resourceBlocks) {
|
|
||||||
if (slotBindings.count(info.name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the binding is -1, or the binding maps to an already used binding
|
|
||||||
if (info.binding == -1 || !isUnusedSlot(resourceBufferSlotMap[info.binding])) {
|
|
||||||
// If no binding was assigned then just do it finding a free slot
|
|
||||||
auto slotIt = std::find_if(resourceBufferSlotMap.begin(), resourceBufferSlotMap.end(), GLBackend::isUnusedSlot);
|
|
||||||
if (slotIt != resourceBufferSlotMap.end()) {
|
|
||||||
info.binding = slotIt - resourceBufferSlotMap.begin();
|
|
||||||
glShaderStorageBlockBinding(glprogram, info.index, info.binding);
|
|
||||||
} else {
|
|
||||||
// This should never happen, an active ssbo cannot find an available slot among the max available?!
|
|
||||||
info.binding = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceBufferSlotMap[info.binding] = info.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& info : resourceBlocks) {
|
|
||||||
static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER);
|
|
||||||
resourceBuffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size));
|
|
||||||
}
|
|
||||||
return buffersCount;
|
|
||||||
/*
|
|
||||||
GLint ssboCount = 0;
|
|
||||||
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssboCount);
|
|
||||||
if (ssboCount > 0) {
|
|
||||||
GLint maxNameLength = 0;
|
|
||||||
glGetProgramInterfaceiv(glprogram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxNameLength);
|
|
||||||
std::vector<GLchar> nameBytes(maxNameLength);
|
|
||||||
|
|
||||||
for (GLint b = 0; b < ssboCount; b++) {
|
|
||||||
GLint length;
|
|
||||||
glGetProgramResourceName(glprogram, GL_SHADER_STORAGE_BLOCK, b, maxNameLength, &length, nameBytes.data());
|
|
||||||
std::string bufferName(nameBytes.data());
|
|
||||||
|
|
||||||
GLenum props = GL_BUFFER_BINDING;
|
|
||||||
GLint binding = -1;
|
|
||||||
glGetProgramResourceiv(glprogram, GL_SHADER_STORAGE_BLOCK, b, 1, &props, 1, nullptr, &binding);
|
|
||||||
|
|
||||||
auto requestedBinding = slotBindings.find(std::string(bufferName));
|
|
||||||
if (requestedBinding != slotBindings.end()) {
|
|
||||||
if (binding != (*requestedBinding)._location) {
|
|
||||||
binding = (*requestedBinding)._location;
|
|
||||||
glShaderStorageBlockBinding(glprogram, b, binding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const Element element(SCALAR, gpu::UINT32, gpu::RESOURCE_BUFFER);
|
|
||||||
resourceBuffers.insert(Shader::Slot(bufferName, binding, element, -1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ssboCount;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) {
|
|
||||||
if (!shaderObject.glprogram) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
GLuint glprogram = shaderObject.glprogram;
|
|
||||||
GLint loc = -1;
|
|
||||||
|
|
||||||
GLBackend::makeProgramBindings(shaderObject);
|
|
||||||
|
|
||||||
// now assign the ubo binding, then DON't relink!
|
|
||||||
|
|
||||||
//Check for gpu specific uniform slotBindings
|
|
||||||
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
|
||||||
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glShaderStorageBlockBinding(glprogram, loc, GL45Backend::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = GL45Backend::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glProgramUniform1i(glprogram, loc, GL45Backend::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = GL45Backend::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
|
|
||||||
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glUniformBlockBinding(glprogram, loc, RESOURCE_TABLE_TEXTURE_SLOT_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ void GL45Backend::initTransform() {
|
||||||
#endif
|
#endif
|
||||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||||
while (_transform._cameraUboSize < cameraSize) {
|
while (_transform._cameraUboSize < cameraSize) {
|
||||||
_transform._cameraUboSize += _uboAlignment;
|
_transform._cameraUboSize += UNIFORM_BUFFER_OFFSET_ALIGNMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,9 @@ void GL45Backend::transferTransformState(const Batch& batch) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GL45Backend::TRANSFORM_OBJECT_SLOT, _transform._objectBuffer);
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot::storage::ObjectTransforms, _transform._objectBuffer);
|
||||||
#else
|
#else
|
||||||
glActiveTexture(GL_TEXTURE0 + GL45Backend::TRANSFORM_OBJECT_SLOT);
|
glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms);
|
||||||
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
||||||
glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer);
|
glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -50,7 +50,3 @@ GLBackend& getBackend() {
|
||||||
}
|
}
|
||||||
return *INSTANCE;
|
return *INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
|
||||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
|
||||||
}
|
|
||||||
|
|
|
@ -163,9 +163,6 @@ protected:
|
||||||
void do_blit(const Batch& batch, size_t paramOffset) override;
|
void do_blit(const Batch& batch, size_t paramOffset) override;
|
||||||
|
|
||||||
std::string getBackendShaderHeader() const override;
|
std::string getBackendShaderHeader() const override;
|
||||||
void makeProgramBindings(ShaderObject& shaderObject) override;
|
|
||||||
int makeResourceBufferSlots(const ShaderObject& shaderObject, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
@ -173,4 +170,4 @@ protected:
|
||||||
Q_DECLARE_LOGGING_CATEGORY(gpugleslogging)
|
Q_DECLARE_LOGGING_CATEGORY(gpugleslogging)
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,93 +24,3 @@ std::string GLESBackend::getBackendShaderHeader() const {
|
||||||
)SHADER");
|
)SHADER");
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLESBackend::makeResourceBufferSlots(const ShaderObject& shaderObject, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
|
||||||
GLint ssboCount = 0;
|
|
||||||
GLint uniformsCount = 0;
|
|
||||||
const auto& glprogram = shaderObject.glprogram;
|
|
||||||
|
|
||||||
for (const auto& uniform : shaderObject.uniforms) {
|
|
||||||
const auto& type = uniform.type;
|
|
||||||
const auto& location = uniform.location;
|
|
||||||
const auto& name = uniform.name;
|
|
||||||
const GLint INVALID_UNIFORM_LOCATION = -1;
|
|
||||||
|
|
||||||
// Try to make sense of the gltype
|
|
||||||
auto elementResource = getFormatFromGLUniform(type);
|
|
||||||
|
|
||||||
// The uniform as a standard var type
|
|
||||||
if (location != INVALID_UNIFORM_LOCATION) {
|
|
||||||
|
|
||||||
if (elementResource._resource == Resource::BUFFER) {
|
|
||||||
if (elementResource._element.getSemantic() == gpu::RESOURCE_BUFFER) {
|
|
||||||
// Let's make sure the name doesn't contains an array element
|
|
||||||
std::string sname(name);
|
|
||||||
auto foundBracket = sname.find_first_of('[');
|
|
||||||
if (foundBracket != std::string::npos) {
|
|
||||||
// std::string arrayname = sname.substr(0, foundBracket);
|
|
||||||
|
|
||||||
if (sname[foundBracket + 1] == '0') {
|
|
||||||
sname = sname.substr(0, foundBracket);
|
|
||||||
} else {
|
|
||||||
// skip this uniform since it's not the first element of an array
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For texture/Sampler, the location is the actual binding value
|
|
||||||
GLint binding = -1;
|
|
||||||
glGetUniformiv(glprogram, location, &binding);
|
|
||||||
|
|
||||||
if (binding == GLESBackend::TRANSFORM_OBJECT_SLOT) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto requestedBinding = slotBindings.find(std::string(sname));
|
|
||||||
if (requestedBinding != slotBindings.end()) {
|
|
||||||
GLint requestedLoc = (*requestedBinding)._location + GLESBackend::RESOURCE_BUFFER_SLOT0_TEX_UNIT;
|
|
||||||
if (binding != requestedLoc) {
|
|
||||||
binding = requestedLoc;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
binding += GLESBackend::RESOURCE_BUFFER_SLOT0_TEX_UNIT;
|
|
||||||
}
|
|
||||||
glProgramUniform1i(glprogram, location, binding);
|
|
||||||
|
|
||||||
ssboCount++;
|
|
||||||
resourceBuffers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ssboCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLESBackend::makeProgramBindings(ShaderObject& shaderObject) {
|
|
||||||
if (!shaderObject.glprogram) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
GLuint glprogram = shaderObject.glprogram;
|
|
||||||
GLint loc = -1;
|
|
||||||
|
|
||||||
GLBackend::makeProgramBindings(shaderObject);
|
|
||||||
|
|
||||||
// now assign the ubo binding, then DON't relink!
|
|
||||||
|
|
||||||
//Check for gpu specific uniform slotBindings
|
|
||||||
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glProgramUniform1i(glprogram, loc, GLESBackend::TRANSFORM_OBJECT_SLOT);
|
|
||||||
shaderObject.transformObjectSlot = GLESBackend::TRANSFORM_OBJECT_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
|
|
||||||
if (loc >= 0) {
|
|
||||||
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
|
|
||||||
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,10 @@ void GLESBackend::initTransform() {
|
||||||
glGenBuffers(1, &_transform._drawCallInfoBuffer);
|
glGenBuffers(1, &_transform._drawCallInfoBuffer);
|
||||||
glGenTextures(1, &_transform._objectBufferTexture);
|
glGenTextures(1, &_transform._objectBufferTexture);
|
||||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||||
while (_transform._cameraUboSize < cameraSize) {
|
if (UNIFORM_BUFFER_OFFSET_ALIGNMENT > 0) {
|
||||||
_transform._cameraUboSize += _uboAlignment;
|
while (_transform._cameraUboSize < cameraSize) {
|
||||||
|
_transform._cameraUboSize += UNIFORM_BUFFER_OFFSET_ALIGNMENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
set(TARGET_NAME gpu)
|
set(TARGET_NAME gpu)
|
||||||
autoscribe_shader_lib(gpu)
|
|
||||||
setup_hifi_library()
|
setup_hifi_library()
|
||||||
link_hifi_libraries(shared ktx)
|
link_hifi_libraries(shared ktx shaders)
|
||||||
|
|
||||||
target_nsight()
|
target_nsight()
|
||||||
|
|
|
@ -24,15 +24,12 @@
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
#include "Transform.h"
|
#include "Transform.h"
|
||||||
|
#include "ShaderConstants.h"
|
||||||
|
|
||||||
class QDebug;
|
class QDebug;
|
||||||
#define BATCH_PREALLOCATE_MIN 128
|
#define BATCH_PREALLOCATE_MIN 128
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
enum ReservedSlot {
|
|
||||||
TRANSFORM_CAMERA_SLOT = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
// The named batch data provides a mechanism for accumulating data into buffers over the course
|
// The named batch data provides a mechanism for accumulating data into buffers over the course
|
||||||
// of many independent calls. For instance, two objects in the scene might both want to render
|
// of many independent calls. For instance, two objects in the scene might both want to render
|
||||||
// a simple box, but are otherwise unaware of each other. The common code that they call to render
|
// a simple box, but are otherwise unaware of each other. The common code that they call to render
|
||||||
|
@ -170,10 +167,10 @@ public:
|
||||||
void resetViewTransform() { setViewTransform(Transform(), false); }
|
void resetViewTransform() { setViewTransform(Transform(), false); }
|
||||||
void setViewTransform(const Transform& view, bool camera = true);
|
void setViewTransform(const Transform& view, bool camera = true);
|
||||||
void setProjectionTransform(const Mat4& proj);
|
void setProjectionTransform(const Mat4& proj);
|
||||||
void setProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
void setProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
||||||
// Very simple 1 level stack management of jitter.
|
// Very simple 1 level stack management of jitter.
|
||||||
void pushProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
void pushProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
||||||
void popProjectionJitter();
|
void popProjectionJitter();
|
||||||
// Viewport is xy = low left corner in framebuffer, zw = width height of the viewport, expressed in pixels
|
// Viewport is xy = low left corner in framebuffer, zw = width height of the viewport, expressed in pixels
|
||||||
void setViewportTransform(const Vec4i& viewport);
|
void setViewportTransform(const Vec4i& viewport);
|
||||||
void setDepthRangeTransform(float nearDepth, float farDepth);
|
void setDepthRangeTransform(float nearDepth, float farDepth);
|
||||||
|
@ -299,9 +296,9 @@ public:
|
||||||
|
|
||||||
COMMAND_setModelTransform,
|
COMMAND_setModelTransform,
|
||||||
COMMAND_setViewTransform,
|
COMMAND_setViewTransform,
|
||||||
COMMAND_setProjectionTransform,
|
COMMAND_setProjectionTransform,
|
||||||
COMMAND_setProjectionJitter,
|
COMMAND_setProjectionJitter,
|
||||||
COMMAND_setViewportTransform,
|
COMMAND_setViewportTransform,
|
||||||
COMMAND_setDepthRangeTransform,
|
COMMAND_setDepthRangeTransform,
|
||||||
|
|
||||||
COMMAND_setPipeline,
|
COMMAND_setPipeline,
|
||||||
|
@ -504,7 +501,7 @@ public:
|
||||||
|
|
||||||
NamedBatchDataMap _namedData;
|
NamedBatchDataMap _namedData;
|
||||||
|
|
||||||
glm::vec2 _projectionJitter{ 0.0f, 0.0f };
|
glm::vec2 _projectionJitter{ 0.0f, 0.0f };
|
||||||
bool _enableStereo{ true };
|
bool _enableStereo{ true };
|
||||||
bool _enableSkybox { false };
|
bool _enableSkybox { false };
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ void ContextStats::evalDelta(const ContextStats& begin, const ContextStats& end)
|
||||||
|
|
||||||
|
|
||||||
Context::CreateBackend Context::_createBackendCallback = nullptr;
|
Context::CreateBackend Context::_createBackendCallback = nullptr;
|
||||||
Context::MakeProgram Context::_makeProgramCallback = nullptr;
|
|
||||||
std::once_flag Context::_initialized;
|
std::once_flag Context::_initialized;
|
||||||
|
|
||||||
Context::Context() {
|
Context::Context() {
|
||||||
|
@ -139,20 +138,6 @@ void Context::executeFrame(const FramePointer& frame) const {
|
||||||
_frameStats.evalDelta(beginStats, endStats);
|
_frameStats.evalDelta(beginStats, endStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler) {
|
|
||||||
PROFILE_RANGE_EX(app, "makeProgram", 0xff4040c0, shader.getID());
|
|
||||||
// If we're running in another DLL context, we need to fetch the program callback out of the application
|
|
||||||
// FIXME find a way to do this without reliance on Qt app properties
|
|
||||||
if (!_makeProgramCallback) {
|
|
||||||
void* rawCallback = qApp->property(hifi::properties::gl::MAKE_PROGRAM_CALLBACK).value<void*>();
|
|
||||||
_makeProgramCallback = reinterpret_cast<Context::MakeProgram>(rawCallback);
|
|
||||||
}
|
|
||||||
if (shader.isProgram() && _makeProgramCallback) {
|
|
||||||
return _makeProgramCallback(shader, bindings, handler);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::enableStereo(bool enable) {
|
void Context::enableStereo(bool enable) {
|
||||||
_stereo._enable = enable;
|
_stereo._enable = enable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ public:
|
||||||
static ContextMetricSize textureResourceIdealGPUMemSize;
|
static ContextMetricSize textureResourceIdealGPUMemSize;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool isStereo() {
|
virtual bool isStereo() const {
|
||||||
return _stereo.isStereo();
|
return _stereo.isStereo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,14 +140,12 @@ class Context {
|
||||||
public:
|
public:
|
||||||
using Size = Resource::Size;
|
using Size = Resource::Size;
|
||||||
typedef BackendPointer (*CreateBackend)();
|
typedef BackendPointer (*CreateBackend)();
|
||||||
typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
|
|
||||||
|
|
||||||
// This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
|
// This one call must happen before any context is created or used (Shader::MakeProgram) in order to setup the Backend and any singleton data needed
|
||||||
template <class T>
|
template <class T>
|
||||||
static void init() {
|
static void init() {
|
||||||
std::call_once(_initialized, [] {
|
std::call_once(_initialized, [] {
|
||||||
_createBackendCallback = T::createBackend;
|
_createBackendCallback = T::createBackend;
|
||||||
_makeProgramCallback = T::makeProgram;
|
|
||||||
T::init();
|
T::init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -261,14 +259,7 @@ protected:
|
||||||
// Sampled at the end of every frame, the stats of all the counters
|
// Sampled at the end of every frame, the stats of all the counters
|
||||||
mutable ContextStats _frameStats;
|
mutable ContextStats _frameStats;
|
||||||
|
|
||||||
// This function can only be called by "static Shader::makeProgram()"
|
|
||||||
// makeProgramShader(...) make a program shader ready to be used in a Batch.
|
|
||||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
|
||||||
// If the shader passed is not a program, nothing happens.
|
|
||||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings, const Shader::CompilationHandler& handler);
|
|
||||||
|
|
||||||
static CreateBackend _createBackendCallback;
|
static CreateBackend _createBackendCallback;
|
||||||
static MakeProgram _makeProgramCallback;
|
|
||||||
static std::once_flag _initialized;
|
static std::once_flag _initialized;
|
||||||
|
|
||||||
friend class Shader;
|
friend class Shader;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawColor.frag
|
||||||
|
//
|
||||||
// Draw with color uniform
|
// Draw with color uniform
|
||||||
//
|
//
|
||||||
// Created by Olivier Prat on 25/10/2017
|
// Created by Olivier Prat on 25/10/2017
|
||||||
|
@ -10,9 +12,12 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
uniform vec4 color;
|
|
||||||
|
|
||||||
out vec4 outFragColor;
|
<@include gpu/ShaderConstants.h@>
|
||||||
|
|
||||||
|
layout(location=GPU_UNIFORM_COLOR) uniform vec4 color;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = color;
|
outFragColor = color;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawColoredTexture.frag
|
||||||
|
//
|
||||||
// Draw texture 0 fetched at texcoord.xy, Blend with color uniform
|
// Draw texture 0 fetched at texcoord.xy, Blend with color uniform
|
||||||
//
|
//
|
||||||
// Created by Sam Gateau on 7/12/2015
|
// Created by Sam Gateau on 7/12/2015
|
||||||
|
@ -11,12 +13,13 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
<@include gpu/ShaderConstants.h@>
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
layout(binding=0) uniform sampler2D colorMap;
|
||||||
uniform vec4 color;
|
layout(location=GPU_UNIFORM_COLOR) uniform vec4 color;
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = texture(colorMap, varTexCoord0) * color;
|
outFragColor = texture(colorMap, varTexCoord0) * color;
|
||||||
|
|
5
libraries/gpu/src/gpu/DrawNada.slf
Normal file
5
libraries/gpu/src/gpu/DrawNada.slf
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
|
||||||
|
void main(void) { }
|
|
@ -1,6 +1,9 @@
|
||||||
<@include gpu/Config.slh@>
|
<@include gpu/Config.slh@>
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// DrawTexcoordRectTransformUnitQuad.vert
|
||||||
|
|
||||||
//
|
//
|
||||||
// Draw and transform the unit quad [-1,-1 -> 1,1]
|
// Draw and transform the unit quad [-1,-1 -> 1,1]
|
||||||
// Transform the normalized texcoords [0, 1] to be in the range [texcoordRect.xy, texcoordRect.xy + texcoordRect.zw]
|
// Transform the normalized texcoords [0, 1] to be in the range [texcoordRect.xy, texcoordRect.xy + texcoordRect.zw]
|
||||||
|
@ -14,12 +17,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
<@include gpu/Transform.slh@>
|
<@include gpu/Transform.slh@>
|
||||||
|
<@include gpu/ShaderConstants.h@>
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
uniform vec4 texcoordRect;
|
layout(location=GPU_UNIFORM_TEXCOORD_RECT) uniform vec4 texcoordRect;
|
||||||
|
|
||||||
out vec2 varTexCoord0;
|
layout(location=0) out vec2 varTexCoord0;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawTexture.frag
|
||||||
|
//
|
||||||
// Draw texture 0 fetched at texcoord.xy
|
// Draw texture 0 fetched at texcoord.xy
|
||||||
//
|
//
|
||||||
// Created by Sam Gateau on 6/22/2015
|
// Created by Sam Gateau on 6/22/2015
|
||||||
|
@ -12,10 +14,10 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
layout(binding=0) uniform sampler2D colorMap;
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = texture(colorMap, varTexCoord0);
|
outFragColor = texture(colorMap, varTexCoord0);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawTextureMirroredX.frag
|
||||||
|
//
|
||||||
// Draw texture 0 fetched at (1.0 - texcoord.x, texcoord.y)
|
// Draw texture 0 fetched at (1.0 - texcoord.x, texcoord.y)
|
||||||
//
|
//
|
||||||
// Created by Sam Gondelman on 10/24/2017
|
// Created by Sam Gondelman on 10/24/2017
|
||||||
|
@ -12,10 +14,10 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
layout(binding=0) uniform sampler2D colorMap;
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y));
|
outFragColor = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y));
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawTextureOpaque.frag
|
||||||
|
//
|
||||||
// Draw texture 0 fetched at texcoord.xy
|
// Draw texture 0 fetched at texcoord.xy
|
||||||
// Alpha is 1
|
// Alpha is 1
|
||||||
//
|
//
|
||||||
|
@ -12,11 +14,13 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
<@include gpu/ShaderConstants.h@>
|
||||||
|
|
||||||
uniform sampler2D colorMap;
|
layout(binding=0) uniform sampler2D colorMap;
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
out vec4 outFragColor;
|
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = vec4(texture(colorMap, varTexCoord0).xyz, 1.0);
|
outFragColor = vec4(texture(colorMap, varTexCoord0).xyz, 1.0);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawTransformUnitQuad.vert
|
||||||
|
//
|
||||||
// Draw and transform the unit quad [-1,-1 -> 1,1]
|
// Draw and transform the unit quad [-1,-1 -> 1,1]
|
||||||
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
||||||
//
|
//
|
||||||
|
@ -16,7 +18,7 @@
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
out vec2 varTexCoord0;
|
layout(location=0) out vec2 varTexCoord0;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawTransformVertexPosition.vert
|
||||||
|
//
|
||||||
// Draw and transform the fed vertex position with the standard MVP stack
|
// Draw and transform the fed vertex position with the standard MVP stack
|
||||||
// Output the clip position
|
// Output the clip position
|
||||||
//
|
//
|
||||||
|
@ -16,9 +18,9 @@
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
layout(location = 0) in vec4 inPosition;
|
layout(location=0) in vec4 inPosition;
|
||||||
|
|
||||||
out vec3 varWorldPos;
|
layout(location=0) out vec3 varWorldPos;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// standard transform
|
// standard transform
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawUnitQuadTexcoord.vert
|
||||||
|
//
|
||||||
// Draw the unit quad [-1,-1 -> 1,1] amd pass along the unit texcoords [0, 0 -> 1, 1]. Not transform used.
|
// Draw the unit quad [-1,-1 -> 1,1] amd pass along the unit texcoords [0, 0 -> 1, 1]. Not transform used.
|
||||||
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
||||||
//
|
//
|
||||||
|
@ -11,7 +13,7 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
out vec2 varTexCoord0;
|
layout(location=0) out vec2 varTexCoord0;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
const float depth = 1.0;
|
const float depth = 1.0;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawVertexPosition.vert
|
||||||
|
//
|
||||||
// Draw the fed vertex position, pass straight as clip pos
|
// Draw the fed vertex position, pass straight as clip pos
|
||||||
// Output the clip position
|
// Output the clip position
|
||||||
//
|
//
|
||||||
|
@ -12,7 +14,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
layout(location = 0) in vec4 inPosition;
|
layout(location=0) in vec4 inPosition;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
gl_Position = inPosition;
|
gl_Position = inPosition;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
|
// DrawViewportQuatTransformTexcoord.vert
|
||||||
|
//
|
||||||
// Draw the unit quad [-1,-1 -> 1,1] filling in
|
// Draw the unit quad [-1,-1 -> 1,1] filling in
|
||||||
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
||||||
//
|
//
|
||||||
|
@ -16,7 +18,7 @@
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
out vec2 varTexCoord0;
|
layout(location=0) out vec2 varTexCoord0;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<$VERSION_HEADER$>
|
<$VERSION_HEADER$>
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
// Draw white
|
// DrawWhite.frag
|
||||||
//
|
//
|
||||||
// Created by Sam Gateau on 5/30/2017
|
// Created by Sam Gateau on 5/30/2017
|
||||||
// Copyright 2017 High Fidelity, Inc.
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = vec4(1.0);
|
outFragColor = vec4(1.0);
|
||||||
|
|
|
@ -10,15 +10,18 @@
|
||||||
!>
|
!>
|
||||||
<@if not GPU_INPUTS_SLH@>
|
<@if not GPU_INPUTS_SLH@>
|
||||||
<@def GPU_INPUTS_SLH@>
|
<@def GPU_INPUTS_SLH@>
|
||||||
layout(location = 0) in vec4 inPosition;
|
|
||||||
layout(location = 1) in vec4 inNormal;
|
<@include gpu/ShaderConstants.h@>
|
||||||
layout(location = 2) in vec4 inColor;
|
|
||||||
layout(location = 3) in vec4 inTexCoord0;
|
layout(location=GPU_ATTR_POSITION) in vec4 inPosition;
|
||||||
layout(location = 4) in vec4 inTangent;
|
layout(location=GPU_ATTR_NORMAL) in vec4 inNormal;
|
||||||
layout(location = 5) in ivec4 inSkinClusterIndex;
|
layout(location=GPU_ATTR_COLOR) in vec4 inColor;
|
||||||
layout(location = 6) in vec4 inSkinClusterWeight;
|
layout(location=GPU_ATTR_TEXCOORD0) in vec4 inTexCoord0;
|
||||||
layout(location = 7) in vec4 inTexCoord1;
|
layout(location=GPU_ATTR_TANGENT) in vec4 inTangent;
|
||||||
layout(location = 8) in vec4 inTexCoord2;
|
layout(location=GPU_ATTR_SKIN_CLUSTER_INDEX) in ivec4 inSkinClusterIndex;
|
||||||
layout(location = 9) in vec4 inTexCoord3;
|
layout(location=GPU_ATTR_SKIN_CLUSTER_WEIGHT) in vec4 inSkinClusterWeight;
|
||||||
layout(location = 10) in vec4 inTexCoord4;
|
layout(location=GPU_ATTR_TEXCOORD1) in vec4 inTexCoord1;
|
||||||
|
layout(location=GPU_ATTR_TEXCOORD2) in vec4 inTexCoord2;
|
||||||
|
layout(location=GPU_ATTR_TEXCOORD3) in vec4 inTexCoord3;
|
||||||
|
layout(location=GPU_ATTR_TEXCOORD4) in vec4 inTexCoord4;
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
|
@ -12,6 +12,12 @@
|
||||||
#include "Shader.h"
|
#include "Shader.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <QtCore/QJsonDocument>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
|
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
|
|
||||||
|
@ -49,6 +55,14 @@ 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() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
|
Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) {
|
||||||
auto found = _domainShaderMaps[type].find(source);
|
auto found = _domainShaderMaps[type].find(source);
|
||||||
if (found != _domainShaderMaps[type].end()) {
|
if (found != _domainShaderMaps[type].end()) {
|
||||||
|
@ -58,21 +72,32 @@ Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& sourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto shader = Pointer(new Shader(type, source));
|
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>(shader));
|
_domainShaderMaps[type].emplace(source, std::weak_ptr<Shader>(shader));
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::Pointer Shader::createVertex(const Source& source) {
|
|
||||||
return createOrReuseDomainShader(VERTEX, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader::Pointer Shader::createPixel(const Source& source) {
|
|
||||||
return createOrReuseDomainShader(PIXEL, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader::Pointer Shader::createGeometry(const Source& source) {
|
|
||||||
return createOrReuseDomainShader(GEOMETRY, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
|
ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
|
||||||
PROFILE_RANGE(app, "createOrReuseProgramShader");
|
PROFILE_RANGE(app, "createOrReuseProgramShader");
|
||||||
|
@ -112,36 +137,32 @@ ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& verte
|
||||||
|
|
||||||
// Program is a new one, let's create it
|
// Program is a new one, let's create it
|
||||||
auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader));
|
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<Shader>(program));
|
_programMap.emplace(key, std::weak_ptr<Shader>(program));
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
|
|
||||||
return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
|
|
||||||
return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& uniformBuffers, const SlotSet& resourceBuffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) {
|
|
||||||
_uniforms = uniforms;
|
|
||||||
_uniformBuffers = uniformBuffers;
|
|
||||||
_resourceBuffers = resourceBuffers;
|
|
||||||
_textures = textures;
|
|
||||||
_samplers = samplers;
|
|
||||||
_inputs = inputs;
|
|
||||||
_outputs = outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings, const CompilationHandler& handler) {
|
|
||||||
if (shader.isProgram()) {
|
|
||||||
return Context::makeProgram(shader, bindings, handler);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::setCompilationLogs(const CompilationLogs& logs) const {
|
void Shader::setCompilationLogs(const CompilationLogs& logs) const {
|
||||||
_compilationLogs.clear();
|
_compilationLogs.clear();
|
||||||
for (const auto& log : logs) {
|
for (const auto& log : logs) {
|
||||||
|
@ -153,3 +174,124 @@ void Shader::incrementCompilationAttempt() const {
|
||||||
_numCompilationAttempts++;
|
_numCompilationAttempts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shader::Pointer Shader::createVertex(const Source& source) {
|
||||||
|
return createOrReuseDomainShader(VERTEX, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::Pointer Shader::createPixel(const Source& source) {
|
||||||
|
return createOrReuseDomainShader(FRAGMENT, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::Pointer Shader::createVertex(uint32_t id) {
|
||||||
|
return createVertex(getShaderSource(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::Pointer Shader::createPixel(uint32_t id) {
|
||||||
|
return createPixel(getShaderSource(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));
|
||||||
|
auto fragmentShader = createPixel(shader::getFragmentId(programId));
|
||||||
|
return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, fragmentShader);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) {
|
||||||
|
return createOrReuseProgramShader(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 };
|
||||||
|
}
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
class Shader {
|
class Shader {
|
||||||
|
@ -26,30 +28,71 @@ public:
|
||||||
// unique identifier of a shader
|
// unique identifier of a shader
|
||||||
using ID = uint32_t;
|
using ID = uint32_t;
|
||||||
|
|
||||||
typedef std::shared_ptr< Shader > Pointer;
|
enum Type
|
||||||
typedef std::vector< Pointer > Shaders;
|
{
|
||||||
|
VERTEX = 0,
|
||||||
|
PIXEL,
|
||||||
|
FRAGMENT = PIXEL,
|
||||||
|
GEOMETRY,
|
||||||
|
NUM_DOMAINS,
|
||||||
|
|
||||||
|
PROGRAM,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Shader> Pointer;
|
||||||
|
typedef std::vector<Pointer> 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<std::string, int32_t>;
|
||||||
|
using ReflectionMap = std::map<BindingType, LocationMap>;
|
||||||
|
|
||||||
class Source {
|
class Source {
|
||||||
public:
|
public:
|
||||||
enum Language {
|
enum Language
|
||||||
|
{
|
||||||
|
INVALID = -1,
|
||||||
GLSL = 0,
|
GLSL = 0,
|
||||||
|
SPIRV = 1,
|
||||||
|
MSL = 2,
|
||||||
|
HLSL = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
Source() {}
|
Source() {}
|
||||||
Source(const std::string& code, Language lang = GLSL) : _code(code), _lang(lang) {}
|
Source(const std::string& code, const ReflectionMap& reflection, Language lang = GLSL) :
|
||||||
Source(const Source& source) : _code(source._code), _lang(source._lang) {}
|
_code(code), _reflection(reflection), _lang(lang) {}
|
||||||
|
Source(const Source& source) : _code(source._code), _reflection(source._reflection), _lang(source._lang) {}
|
||||||
virtual ~Source() {}
|
virtual ~Source() {}
|
||||||
|
|
||||||
virtual const std::string& getCode() const { return _code; }
|
virtual const std::string& getCode() const { return _code; }
|
||||||
|
virtual const ReflectionMap& getReflection() const { return _reflection; }
|
||||||
|
|
||||||
class Less {
|
class Less {
|
||||||
public:
|
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); } }
|
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:
|
protected:
|
||||||
std::string _code;
|
std::string _code;
|
||||||
Language _lang = GLSL;
|
ReflectionMap _reflection;
|
||||||
|
Language _lang;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompilationLog {
|
struct CompilationLog {
|
||||||
|
@ -57,30 +100,40 @@ public:
|
||||||
bool compiled{ false };
|
bool compiled{ false };
|
||||||
|
|
||||||
CompilationLog() {}
|
CompilationLog() {}
|
||||||
CompilationLog(const CompilationLog& src) :
|
CompilationLog(const CompilationLog& src) : message(src.message), compiled(src.compiled) {}
|
||||||
message(src.message),
|
|
||||||
compiled(src.compiled) {}
|
|
||||||
};
|
};
|
||||||
using CompilationLogs = std::vector<CompilationLog>;
|
using CompilationLogs = std::vector<CompilationLog>;
|
||||||
|
|
||||||
static const int32 INVALID_LOCATION = -1;
|
static const int32 INVALID_LOCATION = -1;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Less {
|
||||||
|
public:
|
||||||
|
bool operator()(const T& x, const T& y) const { return x._name < y._name; }
|
||||||
|
};
|
||||||
|
|
||||||
class Slot {
|
class Slot {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string _name;
|
std::string _name;
|
||||||
int32 _location{INVALID_LOCATION};
|
int32 _location{ INVALID_LOCATION };
|
||||||
Element _element;
|
Element _element;
|
||||||
uint16 _resourceType{Resource::BUFFER};
|
uint16 _resourceType{ Resource::BUFFER };
|
||||||
uint32 _size { 0 };
|
uint32 _size{ 0 };
|
||||||
|
|
||||||
Slot(const Slot& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
Slot(const Slot& s) :
|
||||||
Slot(Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
_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) :
|
Slot(Slot&& s) :
|
||||||
_name(name), _location(location), _element(element), _resourceType(resourceType), _size(size) {}
|
_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(const std::string& name) : _name(name) {}
|
||||||
|
|
||||||
Slot& operator= (const Slot& s) {
|
Slot& operator=(const Slot& s) {
|
||||||
_name = s._name;
|
_name = s._name;
|
||||||
_location = s._location;
|
_location = s._location;
|
||||||
_element = s._element;
|
_element = s._element;
|
||||||
|
@ -90,54 +143,62 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Binding {
|
class SlotSet : protected std::set<Slot, Less<Slot>> {
|
||||||
public:
|
using Parent = std::set<Slot, Less<Slot>>;
|
||||||
std::string _name;
|
|
||||||
int32 _location;
|
|
||||||
Binding(const std::string& name, int32 loc = INVALID_LOCATION) : _name(name), _location(loc) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> class Less {
|
|
||||||
public:
|
public:
|
||||||
bool operator() (const T& x, const T& y) const { return x._name < y._name; }
|
void insert(const Parent::value_type& value) {
|
||||||
};
|
Parent::insert(value);
|
||||||
|
if (value._location != INVALID_LOCATION) {
|
||||||
class SlotSet : public std::set<Slot, Less<Slot>> {
|
_validSlots.insert(value._location);
|
||||||
public:
|
|
||||||
Slot findSlot(const std::string& name) const {
|
|
||||||
auto key = Slot(name);
|
|
||||||
auto found = static_cast<const std::set<Slot, Less<Slot>>*>(this)->find(key);
|
|
||||||
if (found != end()) {
|
|
||||||
return (*found);
|
|
||||||
}
|
}
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
int32 findLocation(const std::string& name) const {
|
|
||||||
return findSlot(name)._location;
|
using Parent::begin;
|
||||||
|
using Parent::empty;
|
||||||
|
using Parent::end;
|
||||||
|
using Parent::size;
|
||||||
|
|
||||||
|
using LocationMap = std::unordered_map<std::string, int32>;
|
||||||
|
using NameVector = std::vector<std::string>;
|
||||||
|
|
||||||
|
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:
|
protected:
|
||||||
|
std::unordered_set<int> _validSlots;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::set<Binding, Less<Binding>> BindingSet;
|
|
||||||
|
|
||||||
|
static Source getShaderSource(uint32_t id);
|
||||||
enum Type {
|
static Source getVertexShaderSource(uint32_t id) { return getShaderSource(id); }
|
||||||
VERTEX = 0,
|
static Source getFragmentShaderSource(uint32_t id) { return getShaderSource(id); }
|
||||||
PIXEL,
|
|
||||||
GEOMETRY,
|
|
||||||
NUM_DOMAINS,
|
|
||||||
|
|
||||||
PROGRAM,
|
|
||||||
};
|
|
||||||
|
|
||||||
static Pointer createVertex(const Source& source);
|
static Pointer createVertex(const Source& source);
|
||||||
static Pointer createPixel(const Source& source);
|
static Pointer createPixel(const Source& source);
|
||||||
static Pointer createGeometry(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);
|
||||||
|
|
||||||
|
static Pointer createProgram(uint32_t programId);
|
||||||
static Pointer createProgram(const Pointer& vertexShader, const Pointer& pixelShader);
|
static Pointer createProgram(const Pointer& vertexShader, const Pointer& pixelShader);
|
||||||
static Pointer createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
|
static Pointer createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
|
||||||
|
|
||||||
|
|
||||||
~Shader();
|
~Shader();
|
||||||
|
|
||||||
ID getID() const { return _ID; }
|
ID getID() const { return _ID; }
|
||||||
|
@ -156,22 +217,6 @@ public:
|
||||||
const SlotSet& getResourceBuffers() const { return _resourceBuffers; }
|
const SlotSet& getResourceBuffers() const { return _resourceBuffers; }
|
||||||
const SlotSet& getTextures() const { return _textures; }
|
const SlotSet& getTextures() const { return _textures; }
|
||||||
const SlotSet& getSamplers() const { return _samplers; }
|
const SlotSet& getSamplers() const { return _samplers; }
|
||||||
|
|
||||||
const SlotSet& getInputs() const { return _inputs; }
|
|
||||||
const SlotSet& getOutputs() const { return _outputs; }
|
|
||||||
|
|
||||||
// Define the list of uniforms, inputs and outputs for the shader
|
|
||||||
// This call is intendend to build the list of exposed slots in order
|
|
||||||
// to correctly bind resource to the shader.
|
|
||||||
// These can be build "manually" from knowledge of the atual shader code
|
|
||||||
// or automatically by calling "makeShader()", this is the preferred way
|
|
||||||
void defineSlots(const SlotSet& uniforms,
|
|
||||||
const SlotSet& uniformBuffers,
|
|
||||||
const SlotSet& resourceBuffers,
|
|
||||||
const SlotSet& textures,
|
|
||||||
const SlotSet& samplers,
|
|
||||||
const SlotSet& inputs,
|
|
||||||
const SlotSet& outputs);
|
|
||||||
|
|
||||||
// Compilation Handler can be passed while compiling a shader (in the makeProgram call) to be able to give the hand to
|
// 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 comilation fails and to prvide a different version of the source for it
|
||||||
|
@ -180,22 +225,7 @@ public:
|
||||||
// @param2 the compilation log containing the error message
|
// @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
|
// @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
|
// @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
|
||||||
using CompilationHandler = std::function<bool (const Shader&, const std::string&, CompilationLog&, std::string&)>;
|
using CompilationHandler = std::function<bool(const Shader&, const std::string&, CompilationLog&, std::string&)>;
|
||||||
|
|
||||||
// makeProgram(...) make a program shader ready to be used in a Batch.
|
|
||||||
// It compiles the sub shaders, link them and defines the Slots and their bindings.
|
|
||||||
// If the shader passed is not a program, nothing happens.
|
|
||||||
//
|
|
||||||
// It is possible to provide a set of slot bindings (from the name of the slot to a unit number) allowing
|
|
||||||
// to make sure slots with the same semantics can be always bound on the same location from shader to shader.
|
|
||||||
// For example, the "diffuseMap" can always be bound to texture unit #1 for different shaders by specifying a Binding("diffuseMap", 1)
|
|
||||||
//
|
|
||||||
// As of now (03/2015), the call to makeProgram is in fact calling gpu::Context::makeProgram and does rely
|
|
||||||
// on the underneath gpu::Context::Backend available. Since we only support glsl, this means that it relies
|
|
||||||
// on a gl Context and the driver to compile the glsl shader.
|
|
||||||
// Hoppefully in a few years the shader compilation will be completely abstracted in a separate shader compiler library
|
|
||||||
// independant of the graphics api in use underneath (looking at you opengl & vulkan).
|
|
||||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& bindings = Shader::BindingSet(), const CompilationHandler& handler = nullptr);
|
|
||||||
|
|
||||||
// Check the compilation state
|
// Check the compilation state
|
||||||
bool compilationHasFailed() const { return _compilationHasFailed; }
|
bool compilationHasFailed() const { return _compilationHasFailed; }
|
||||||
|
@ -207,16 +237,14 @@ public:
|
||||||
void setCompilationLogs(const CompilationLogs& logs) const;
|
void setCompilationLogs(const CompilationLogs& logs) const;
|
||||||
void incrementCompilationAttempt() const;
|
void incrementCompilationAttempt() const;
|
||||||
|
|
||||||
|
const GPUObjectPointer gpuObject{};
|
||||||
const GPUObjectPointer gpuObject {};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Shader(Type type, const Source& source);
|
Shader(Type type, const Source& source);
|
||||||
Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
|
Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
|
||||||
|
|
||||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
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 contains the actual source code or nothing if the shader is a program
|
||||||
Source _source;
|
Source _source;
|
||||||
|
@ -245,32 +273,29 @@ protected:
|
||||||
mutable CompilationLogs _compilationLogs;
|
mutable CompilationLogs _compilationLogs;
|
||||||
|
|
||||||
// Whether or not the shader compilation failed
|
// Whether or not the shader compilation failed
|
||||||
bool _compilationHasFailed { false };
|
bool _compilationHasFailed{ false };
|
||||||
|
|
||||||
|
// Global maps of the shaders
|
||||||
// Global maps of the shaders
|
|
||||||
// Unique shader ID
|
// Unique shader ID
|
||||||
static std::atomic<ID> _nextShaderID;
|
static std::atomic<ID> _nextShaderID;
|
||||||
|
|
||||||
using ShaderMap = std::map<Source, std::weak_ptr<Shader>, Source::Less>;
|
using ShaderMap = std::map<Source, std::weak_ptr<Shader>, Source::Less>;
|
||||||
using DomainShaderMaps = std::array<ShaderMap, NUM_DOMAINS>;
|
using DomainShaderMaps = std::array<ShaderMap, NUM_DOMAINS>;
|
||||||
static DomainShaderMaps _domainShaderMaps;
|
static DomainShaderMaps _domainShaderMaps;
|
||||||
|
|
||||||
static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
|
static ShaderPointer createOrReuseDomainShader(Type type, const Source& source);
|
||||||
|
|
||||||
using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key
|
using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key
|
||||||
class ProgramKeyLess {
|
class ProgramKeyLess {
|
||||||
public:
|
public:
|
||||||
bool operator() (const ProgramMapKey& l, const ProgramMapKey& r) const {
|
bool operator()(const ProgramMapKey& l, const ProgramMapKey& r) const {
|
||||||
if (l.x == r.x) {
|
if (l.x == r.x) {
|
||||||
if (l.y == r.y) {
|
if (l.y == r.y) {
|
||||||
return (l.z < r.z);
|
return (l.z < r.z);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return (l.y < r.y);
|
return (l.y < r.y);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return (l.x < r.x);
|
return (l.x < r.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,13 +303,15 @@ protected:
|
||||||
using ProgramMap = std::map<ProgramMapKey, std::weak_ptr<Shader>, ProgramKeyLess>;
|
using ProgramMap = std::map<ProgramMapKey, std::weak_ptr<Shader>, ProgramKeyLess>;
|
||||||
static ProgramMap _programMap;
|
static ProgramMap _programMap;
|
||||||
|
|
||||||
static ShaderPointer createOrReuseProgramShader(Type type, const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
|
static ShaderPointer createOrReuseProgramShader(Type type,
|
||||||
|
const Pointer& vertexShader,
|
||||||
|
const Pointer& geometryShader,
|
||||||
|
const Pointer& pixelShader);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Shader::Pointer ShaderPointer;
|
typedef Shader::Pointer ShaderPointer;
|
||||||
typedef std::vector< ShaderPointer > Shaders;
|
typedef std::vector<ShaderPointer> Shaders;
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
}; // namespace gpu
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
129
libraries/gpu/src/gpu/ShaderConstants.h
Normal file
129
libraries/gpu/src/gpu/ShaderConstants.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
// <!
|
||||||
|
// Created by Bradley Austin Davis on 2018/05/25
|
||||||
|
// Copyright 2013-2018 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
|
||||||
|
// !>
|
||||||
|
|
||||||
|
// <@if not GPU_SHADER_CONSTANTS_H@>
|
||||||
|
// <@def GPU_SHADER_CONSTANTS_H@>
|
||||||
|
|
||||||
|
// Hack comment to absorb the extra '//' scribe prepends
|
||||||
|
|
||||||
|
#ifndef GPU_SHADER_CONSTANTS_H
|
||||||
|
#define GPU_SHADER_CONSTANTS_H
|
||||||
|
|
||||||
|
#define GPU_BUFFER_TRANSFORM_CAMERA 15
|
||||||
|
#define GPU_BUFFER_TEXTURE_TABLE0 16
|
||||||
|
#define GPU_BUFFER_TEXTURE_TABLE1 17
|
||||||
|
#define GPU_BUFFER_CAMERA_CORRECTION 18
|
||||||
|
|
||||||
|
#define GPU_TEXTURE_TRANSFORM_OBJECT 31
|
||||||
|
|
||||||
|
#define GPU_STORAGE_TRANSFORM_OBJECT 7
|
||||||
|
|
||||||
|
#define GPU_ATTR_POSITION 0
|
||||||
|
#define GPU_ATTR_NORMAL 1
|
||||||
|
#define GPU_ATTR_COLOR 2
|
||||||
|
#define GPU_ATTR_TEXCOORD0 3
|
||||||
|
#define GPU_ATTR_TANGENT 4
|
||||||
|
#define GPU_ATTR_SKIN_CLUSTER_INDEX 5
|
||||||
|
#define GPU_ATTR_SKIN_CLUSTER_WEIGHT 6
|
||||||
|
#define GPU_ATTR_TEXCOORD1 7
|
||||||
|
#define GPU_ATTR_TEXCOORD2 8
|
||||||
|
#define GPU_ATTR_TEXCOORD3 9
|
||||||
|
#define GPU_ATTR_TEXCOORD4 10
|
||||||
|
#define GPU_ATTR_STEREO_SIDE 14
|
||||||
|
#define GPU_ATTR_DRAW_CALL_INFO 15
|
||||||
|
|
||||||
|
// OSX seems to have an issue using 14 as an attribute location for passing from the vertex to the fragment shader
|
||||||
|
#define GPU_ATTR_V2F_STEREO_SIDE 8
|
||||||
|
|
||||||
|
#define GPU_UNIFORM_COLOR 101
|
||||||
|
#define GPU_UNIFORM_TEXCOORD_RECT 102
|
||||||
|
#define GPU_UNIFORM_EXTRA0 110
|
||||||
|
#define GPU_UNIFORM_EXTRA1 111
|
||||||
|
#define GPU_UNIFORM_EXTRA2 112
|
||||||
|
#define GPU_UNIFORM_EXTRA3 113
|
||||||
|
#define GPU_UNIFORM_EXTRA4 114
|
||||||
|
#define GPU_UNIFORM_EXTRA5 115
|
||||||
|
#define GPU_UNIFORM_EXTRA6 116
|
||||||
|
#define GPU_UNIFORM_EXTRA7 117
|
||||||
|
#define GPU_UNIFORM_EXTRA8 118
|
||||||
|
#define GPU_UNIFORM_EXTRA9 119
|
||||||
|
|
||||||
|
// <!
|
||||||
|
|
||||||
|
namespace gpu { namespace slot {
|
||||||
|
|
||||||
|
namespace buffer {
|
||||||
|
enum Buffer {
|
||||||
|
CameraTransform = GPU_BUFFER_TRANSFORM_CAMERA,
|
||||||
|
TextureTable0 = GPU_BUFFER_TEXTURE_TABLE0,
|
||||||
|
TextureTable1 = GPU_BUFFER_TEXTURE_TABLE1,
|
||||||
|
CameraCorrection = GPU_BUFFER_CAMERA_CORRECTION,
|
||||||
|
};
|
||||||
|
} // namespace buffer
|
||||||
|
|
||||||
|
namespace texture {
|
||||||
|
enum Texture {
|
||||||
|
ObjectTransforms = GPU_TEXTURE_TRANSFORM_OBJECT,
|
||||||
|
};
|
||||||
|
} // namespace texture
|
||||||
|
|
||||||
|
namespace storage {
|
||||||
|
enum Storage {
|
||||||
|
ObjectTransforms = GPU_STORAGE_TRANSFORM_OBJECT,
|
||||||
|
};
|
||||||
|
} // namespace storage
|
||||||
|
|
||||||
|
namespace attr {
|
||||||
|
enum Attribute {
|
||||||
|
Position = GPU_ATTR_POSITION,
|
||||||
|
Normal = GPU_ATTR_NORMAL,
|
||||||
|
Color = GPU_ATTR_COLOR,
|
||||||
|
TexCoord0 = GPU_ATTR_TEXCOORD0,
|
||||||
|
Tangent = GPU_ATTR_TANGENT,
|
||||||
|
SkinClusterIndex = GPU_ATTR_SKIN_CLUSTER_INDEX,
|
||||||
|
SkinClusterWeight = GPU_ATTR_SKIN_CLUSTER_WEIGHT,
|
||||||
|
TexCoord1 = GPU_ATTR_TEXCOORD1,
|
||||||
|
TexCoord2 = GPU_ATTR_TEXCOORD2,
|
||||||
|
TexCoord3 = GPU_ATTR_TEXCOORD3,
|
||||||
|
TexCoord4 = GPU_ATTR_TEXCOORD4,
|
||||||
|
StereoSide = GPU_ATTR_STEREO_SIDE,
|
||||||
|
DrawCallInfo = GPU_ATTR_DRAW_CALL_INFO,
|
||||||
|
};
|
||||||
|
} // namespace attr
|
||||||
|
|
||||||
|
namespace uniform {
|
||||||
|
enum Uniform {
|
||||||
|
Color = GPU_UNIFORM_COLOR,
|
||||||
|
TexCoordRect = GPU_UNIFORM_TEXCOORD_RECT,
|
||||||
|
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
|
||||||
|
|
||||||
|
// !>
|
||||||
|
|
||||||
|
// Hack Comment
|
||||||
|
#endif // GPU_SHADER_CONSTANTS_H
|
||||||
|
|
||||||
|
// <@if 1@>
|
||||||
|
// Trigger Scribe include
|
||||||
|
// <@endif@> <!def that !>
|
||||||
|
|
||||||
|
// <@endif@>
|
||||||
|
|
||||||
|
// Hack Comment
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue