mirror of
https://github.com/overte-org/overte.git
synced 2025-04-12 19:58:15 +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)
|
||||
add_subdirectory(tools/scribe)
|
||||
add_subdirectory(tools/shader_reflect)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ android {
|
|||
'-DANDROID_STL=c++_shared',
|
||||
'-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake',
|
||||
'-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe' + EXEC_SUFFIX,
|
||||
'-DNATIVE_SHREFLECT=' + HIFI_ANDROID_PRECOMPILED + '/shreflect' + EXEC_SUFFIX,
|
||||
'-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED,
|
||||
'-DRELEASE_NUMBER=' + RELEASE_NUMBER,
|
||||
'-DRELEASE_TYPE=' + RELEASE_TYPE,
|
||||
|
|
|
@ -164,18 +164,29 @@ def packages = [
|
|||
|
||||
|
||||
def scribeLocalFile='scribe' + EXEC_SUFFIX
|
||||
|
||||
def scribeFile='scribe_linux_x86_64'
|
||||
def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6'
|
||||
def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G'
|
||||
|
||||
def shreflectLocalFile='shreflect' + EXEC_SUFFIX
|
||||
def shreflectFile='shreflect_linux_x86_64'
|
||||
def shreflectChecksum='d6094a8580066c0b6f4e80b5adfb1d98'
|
||||
def shreflectVersion='jnrpudh6fptIg6T2.Z6fgKP2ultAdKmE'
|
||||
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
scribeFile = 'scribe_osx_x86_64'
|
||||
scribeChecksum='72db9d32d4e1e50add755570ac5eb749'
|
||||
scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC'
|
||||
shreflectFile='shreflect_osx_x86_64'
|
||||
shreflectChecksum='d613ef0703c21371fee93fd2e54b964f'
|
||||
shreflectVersion='.rYNzjSFq6WtWDnE5KIKRIAGyJtr__ad'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
scribeFile = 'scribe_win32_x86_64.exe'
|
||||
scribeChecksum='678e43d290c90fda670c6fefe038a06d'
|
||||
scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7'
|
||||
shreflectFile='shreflect_win32_x86_64.exe'
|
||||
shreflectChecksum='6f4a77b8cceb3f1bbc655132c3665060'
|
||||
shreflectVersion='iIyCyza1nelkbI7ihybF59bBlwrfAC3D'
|
||||
}
|
||||
|
||||
def options = [
|
||||
|
@ -450,11 +461,27 @@ task fixScribePermissions(type: Exec, dependsOn: verifyScribe) {
|
|||
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
|
||||
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
setupScribe.dependsOn fixScribePermissions
|
||||
setupScribe.dependsOn fixShreflectPermissions
|
||||
}
|
||||
|
||||
task extractGvrBinaries(dependsOn: extractDependencies) {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
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 (NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
message( FATAL_ERROR "Only 64 bit builds supported." )
|
||||
endif()
|
||||
|
||||
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
if (NOT WINDOW_SDK_PATH)
|
||||
|
@ -52,32 +54,27 @@ endif()
|
|||
|
||||
if (ANDROID)
|
||||
# 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))
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
|
||||
if (COMPILER_SUPPORTS_CXX14)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
|
||||
else()
|
||||
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
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)
|
||||
set(ANDROID_LIB_DIR $ENV{ANDROID_LIB_DIR})
|
||||
|
@ -110,4 +107,4 @@ if (APPLE)
|
|||
# set that as the SDK to use
|
||||
set(CMAKE_OSX_SYSROOT ${_OSX_DESIRED_SDK_PATH}/MacOSX${OSX_SDK}.sdk)
|
||||
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
|
||||
#
|
||||
|
||||
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)
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
|
@ -45,11 +51,8 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
|||
elseif(${SHADER_EXT} STREQUAL .slg)
|
||||
set(SHADER_TYPE geom)
|
||||
endif()
|
||||
set(SHADER_TARGET ${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)
|
||||
file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}")
|
||||
set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_TARGET}.${SHADER_TYPE}")
|
||||
set(SCRIBE_COMMAND scribe)
|
||||
|
||||
# Target dependant Custom rule on the SHADER_FILE
|
||||
|
@ -63,65 +66,232 @@ function(AUTOSCRIBE_SHADER SHADER_FILE)
|
|||
else ()
|
||||
set(GLPROFILE PC_GL)
|
||||
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(
|
||||
OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE}
|
||||
OUTPUT ${SHADER_TARGET}
|
||||
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
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} PARENT_SCOPE)
|
||||
|
||||
file(GLOB INCLUDE_FILES ${SHADER_TARGET_HEADER})
|
||||
|
||||
set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE)
|
||||
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)
|
||||
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}")
|
||||
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)
|
||||
endforeach()
|
||||
#message("${TARGET_NAME} ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES}")
|
||||
endmacro()
|
||||
|
||||
file(GLOB_RECURSE SHADER_INCLUDE_FILES src/*.slh)
|
||||
file(GLOB_RECURSE SHADER_SOURCE_FILES src/*.slv src/*.slf src/*.slg)
|
||||
macro(AUTOSCRIBE_PROGRAM)
|
||||
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
|
||||
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders/${TARGET_NAME}")
|
||||
file(MAKE_DIRECTORY ${SHADERS_DIR})
|
||||
if (NOT (${AUTOSCRIBE_PROGRAM_VERTEX} MATCHES ".*::.*"))
|
||||
set(AUTOSCRIBE_PROGRAM_VERTEX "vertex::${AUTOSCRIBE_PROGRAM_VERTEX}")
|
||||
endif()
|
||||
if (NOT (${AUTOSCRIBE_PROGRAM_FRAGMENT} MATCHES ".*::.*"))
|
||||
set(AUTOSCRIBE_PROGRAM_FRAGMENT "fragment::${AUTOSCRIBE_PROGRAM_FRAGMENT}")
|
||||
endif()
|
||||
|
||||
#message("${TARGET_NAME} ${SHADER_INCLUDE_FILES}")
|
||||
set(AUTOSCRIBE_SHADER_SRC "")
|
||||
foreach(SHADER_FILE ${SHADER_SOURCE_FILES})
|
||||
AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES})
|
||||
unset(AUTOSCRIBE_PROGRAM_MAP)
|
||||
list(APPEND AUTOSCRIBE_PROGRAM_MAP AUTOSCRIBE_PROGRAM_VERTEX)
|
||||
list(APPEND AUTOSCRIBE_PROGRAM_MAP ${AUTOSCRIBE_PROGRAM_VERTEX})
|
||||
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)
|
||||
set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON)
|
||||
list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE})
|
||||
endforeach()
|
||||
#message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
if (WIN32)
|
||||
source_group("Shaders" FILES ${SHADER_INCLUDE_FILES})
|
||||
source_group("Shaders" FILES ${SHADER_SOURCE_FILES})
|
||||
source_group("Shaders\\generated" FILES ${AUTOSCRIBE_SHADER_SRC})
|
||||
endif()
|
||||
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_INCLUDE_FILES})
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_SOURCE_FILES})
|
||||
list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_SRC})
|
||||
|
||||
# Link library shaders, if they exist
|
||||
include_directories("${SHADERS_DIR}")
|
||||
|
||||
# Add search directory to find gpu/Shader.h
|
||||
include_directories("${HIFI_LIBRARY_DIR}/gpu/src")
|
||||
|
||||
source_group("Compiled/${SHADER_LIB}" FILES ${AUTOSCRIBE_GENERATED_FILE})
|
||||
set(REFLECTED_SHADER "${AUTOSCRIBE_GENERATED_FILE}.json")
|
||||
source_group("Reflected/${SHADER_LIB}" FILES ${REFLECTED_SHADER})
|
||||
list(APPEND COMPILED_SHADERS ${AUTOSCRIBE_GENERATED_FILE})
|
||||
get_filename_component(ENUM_NAME ${SHADER} NAME_WE)
|
||||
string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${ENUM_NAME} = ${SHADER_COUNT},\n")
|
||||
MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1")
|
||||
endmacro()
|
||||
|
||||
macro(AUTOSCRIBE_SHADER_FINISH)
|
||||
get_property(GLOBAL_SHADER_LIBS GLOBAL PROPERTY GLOBAL_SHADER_LIBS)
|
||||
list(REMOVE_DUPLICATES GLOBAL_SHADER_LIBS)
|
||||
set(SHADER_COUNT 0)
|
||||
set(PROGRAM_COUNT 0)
|
||||
set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders")
|
||||
set(SHADER_ENUMS "")
|
||||
file(MAKE_DIRECTORY ${SHADERS_DIR})
|
||||
|
||||
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()
|
||||
|
|
|
@ -19,12 +19,8 @@ function(LINK_HIFI_LIBRARIES)
|
|||
endforeach()
|
||||
|
||||
foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK})
|
||||
|
||||
include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src")
|
||||
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}/shaders")
|
||||
|
||||
#add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
|
||||
include_directories("${CMAKE_BINARY_DIR}/libraries/${HIFI_LIBRARY}")
|
||||
# link the actual library - it is static so don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY})
|
||||
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",
|
||||
"type": "int",
|
||||
"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() {
|
||||
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);
|
||||
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::nodeKilled, this, &DomainServer::nodeKilled);
|
||||
|
||||
|
@ -1133,7 +1137,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
extendedHeaderStream << node->getUUID();
|
||||
extendedHeaderStream << node->getLocalID();
|
||||
extendedHeaderStream << node->getPermissions();
|
||||
|
||||
extendedHeaderStream << limitedNodeList->getAuthenticatePackets();
|
||||
auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader);
|
||||
|
||||
// always send the node their own UUID back
|
||||
|
|
|
@ -214,6 +214,7 @@ link_hifi_libraries(
|
|||
controllers plugins image trackers
|
||||
ui-plugins display-plugins input-plugins
|
||||
${PLATFORM_GL_BACKEND}
|
||||
shaders
|
||||
)
|
||||
|
||||
# include the binary directory of render-utils for shader includes
|
||||
|
|
|
@ -62,6 +62,7 @@ Windows.ScrollingWindow {
|
|||
url: "about:blank"
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ Item {
|
|||
anchors.fill: stackView
|
||||
id: controllerPrefereneces
|
||||
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: {
|
||||
"VR Movement" : {
|
||||
"User real-world height (meters)" : { "anchors.right" : "undefined" },
|
||||
|
|
|
@ -2703,8 +2703,6 @@ void Application::initializeGL() {
|
|||
// contexts
|
||||
_glWidget->makeCurrent();
|
||||
gpu::Context::init<gpu::gl::GLBackend>();
|
||||
qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK,
|
||||
QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram)));
|
||||
_glWidget->makeCurrent();
|
||||
_gpuContext = std::make_shared<gpu::Context>();
|
||||
|
||||
|
@ -4574,11 +4572,14 @@ void Application::idle() {
|
|||
_lastTimeUpdated.start();
|
||||
|
||||
// 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()) {
|
||||
_keyboardMouseDevice->pluginFocusOutEvent();
|
||||
_keyboardDeviceHasFocus = false;
|
||||
} else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) {
|
||||
_keyboardDeviceHasFocus = true;
|
||||
if (offscreenUi && offscreenUi->getWindow()) {
|
||||
auto activeFocusItem = offscreenUi->getWindow()->activeFocusItem();
|
||||
if (_keyboardDeviceHasFocus && activeFocusItem != offscreenUi->getRootItem()) {
|
||||
_keyboardMouseDevice->pluginFocusOutEvent();
|
||||
_keyboardDeviceHasFocus = false;
|
||||
} else if (activeFocusItem == offscreenUi->getRootItem()) {
|
||||
_keyboardDeviceHasFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
checkChangeCursor();
|
||||
|
@ -6619,11 +6620,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
bool clientScript = scriptEngine->isClientScript();
|
||||
scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor);
|
||||
#if !defined(Q_OS_ANDROID)
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
scriptEngine->registerFunction("OverlayWebWindow", clientScript ? QmlWebWindowClass::constructor : QmlWebWindowClass::restricted_constructor);
|
||||
#endif
|
||||
scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor);
|
||||
scriptEngine->registerFunction("QmlFragment", QmlFragmentClass::constructor);
|
||||
scriptEngine->registerFunction("QmlFragment", clientScript ? QmlFragmentClass::constructor : QmlFragmentClass::restricted_constructor);
|
||||
|
||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get<DesktopPreviewProvider>().data());
|
||||
|
|
|
@ -412,9 +412,6 @@ void AvatarManager::clearOtherAvatars() {
|
|||
while (avatarIterator != _avatarHash.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
||||
if (avatar != _myAvatar) {
|
||||
if (avatar->isInScene()) {
|
||||
avatar->removeFromScene(avatar, scene, transaction);
|
||||
}
|
||||
handleRemovedAvatar(avatar);
|
||||
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||
} else {
|
||||
|
|
|
@ -1135,7 +1135,6 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||
settings.setValue("userHeight", getUserHeight());
|
||||
settings.setValue("flyingDesktop", getFlyingDesktopPref());
|
||||
settings.setValue("flyingHMD", getFlyingHMDPref());
|
||||
|
||||
settings.endGroup();
|
||||
|
@ -1289,7 +1288,6 @@ void MyAvatar::loadData() {
|
|||
|
||||
// Flying preferences must be loaded before calling setFlyingEnabled()
|
||||
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
||||
setFlyingDesktopPref(firstRunVal.get() ? true : settings.value("flyingDesktop").toBool());
|
||||
setFlyingHMDPref(firstRunVal.get() ? false : settings.value("flyingHMD").toBool());
|
||||
setFlyingEnabled(getFlyingEnabled());
|
||||
|
||||
|
|
|
@ -12,11 +12,9 @@
|
|||
#include <StencilMaskPass.h>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <shaders/Shaders.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 float ParabolaPointer::RenderState::ParabolaRenderItem::DEFAULT_PARABOLA_WIDTH { 0.01f };
|
||||
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() {
|
||||
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
|
||||
auto vs = parabola_vert::getShader();
|
||||
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);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);
|
||||
|
||||
{
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
|
|
@ -26,7 +26,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
/**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
|
||||
*
|
||||
|
@ -35,14 +35,23 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
|||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {boolean} muted
|
||||
* @property {boolean} noiseReduction
|
||||
* @property {number} inputVolume
|
||||
* @property {number} inputLevel <em>Read-only.</em>
|
||||
* @property {string} context <em>Read-only.</em>
|
||||
* @property {} devices <em>Read-only.</em>
|
||||
* @property {boolean} muted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||
* @property {boolean} noiseReduction - <code>true</code> if noise reduction is enabled, otherwise <code>false</code>. When
|
||||
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
||||
* above the noise floor.
|
||||
* @property {number} inputLevel - The loudness of the audio input, range <code>0.0</code> (no sound) –
|
||||
* <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 noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
||||
Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY inputVolumeChanged)
|
||||
|
@ -69,45 +78,91 @@ public:
|
|||
|
||||
/**jsdoc
|
||||
* @function Audio.setInputDevice
|
||||
* @param {} device
|
||||
* @param {object} device
|
||||
* @param {boolean} isHMD
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||
|
||||
/**jsdoc
|
||||
* @function Audio.setOutputDevice
|
||||
* @param {} device
|
||||
* @param {object} device
|
||||
* @param {boolean} isHMD
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
|
||||
|
||||
/**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
|
||||
* @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);
|
||||
|
||||
/**jsdoc
|
||||
* Configure reverberation options. Use {@link Audio.setReverb|setReverb} to enable or disable reverberation.
|
||||
* @function Audio.setReverbOptions
|
||||
* @param {AudioEffectOptions} options
|
||||
* @param {AudioEffectOptions} options - The reverberation options.
|
||||
*/
|
||||
Q_INVOKABLE void setReverbOptions(const AudioEffectOptions* options);
|
||||
|
||||
/**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
|
||||
* @param {string} filename
|
||||
* @returns {boolean}
|
||||
* @param {string} filename - The path and name of the file to make the recording in. Should have a <code>.wav</code>
|
||||
* 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);
|
||||
|
||||
/**jsdoc
|
||||
* Finish making an audio recording started with {@link Audio.startRecording|startRecording}.
|
||||
* @function Audio.stopRecording
|
||||
*/
|
||||
Q_INVOKABLE void stopRecording();
|
||||
|
||||
/**jsdoc
|
||||
* Check whether an audio recording is currently being made.
|
||||
* @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();
|
||||
|
||||
|
@ -116,40 +171,54 @@ signals:
|
|||
/**jsdoc
|
||||
* @function Audio.nop
|
||||
* @returns {Signal}
|
||||
* @deprecated This signal is deprecated and will be removed.
|
||||
*/
|
||||
void nop();
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the audio input is muted or unmuted.
|
||||
* @function Audio.mutedChanged
|
||||
* @param {boolean} isMuted
|
||||
* @param {boolean} isMuted - <code>true</code> if the audio input is muted, otherwise <code>false</code>.
|
||||
* @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);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the audio input noise reduction is enabled or disabled.
|
||||
* @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}
|
||||
*/
|
||||
void noiseReductionChanged(bool isEnabled);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the input audio volume changes.
|
||||
* @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}
|
||||
*/
|
||||
void inputVolumeChanged(float volume);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the input audio level changes.
|
||||
* @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}
|
||||
*/
|
||||
void inputLevelChanged(float level);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the current context of the audio changes.
|
||||
* @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}
|
||||
*/
|
||||
void contextChanged(const QString& context);
|
||||
|
@ -158,7 +227,7 @@ public slots:
|
|||
|
||||
/**jsdoc
|
||||
* @function Audio.onContextChanged
|
||||
* @returns {Signal}
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
void onContextChanged();
|
||||
|
||||
|
|
|
@ -266,42 +266,6 @@ void setupPreferences() {
|
|||
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" };
|
||||
{
|
||||
|
||||
|
@ -315,7 +279,7 @@ void setupPreferences() {
|
|||
{
|
||||
auto getter = [=]()->bool { return myAvatar->getFlyingHMDPref(); };
|
||||
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; };
|
||||
|
|
|
@ -14,11 +14,7 @@
|
|||
|
||||
#include <StencilMaskPass.h>
|
||||
#include <GeometryCache.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"
|
||||
#include <shaders/Shaders.h>
|
||||
|
||||
|
||||
void GameSpaceToRender::configure(const Config& config) {
|
||||
|
@ -149,14 +145,7 @@ void GameWorkloadRenderItem::setAllViews(const workload::Views& views) {
|
|||
|
||||
const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
|
||||
if (!_drawAllProxiesPipeline) {
|
||||
auto vs = drawWorkloadProxy_vert::getShader();
|
||||
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);
|
||||
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadProxy);
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
/* state->setBlendFunction(true,
|
||||
|
@ -173,15 +162,7 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getProxiesPipeline() {
|
|||
|
||||
const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
|
||||
if (!_drawAllViewsPipeline) {
|
||||
auto vs = drawWorkloadView_vert::getShader();
|
||||
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);
|
||||
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::drawWorkloadView);
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
/* state->setBlendFunction(true,
|
||||
|
@ -192,6 +173,7 @@ const gpu::PipelinePointer GameWorkloadRenderItem::getViewsPipeline() {
|
|||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
_drawAllViewsPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
return _drawAllViewsPipeline;
|
||||
}
|
||||
|
||||
|
|
|
@ -1547,16 +1547,18 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
|||
glm::vec3 backVector = oppositeArmPose.trans() - armPose.trans();
|
||||
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
|
||||
frontVector = frontVector.z < 0 ? -frontVector : frontVector;
|
||||
|
||||
float horizontalModule = glm::dot(armToHand, glm::vec3(0, -1, 0));
|
||||
glm::vec3 headForward = headCenter + horizontalModule * frontVector;
|
||||
float horizontalModule = glm::dot(centerToHand, -topVector);
|
||||
|
||||
glm::vec3 headForward = headCenter + glm::max(0.0f, horizontalModule) * frontVector;
|
||||
glm::vec3 armToHead = headForward - armPose.trans();
|
||||
|
||||
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
|
||||
float oppositeProjection = glm::dot(armToHandDir, glm::normalize(backVector));
|
||||
|
||||
// Don't use pole vector when the hands are behind
|
||||
if (glm::dot(frontVector, armToHand) < 0 && oppositeProjection < 0.5f * armTotalDistance) {
|
||||
bool isCrossed = glm::dot(centerToHand, backVector) > 0;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1585,7 +1589,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex,
|
|||
glm::vec3 correctionVector = glm::vec3(0, 0, 0);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -59,28 +59,29 @@ static void setOption(QScriptValue arguments, const QString name, float defaultV
|
|||
}
|
||||
|
||||
/**jsdoc
|
||||
* Reverberation options that can be used to initialize an {@link AudioEffectOptions} object when created.
|
||||
* @typedef {object} AudioEffectOptions.ReverbOptions
|
||||
* @property {number} bandwidth
|
||||
* @property {number} preDelay
|
||||
* @property {number} lateDelay
|
||||
* @property {number} reverbTime
|
||||
* @property {number} earlyDiffusion
|
||||
* @property {number} lateDiffusion
|
||||
* @property {number} roomSize
|
||||
* @property {number} density
|
||||
* @property {number} bassMult
|
||||
* @property {number} bassFreq
|
||||
* @property {number} highGain
|
||||
* @property {number} highFreq
|
||||
* @property {number} modRate
|
||||
* @property {number} modDepth
|
||||
* @property {number} earlyGain
|
||||
* @property {number} lateGain
|
||||
* @property {number} earlyMixLeft
|
||||
* @property {number} earlyMixRight
|
||||
* @property {number} lateMixLeft
|
||||
* @property {number} lateMixRight
|
||||
* @property {number} wetDryMix
|
||||
* @property {number} bandwidth=10000 - The corner frequency (Hz) of the low-pass filter at reverb input.
|
||||
* @property {number} preDelay=20 - The delay (milliseconds) between dry signal and the onset of early reflections.
|
||||
* @property {number} lateDelay=0 - The delay (milliseconds) between early reflections and the onset of reverb tail.
|
||||
* @property {number} reverbTime=2 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
|
||||
* @property {number} earlyDiffusion=100 - Adjusts the buildup of echo density in the early reflections, normally 100%.
|
||||
* @property {number} lateDiffusion=100 - Adjusts the buildup of echo density in the reverb tail, normally 100%.
|
||||
* @property {number} roomSize=50 - The apparent room size, from small (0%) to large (100%).
|
||||
* @property {number} density=100 - Adjusts the echo density in the reverb tail, normally 100%.
|
||||
* @property {number} bassMult=1.5 - Adjusts the bass-frequency reverb time, as multiple of reverbTime.
|
||||
* @property {number} bassFreq=250 - The crossover frequency (Hz) for the onset of bassMult.
|
||||
* @property {number} highGain=-6 - Reduces the high-frequency reverb time, as attenuation (dB).
|
||||
* @property {number} highFreq=3000 - The crossover frequency (Hz) for the onset of highGain.
|
||||
* @property {number} modRate=2.3 - The rate of modulation (Hz) of the LFO-modulated delay lines.
|
||||
* @property {number} modDepth=50 - The depth of modulation (percent) of the LFO-modulated delay lines.
|
||||
* @property {number} earlyGain=0 - Adjusts the relative level (dB) of the early reflections.
|
||||
* @property {number} lateGain=0 - Adjusts the relative level (dB) of the reverb tail.
|
||||
* @property {number} earlyMixLeft=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} earlyMixRight=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} lateMixLeft=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%).
|
||||
*/
|
||||
AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) {
|
||||
setOption(arguments, BANDWIDTH_HANDLE, BANDWIDTH_DEFAULT, _bandwidth);
|
||||
|
|
|
@ -16,35 +16,39 @@
|
|||
#include <QtScript/QScriptEngine>
|
||||
|
||||
/**jsdoc
|
||||
* Audio effect options used by the {@link Audio} API.
|
||||
*
|
||||
* <p>Create using <code>new AudioEffectOptions(reverbOptions)</code>.</p>
|
||||
*
|
||||
* @class AudioEffectOptions
|
||||
* @param {AudioEffectOptions.ReverbOptions} [reverbOptions=null]
|
||||
* @param {AudioEffectOptions.ReverbOptions} [reverbOptions=null] - Reverberation options.
|
||||
*
|
||||
* @hifi-interface
|
||||
* @hifi-client-entity
|
||||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {number} bandwidth=10000
|
||||
* @property {number} preDelay=20
|
||||
* @property {number} lateDelay=0
|
||||
* @property {number} reverbTime=2
|
||||
* @property {number} earlyDiffusion=100
|
||||
* @property {number} lateDiffusion=100
|
||||
* @property {number} roomSize=50
|
||||
* @property {number} density=100
|
||||
* @property {number} bassMult=1.5
|
||||
* @property {number} bassFreq=250
|
||||
* @property {number} highGain=-6
|
||||
* @property {number} highFreq=3000
|
||||
* @property {number} modRate=2.3
|
||||
* @property {number} modDepth=50
|
||||
* @property {number} earlyGain=0
|
||||
* @property {number} lateGain=0
|
||||
* @property {number} earlyMixLeft=20
|
||||
* @property {number} earlyMixRight=20
|
||||
* @property {number} lateMixLeft=90
|
||||
* @property {number} lateMixRight=90
|
||||
* @property {number} wetDryMix=50
|
||||
* @property {number} bandwidth=10000 - The corner frequency (Hz) of the low-pass filter at reverb input.
|
||||
* @property {number} preDelay=20 - The delay (milliseconds) between dry signal and the onset of early reflections.
|
||||
* @property {number} lateDelay=0 - The delay (milliseconds) between early reflections and the onset of reverb tail.
|
||||
* @property {number} reverbTime=2 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60.
|
||||
* @property {number} earlyDiffusion=100 - Adjusts the buildup of echo density in the early reflections, normally 100%.
|
||||
* @property {number} lateDiffusion=100 - Adjusts the buildup of echo density in the reverb tail, normally 100%.
|
||||
* @property {number} roomSize=50 - The apparent room size, from small (0%) to large (100%).
|
||||
* @property {number} density=100 - Adjusts the echo density in the reverb tail, normally 100%.
|
||||
* @property {number} bassMult=1.5 - Adjusts the bass-frequency reverb time, as multiple of reverbTime.
|
||||
* @property {number} bassFreq=250 - The crossover frequency (Hz) for the onset of bassMult.
|
||||
* @property {number} highGain=-6 - Reduces the high-frequency reverb time, as attenuation (dB).
|
||||
* @property {number} highFreq=3000 - The crossover frequency (Hz) for the onset of highGain.
|
||||
* @property {number} modRate=2.3 - The rate of modulation (Hz) of the LFO-modulated delay lines.
|
||||
* @property {number} modDepth=50 - The depth of modulation (percent) of the LFO-modulated delay lines.
|
||||
* @property {number} earlyGain=0 - Adjusts the relative level (dB) of the early reflections.
|
||||
* @property {number} lateGain=0 - Adjusts the relative level (dB) of the reverb tail.
|
||||
* @property {number} earlyMixLeft=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} earlyMixRight=20 - The apparent distance of the source (percent) in the early reflections.
|
||||
* @property {number} lateMixLeft=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} lateMixRight=90 - The apparent distance of the source (percent) in the reverb tail.
|
||||
* @property {number} wetDryMix=50 - Adjusts the wet/dry ratio, from completely dry (0%) to completely wet (100%).
|
||||
*/
|
||||
|
||||
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]
|
||||
assert(distance < HRTF_NEARFIELD_MAX);
|
||||
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
|
||||
float angleL = azimuth + HALFPI;
|
||||
|
@ -919,6 +919,9 @@ static void azimuthToIndex(float azimuth, int& index0, int& index1, float& frac)
|
|||
index1 = index0 + 1;
|
||||
frac = azimuth - (float)index0;
|
||||
|
||||
if (index0 >= HRTF_AZIMUTHS) {
|
||||
index0 -= HRTF_AZIMUTHS;
|
||||
}
|
||||
if (index1 >= HRTF_AZIMUTHS) {
|
||||
index1 -= HRTF_AZIMUTHS;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,23 @@ QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInje
|
|||
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) {
|
||||
if (!object.isObject()) {
|
||||
qWarning() << "Audio injector options is not an object.";
|
||||
|
|
|
@ -79,6 +79,14 @@ private:
|
|||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||
|
||||
/**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
|
||||
*
|
||||
* @hifi-interface
|
||||
|
@ -86,8 +94,9 @@ typedef QSharedPointer<Sound> SharedSoundPointer;
|
|||
* @hifi-server-entity
|
||||
* @hifi-assignment-client
|
||||
*
|
||||
* @property {boolean} downloaded
|
||||
* @property {number} duration
|
||||
* @property {boolean} downloaded - <code>true</code> if the sound has been downloaded and is ready to be played, otherwise
|
||||
* <code>false</code>.
|
||||
* @property {number} duration - The duration of the sound, in seconds.
|
||||
*/
|
||||
class SoundScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -103,6 +112,7 @@ public:
|
|||
float getDuration() { return _sound->getDuration(); }
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the sound has been downloaded and is ready to be played.
|
||||
* @function SoundObject.ready
|
||||
* @returns {Signal}
|
||||
*/
|
||||
|
|
|
@ -48,9 +48,11 @@ public:
|
|||
SoundCacheScriptingInterface();
|
||||
|
||||
/**jsdoc
|
||||
* Loads the content of an audio file into a {@link SoundObject}, ready for playback by {@link Audio.playSound}.
|
||||
* @function SoundCache.getSound
|
||||
* @param {string} url
|
||||
* @returns {SoundObject}
|
||||
* @param {string} url - The URL of the audio file to load — Web, ATP, or file. See {@link SoundObject} for supported
|
||||
* formats.
|
||||
* @returns {SoundObject} The sound ready for playback.
|
||||
*/
|
||||
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
set(TARGET_NAME display-plugins)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu display-plugins)
|
||||
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(model-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 <gpu/Texture.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
#include <shaders/Shaders.h>
|
||||
#include <gpu/gl/GLShared.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <GeometryCache.h>
|
||||
|
@ -44,33 +44,6 @@
|
|||
#include "CompositorHelper.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;
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
|
@ -391,10 +364,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
|
||||
if (!_presentPipeline) {
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTexture);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setScissorEnable(true);
|
||||
|
@ -402,10 +372,7 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(SRGB_TO_LINEAR_FRAG));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::SrgbToLinear);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setScissorEnable(true);
|
||||
|
@ -413,10 +380,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord);
|
||||
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setBlendFunction(true,
|
||||
|
@ -426,10 +392,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTextureMirroredXPS();
|
||||
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord);
|
||||
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTextureMirroredX);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setBlendFunction(true,
|
||||
|
@ -439,10 +404,9 @@ void OpenGLDisplayPlugin::customizeContext() {
|
|||
}
|
||||
|
||||
{
|
||||
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
|
||||
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawTransformUnitQuad);
|
||||
auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
gpu::Shader::makeProgram(*program);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
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 <shared/NsightHelpers.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <shaders/Shaders.h>
|
||||
|
||||
#include <TextureCache.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -34,8 +34,6 @@
|
|||
#include "../CompositorHelper.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 DISABLE_PREVIEW = "Disable Preview";
|
||||
|
@ -409,12 +407,7 @@ void HmdDisplayPlugin::HUDRenderer::build() {
|
|||
|
||||
void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
|
||||
if (!pipeline) {
|
||||
auto vs = hmd_ui_vert::getShader();
|
||||
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");
|
||||
|
||||
auto program = gpu::Shader::createProgram(shader::render_utils::program::hmd_ui);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(true, true, gpu::LESS_EQUAL));
|
||||
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::TEXCOORD, uvView);
|
||||
batch.setIndexBuffer(gpu::UINT16, indices, 0);
|
||||
|
||||
uniformsBuffer->setSubData(0, uniforms);
|
||||
batch.setUniformBuffer(uniformsLocation, uniformsBuffer);
|
||||
batch.setUniformBuffer(0, uniformsBuffer);
|
||||
|
||||
auto compositorHelper = DependencyManager::get<CompositorHelper>();
|
||||
glm::mat4 modelTransform = compositorHelper->getUiTransform();
|
||||
|
|
|
@ -102,7 +102,6 @@ private:
|
|||
gpu::BufferPointer indices;
|
||||
uint32_t indexCount { 0 };
|
||||
gpu::PipelinePointer pipeline;
|
||||
int32_t uniformsLocation { -1 };
|
||||
|
||||
gpu::BufferPointer uniformsBuffer;
|
||||
|
||||
|
|
|
@ -8,48 +8,17 @@
|
|||
|
||||
#include "InterleavedStereoDisplayPlugin.h"
|
||||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.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";
|
||||
#include <shaders/Shaders.h>
|
||||
|
||||
const QString InterleavedStereoDisplayPlugin::NAME("3D TV - Interleaved");
|
||||
|
||||
void InterleavedStereoDisplayPlugin::customizeContext() {
|
||||
StereoDisplayPlugin::customizeContext();
|
||||
if (!_interleavedPresentPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
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::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::InterleavedSrgbToLinear);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
_interleavedPresentPipeline = gpu::Pipeline::create(program, state);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
set(TARGET_NAME entities-renderer)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu graphics procedural render render-utils)
|
||||
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(gl)
|
||||
include_hifi_library_headers(ktx)
|
||||
|
@ -18,3 +17,4 @@ include_hifi_library_headers(graphics-scripting) # for Forward.h
|
|||
|
||||
target_bullet()
|
||||
target_polyvox()
|
||||
|
||||
|
|
|
@ -336,6 +336,11 @@ bool EntityRenderer::needsRenderUpdate() const {
|
|||
if (_needsRenderUpdate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isFading()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_prevIsTransparent != isTransparent()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -380,6 +385,10 @@ void EntityRenderer::updateModelTransformAndBound() {
|
|||
void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transaction& transaction, const EntityItemPointer& entity) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
||||
withWriteLock([&] {
|
||||
if (isFading()) {
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
|
||||
auto transparent = isTransparent();
|
||||
if (_prevIsTransparent && !transparent) {
|
||||
_isFading = false;
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
#include <StencilMaskPass.h>
|
||||
|
||||
#include <GeometryCache.h>
|
||||
#include <shaders/Shaders.h>
|
||||
|
||||
#include "textured_particle_vert.h"
|
||||
#include "textured_particle_frag.h"
|
||||
|
||||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
@ -23,8 +22,6 @@ using namespace render::entities;
|
|||
static uint8_t CUSTOM_PIPELINE_NUMBER = 0;
|
||||
static gpu::Stream::FormatPointer _vertexFormat;
|
||||
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) {
|
||||
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);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
auto vertShader = textured_particle_vert::getShader();
|
||||
auto fragShader = textured_particle_frag::getShader();
|
||||
|
||||
auto program = gpu::Shader::createProgram(vertShader, fragShader);
|
||||
auto program = gpu::Shader::createProgram(shader::entities_renderer::program::textured_particle);
|
||||
_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);
|
||||
|
@ -346,7 +334,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) {
|
|||
transform.setRotation(_renderTransform.getRotation());
|
||||
});
|
||||
batch.setModelTransform(transform);
|
||||
batch.setUniformBuffer(PARTICLE_UNIFORM_SLOT, _uniformBuffer);
|
||||
batch.setUniformBuffer(0, _uniformBuffer);
|
||||
batch.setInputFormat(_vertexFormat);
|
||||
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(GpuParticle));
|
||||
|
||||
|
|
|
@ -17,18 +17,13 @@
|
|||
#include <TextureCache.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <shaders/Shaders.h>
|
||||
|
||||
//#define POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||
# include <FadeEffect.h>
|
||||
#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::entities;
|
||||
|
||||
|
@ -48,29 +43,12 @@ struct PolyLineUniforms {
|
|||
|
||||
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key, gpu::Batch& batch) {
|
||||
if (!polylinePipeline) {
|
||||
auto VS = paintStroke_vert::getShader();
|
||||
auto PS = paintStroke_frag::getShader();
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS);
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke);
|
||||
#ifdef POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||
auto fadeVS = gpu::Shader::createVertex(std::string(paintStroke_fade_vert));
|
||||
auto fadePS = gpu::Shader::createPixel(std::string(paintStroke_fade_frag));
|
||||
gpu::ShaderPointer fadeProgram = gpu::Shader::createProgram(fadeVS, fadePS);
|
||||
#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());
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
|
|
@ -25,14 +25,15 @@
|
|||
#include <EntityEditPacketSender.h>
|
||||
#include <PhysicalEntitySimulation.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 "polyvox_vert.h"
|
||||
#include "polyvox_frag.h"
|
||||
#include "polyvox_fade_vert.h"
|
||||
#include "polyvox_fade_frag.h"
|
||||
|
||||
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
|
||||
# include <FadeEffect.h>
|
||||
#endif
|
||||
|
@ -72,11 +73,6 @@
|
|||
|
||||
#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 "EntityEditPacketSender.h"
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
|
@ -1564,7 +1560,6 @@ scriptable::ScriptableModelBase RenderablePolyVoxEntityItem::getScriptableModel(
|
|||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
||||
static const int MATERIAL_GPU_SLOT { 3 };
|
||||
static uint8_t CUSTOM_PIPELINE_NUMBER;
|
||||
static gpu::PipelinePointer _pipelines[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) {
|
||||
if (!_pipelines[0]) {
|
||||
gpu::ShaderPointer vertexShaders[2] = { polyvox_vert::getShader(), polyvox_fade_vert::getShader() };
|
||||
gpu::ShaderPointer pixelShaders[2] = { polyvox_frag::getShader(), polyvox_fade_frag::getShader() };
|
||||
|
||||
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
|
||||
using namespace shader::entities_renderer::program;
|
||||
int programsIds[2] = { polyvox, polyvox_fade };
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
|
@ -1597,12 +1583,7 @@ ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const Sha
|
|||
|
||||
// Two sets of pipelines: normal and fading
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShaders[i], pixelShaders[i]);
|
||||
|
||||
batch.runLambda([program, slotBindings] {
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
});
|
||||
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(programsIds[i]);
|
||||
_pipelines[i] = gpu::Pipeline::create(program, state);
|
||||
_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(voxelVolumeSizeLocation, _lastVoxelVolumeSize.x, _lastVoxelVolumeSize.y, _lastVoxelVolumeSize.z);
|
||||
batch._glUniform3f(entities_renderer::slot::uniform::PolyvoxVoxelSize, _lastVoxelVolumeSize.x, _lastVoxelVolumeSize.y, _lastVoxelVolumeSize.z);
|
||||
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_mesh->getNumIndices(), 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,7 @@
|
|||
#include <StencilMaskPass.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <PerfStat.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 <shaders/Shaders.h>
|
||||
|
||||
#include "RenderPipelines.h"
|
||||
|
||||
|
@ -37,12 +32,12 @@ static const float SPHERE_ENTITY_SCALE = 0.5f;
|
|||
|
||||
|
||||
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
|
||||
_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
|
||||
//_procedural._transparentfragmentSource = simple_transparent_frag::getSource();
|
||||
_procedural._transparentfragmentSource = simple_frag::getSource();
|
||||
_procedural._transparentfragmentSource = _procedural._opaquefragmentSource;
|
||||
_procedural._opaqueState->setCullMode(gpu::State::CULL_NONE);
|
||||
_procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
|
||||
|
@ -216,7 +211,14 @@ ShapeKey ShapeEntityRenderer::getShapeKey() {
|
|||
|
||||
return builder.build();
|
||||
} 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
|
||||
uniform sampler2D originalTexture;
|
||||
layout(binding=0) uniform sampler2D originalTexture;
|
||||
|
||||
// the interpolated normal
|
||||
in vec3 interpolatedNormal;
|
||||
in vec2 varTexcoord;
|
||||
in vec4 varColor;
|
||||
layout(location=0) in vec3 interpolatedNormal;
|
||||
layout(location=1) in vec2 varTexcoord;
|
||||
layout(location=2) in vec4 varColor;
|
||||
|
||||
struct PolyLineUniforms {
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
uniform polyLineBuffer {
|
||||
layout(binding=0) uniform polyLineBuffer {
|
||||
PolyLineUniforms polyline;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
// the interpolated normal
|
||||
out vec3 interpolatedNormal;
|
||||
layout(location=0) out vec3 interpolatedNormal;
|
||||
|
||||
//the diffuse texture
|
||||
out vec2 varTexcoord;
|
||||
layout(location=1) out vec2 varTexcoord;
|
||||
|
||||
out vec4 varColor;
|
||||
layout(location=2) out vec4 varColor;
|
||||
|
||||
void main(void) {
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// paintStroke_fade.slf
|
||||
// paintStroke_fade.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Olivier Prat on 19/07/17.
|
||||
|
@ -18,19 +18,19 @@
|
|||
<$declareFadeFragment()$>
|
||||
|
||||
// the albedo texture
|
||||
uniform sampler2D originalTexture;
|
||||
layout(binding=0) uniform sampler2D originalTexture;
|
||||
|
||||
// the interpolated normal
|
||||
in vec3 interpolatedNormal;
|
||||
in vec2 varTexcoord;
|
||||
in vec4 varColor;
|
||||
in vec4 _worldPosition;
|
||||
layout(location=0) in vec3 interpolatedNormal;
|
||||
layout(location=1) in vec2 varTexcoord;
|
||||
layout(location=2) in vec4 varColor;
|
||||
layout(location=3) in vec4 _worldPosition;
|
||||
|
||||
struct PolyLineUniforms {
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
uniform polyLineBuffer {
|
||||
layout(binding=0) uniform polyLineBuffer {
|
||||
PolyLineUniforms polyline;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// paintStroke_fade.slv
|
||||
// paintStroke_fade.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Olivier Prat on 19/07/17.
|
||||
|
@ -18,13 +18,13 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
// the interpolated normal
|
||||
out vec3 interpolatedNormal;
|
||||
layout(location=0) out vec3 interpolatedNormal;
|
||||
|
||||
//the diffuse texture
|
||||
out vec2 varTexcoord;
|
||||
layout(location=1) out vec2 varTexcoord;
|
||||
|
||||
out vec4 varColor;
|
||||
out vec4 _worldPosition;
|
||||
layout(location=2) out vec4 varColor;
|
||||
layout(location=3) out vec4 _worldPosition;
|
||||
|
||||
void main(void) {
|
||||
|
||||
|
|
|
@ -13,15 +13,17 @@
|
|||
|
||||
<@include graphics/Material.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
<@include entities-renderer/ShaderConstants.h@>
|
||||
|
||||
in vec3 _normal;
|
||||
in vec4 _position;
|
||||
in vec4 _worldPosition;
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition;
|
||||
|
||||
uniform sampler2D xMap;
|
||||
uniform sampler2D yMap;
|
||||
uniform sampler2D zMap;
|
||||
uniform vec3 voxelVolumeSize;
|
||||
layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
|
||||
layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
|
||||
layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
|
||||
layout(location=ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE) uniform vec3 voxelVolumeSize;
|
||||
|
||||
void main(void) {
|
||||
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec4 _worldPosition;
|
||||
out vec3 _normal;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec4 _position;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _worldPosition;
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) out vec3 _normal;
|
||||
|
||||
void main(void) {
|
||||
// standard transform
|
||||
|
|
|
@ -13,18 +13,21 @@
|
|||
|
||||
<@include graphics/Material.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
<@include entities-renderer/ShaderConstants.h@>
|
||||
|
||||
<@include Fade.slh@>
|
||||
|
||||
in vec3 _normal;
|
||||
in vec4 _position;
|
||||
in vec4 _worldPosition;
|
||||
in vec4 _worldFadePosition;
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _worldFadePosition;
|
||||
|
||||
uniform sampler2D xMap;
|
||||
uniform sampler2D yMap;
|
||||
uniform sampler2D zMap;
|
||||
uniform vec3 voxelVolumeSize;
|
||||
layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap;
|
||||
layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap;
|
||||
layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap;
|
||||
|
||||
layout(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)
|
||||
<$declareFadeFragment()$>
|
||||
|
|
|
@ -12,15 +12,15 @@
|
|||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<@include render-utils/ShaderConstants.h@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec4 _worldPosition;
|
||||
out vec4 _worldFadePosition;
|
||||
out vec3 _normal;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec4 _position;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _worldPosition;
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_MS) out vec3 _normal;
|
||||
layout(location=RENDER_UTILS_ATTR_POSITION_ES) out vec4 _worldFadePosition;
|
||||
|
||||
void main(void) {
|
||||
// standard transform
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// fragment shader
|
||||
//
|
||||
// textured_particle.frag
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -9,12 +10,12 @@
|
|||
// 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;
|
||||
in vec2 varTexcoord;
|
||||
layout(location=0) in vec4 varColor;
|
||||
layout(location=1) in vec2 varTexcoord;
|
||||
|
||||
out vec4 outFragColor;
|
||||
layout(location=0) out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(colorMap, varTexcoord.xy) * varColor;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// particle vertex shader
|
||||
// texture_particle.vert
|
||||
//
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -43,15 +43,15 @@ struct ParticleUniforms {
|
|||
vec2 spare;
|
||||
};
|
||||
|
||||
layout(std140) uniform particleBuffer {
|
||||
layout(std140, binding=0) uniform particleBuffer {
|
||||
ParticleUniforms particle;
|
||||
};
|
||||
|
||||
layout(location=0) in vec3 inPosition;
|
||||
layout(location=2) in vec2 inColor; // This is actual Lifetime + Seed
|
||||
|
||||
out vec4 varColor;
|
||||
out vec2 varTexcoord;
|
||||
layout(location=0) out vec4 varColor;
|
||||
layout(location=1) out vec2 varTexcoord;
|
||||
|
||||
float bezierInterpolate(float y1, float y2, float y3, float u) {
|
||||
// https://en.wikipedia.org/wiki/Bezier_curve
|
||||
|
|
|
@ -269,7 +269,9 @@ void Context::create() {
|
|||
#if defined(USE_GLES)
|
||||
_version = 0x0200;
|
||||
#else
|
||||
if (GLAD_GL_VERSION_4_5) {
|
||||
if (gl::disableGl45()) {
|
||||
_version = 0x0401;
|
||||
} else if (GLAD_GL_VERSION_4_5) {
|
||||
_version = 0x0405;
|
||||
} else if (GLAD_GL_VERSION_4_3) {
|
||||
_version = 0x0403;
|
||||
|
|
|
@ -24,6 +24,26 @@ size_t evalGLFormatSwapchainPixelSize(const QSurfaceFormat& format) {
|
|||
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() {
|
||||
static QSurfaceFormat format;
|
||||
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.
|
||||
format.setDepthBufferSize(DEFAULT_GL_DEPTH_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);
|
||||
});
|
||||
return format;
|
||||
|
|
|
@ -26,15 +26,6 @@ class QOpenGLDebugMessage;
|
|||
class QSurfaceFormat;
|
||||
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);
|
||||
|
||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
||||
|
@ -50,6 +41,9 @@ namespace gl {
|
|||
|
||||
bool checkGLErrorDebug(const char* name);
|
||||
|
||||
bool disableGl45();
|
||||
|
||||
void getTargetVersion(int& major, int& minor);
|
||||
} // namespace gl
|
||||
|
||||
#define CHECK_GL_ERROR() ::gl::checkGLErrorDebug(__FUNCTION__)
|
||||
|
|
|
@ -13,32 +13,194 @@
|
|||
using namespace gl;
|
||||
|
||||
void Uniform::load(GLuint glprogram, int index) {
|
||||
this->index = index;
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar glname[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
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);
|
||||
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;
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||
|
||||
Uniforms result;
|
||||
result.resize(uniformsCount);
|
||||
result.reserve(uniformsCount);
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
bool gl::compileShader(GLenum shaderDomain,
|
||||
const std::string& shaderSource,
|
||||
GLuint& shaderObject,
|
||||
GLuint& programObject,
|
||||
std::string& message) {
|
||||
const std::string& shaderSource,
|
||||
GLuint& shaderObject,
|
||||
GLuint& programObject,
|
||||
std::string& message) {
|
||||
return compileShader(shaderDomain, std::vector<std::string>{ shaderSource }, shaderObject, programObject, message);
|
||||
}
|
||||
#else
|
||||
|
@ -49,15 +211,15 @@ bool gl::compileShader(GLenum shaderDomain, const std::string& shaderSource, GLu
|
|||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
bool gl::compileShader(GLenum shaderDomain,
|
||||
const std::string& shaderSource,
|
||||
GLuint& shaderObject,
|
||||
GLuint& programObject,
|
||||
std::string& message) {
|
||||
const std::string& shaderSource,
|
||||
GLuint& shaderObject,
|
||||
GLuint& programObject,
|
||||
std::string& message) {
|
||||
#else
|
||||
bool gl::compileShader(GLenum shaderDomain,
|
||||
const std::vector<std::string>& shaderSources,
|
||||
GLuint& shaderObject,
|
||||
std::string& message) {
|
||||
const std::vector<std::string>& shaderSources,
|
||||
GLuint& shaderObject,
|
||||
std::string& message) {
|
||||
#endif
|
||||
if (shaderSources.empty()) {
|
||||
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;
|
||||
glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
|
||||
|
||||
GLint infoLength = 0;
|
||||
glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
|
||||
|
||||
if ((infoLength > 0) || !compiled) {
|
||||
char* temp = new char[infoLength];
|
||||
glGetShaderInfoLog(glshader, infoLength, NULL, temp);
|
||||
|
||||
message = std::string(temp);
|
||||
|
||||
// if compilation fails
|
||||
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();
|
||||
getShaderInfoLog(glshader, message);
|
||||
// if compilation fails
|
||||
if (!compiled) {
|
||||
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);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
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
|
||||
qCWarning(glLogging) << "GLShader::compileShader - Success:";
|
||||
qCWarning(glLogging) << temp;
|
||||
delete[] temp;
|
||||
qCWarning(glLogging) << message.c_str();
|
||||
}
|
||||
|
||||
#ifdef SEPARATE_PROGRAM
|
||||
|
@ -193,7 +326,47 @@ bool gl::compileShader(GLenum shaderDomain,
|
|||
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:
|
||||
GLuint glprogram = glCreateProgram();
|
||||
if (!glprogram) {
|
||||
|
@ -201,80 +374,55 @@ GLuint gl::compileProgram(const std::vector<GLuint>& glshaders, std::string& mes
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool binaryLoaded = false;
|
||||
|
||||
if (glshaders.empty() && cachedShader) {
|
||||
glProgramBinary(glprogram, cachedShader.format, cachedShader.binary.data(), (GLsizei)cachedShader.binary.size());
|
||||
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());
|
||||
}
|
||||
// glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
|
||||
// Create the program from the sub shaders
|
||||
for (auto so : glshaders) {
|
||||
glAttachShader(glprogram, so);
|
||||
}
|
||||
|
||||
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() {
|
||||
static const QString SHADER_CACHE_FOLDER{ "shaders" };
|
||||
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";
|
||||
|
||||
void gl::loadShaderCache(ShaderCache& cache) {
|
||||
#if !defined(DISABLE_QML)
|
||||
QString shaderCacheFile = getShaderCacheFile();
|
||||
if (QFileInfo(shaderCacheFile).exists()) {
|
||||
QString json = FileUtils::readFile(shaderCacheFile);
|
||||
|
@ -302,6 +451,7 @@ void gl::loadShaderCache(ShaderCache& cache) {
|
|||
cachedShader.source = programObject[SHADER_JSON_SOURCE_KEY].toString().toStdString();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void gl::saveShaderCache(const ShaderCache& cache) {
|
||||
|
|
|
@ -12,50 +12,114 @@
|
|||
|
||||
#include "Config.h"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace gl {
|
||||
|
||||
struct Uniform {
|
||||
std::string name;
|
||||
GLint size{ -1 };
|
||||
GLenum type{ GL_FLOAT };
|
||||
GLint location{ -1 };
|
||||
void load(GLuint glprogram, int index);
|
||||
};
|
||||
struct ShaderBinding {
|
||||
int index;
|
||||
std::string name;
|
||||
GLint size{ -1 };
|
||||
GLint binding{ -1 };
|
||||
};
|
||||
|
||||
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 {
|
||||
GLenum format{ 0 };
|
||||
std::string source;
|
||||
std::vector<char> binary;
|
||||
inline operator bool() const {
|
||||
return format != 0 && !binary.empty();
|
||||
template <typename C>
|
||||
static Vector loadByName(GLuint glprogram, const C& names) {
|
||||
if (names.empty()) {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
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);
|
||||
void loadShaderCache(ShaderCache& cache);
|
||||
void saveShaderCache(const ShaderCache& cache);
|
||||
struct UniformBlock : public ShaderBinding {
|
||||
UniformBlock(){};
|
||||
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
|
||||
bool compileShader(GLenum shaderDomain, 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);
|
||||
bool compileShader(GLenum shaderDomain,
|
||||
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
|
||||
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::string& shaderSource, GLuint& shaderObject, std::string& message);
|
||||
bool compileShader(GLenum shaderDomain,
|
||||
const std::vector<std::string>& shaderSources,
|
||||
GLuint& shaderObject,
|
||||
std::string& message);
|
||||
#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
|
||||
|
|
|
@ -100,11 +100,33 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::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() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
|
||||
|
||||
QString vendor{ (const char*)glGetString(GL_VENDOR) };
|
||||
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 Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
qCDebug(gpugllogging) << "GL Vendor: " << vendor;
|
||||
|
@ -115,15 +137,26 @@ void GLBackend::init() {
|
|||
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
|
||||
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
|
||||
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)
|
||||
qCDebug(gpugllogging, "V-Sync is %s\n", (::gl::getSwapInterval() > 0 ? "ON" : "OFF"));
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
GLBackend::GLBackend(bool syncCache) {
|
||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||
initShaderBinaryCache();
|
||||
}
|
||||
|
||||
GLBackend::GLBackend() {
|
||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
|
||||
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
|
||||
// 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
|
||||
|
||||
// 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) {
|
||||
if (_pipeline._program == 0) {
|
||||
// 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();
|
||||
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 1]._int);
|
||||
glUniform1i(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 0]._int);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
@ -419,8 +447,9 @@ void GLBackend::do_glUniform1f(const Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
updatePipeline();
|
||||
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 1]._int);
|
||||
glUniform1f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
@ -432,8 +461,9 @@ void GLBackend::do_glUniform2f(const Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||
glUniform2f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
@ -446,8 +476,9 @@ void GLBackend::do_glUniform3f(const Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 3]._int);
|
||||
glUniform3f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
|
@ -461,8 +492,9 @@ void GLBackend::do_glUniform4f(const Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 4]._int);
|
||||
glUniform4f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 4]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 3]._float,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
|
@ -477,8 +509,9 @@ void GLBackend::do_glUniform3fv(const Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||
glUniform3fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 1]._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();
|
||||
|
||||
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;
|
||||
const GLfloat* value = (const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint);
|
||||
glUniform4fv(location, count, value);
|
||||
|
@ -508,8 +541,9 @@ void GLBackend::do_glUniform4iv(const Batch& batch, size_t paramOffset) {
|
|||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 2]._int);
|
||||
glUniform4iv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 1]._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();
|
||||
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 3]._int);
|
||||
glUniformMatrix3fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
batch._params[paramOffset + 1]._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();
|
||||
|
||||
GLint location = getRealUniformLocation(batch._params[paramOffset + 3]._int);
|
||||
glUniformMatrix4fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
location,
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
|
|
|
@ -68,7 +68,29 @@ protected:
|
|||
explicit GLBackend(bool syncCache);
|
||||
GLBackend();
|
||||
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();
|
||||
|
||||
|
@ -107,7 +129,6 @@ public:
|
|||
|
||||
// Texture Tables offers 2 dedicated slot (taken from the ubo slots)
|
||||
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; }
|
||||
|
||||
|
||||
|
@ -238,6 +259,7 @@ public:
|
|||
bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); }
|
||||
|
||||
protected:
|
||||
virtual GLint getRealUniformLocation(GLint location) const;
|
||||
|
||||
void recycle() const override;
|
||||
|
||||
|
@ -247,7 +269,6 @@ protected:
|
|||
|
||||
static const size_t INVALID_OFFSET = (size_t)-1;
|
||||
bool _inRenderTransferPass { false };
|
||||
int32_t _uboAlignment { 0 };
|
||||
int _currentDraw { -1 };
|
||||
|
||||
std::list<std::string> profileRanges;
|
||||
|
@ -394,10 +415,24 @@ protected:
|
|||
virtual void transferTransformState(const Batch& batch) const = 0;
|
||||
|
||||
struct UniformStageState {
|
||||
std::array<BufferPointer, MAX_NUM_UNIFORM_BUFFERS> _buffers;
|
||||
//Buffers _buffers { };
|
||||
struct BufferState {
|
||||
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;
|
||||
|
||||
// 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 resetUniformStage();
|
||||
|
||||
|
@ -410,6 +445,7 @@ protected:
|
|||
// do_setResourceTextureTable (in non-bindless mode)
|
||||
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
|
||||
void releaseResourceTexture(uint32_t slot);
|
||||
|
||||
|
@ -436,7 +472,7 @@ protected:
|
|||
PipelinePointer _pipeline;
|
||||
|
||||
GLuint _program { 0 };
|
||||
GLint _cameraCorrectionLocation { -1 };
|
||||
bool _cameraCorrection { false };
|
||||
GLShader* _programShader { nullptr };
|
||||
bool _invalidProgram { false };
|
||||
|
||||
|
@ -457,6 +493,7 @@ protected:
|
|||
} _pipeline;
|
||||
|
||||
// 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* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler);
|
||||
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 shader strings can be reliably sent to the low level `compileShader` functions
|
||||
virtual std::string getShaderSource(const Shader& shader, int version) final;
|
||||
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
||||
class ElementResource {
|
||||
public:
|
||||
gpu::Element _element;
|
||||
|
@ -475,15 +511,6 @@ protected:
|
|||
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
|
||||
};
|
||||
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
|
||||
void syncOutputStateCache();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
#include "GLBackend.h"
|
||||
#include <gpu/TextureTable.h>
|
||||
#include <gpu/ShaderConstants.h>
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLPipeline.h"
|
||||
|
@ -36,7 +37,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
|||
_pipeline._pipeline.reset();
|
||||
|
||||
_pipeline._program = 0;
|
||||
_pipeline._cameraCorrectionLocation = -1;
|
||||
_pipeline._cameraCorrection = false;
|
||||
_pipeline._programShader = nullptr;
|
||||
_pipeline._invalidProgram = true;
|
||||
|
||||
|
@ -62,7 +63,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
|||
_pipeline._program = glprogram;
|
||||
_pipeline._programShader = pipelineObject->_program;
|
||||
_pipeline._invalidProgram = true;
|
||||
_pipeline._cameraCorrectionLocation = pipelineObject->_cameraCorrection;
|
||||
_pipeline._cameraCorrection = pipelineObject->_cameraCorrection;
|
||||
}
|
||||
|
||||
// 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...
|
||||
if (_pipeline._invalidProgram) {
|
||||
glUseProgram(_pipeline._program);
|
||||
if (_pipeline._cameraCorrectionLocation != -1) {
|
||||
gl::GLBuffer* cameraCorrectionBuffer = nullptr;
|
||||
if (_transform._viewCorrectionEnabled) {
|
||||
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer);
|
||||
} else {
|
||||
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBufferIdentity._buffer);
|
||||
}
|
||||
if (_pipeline._cameraCorrection) {
|
||||
// Invalidate uniform buffer cache slot
|
||||
_uniform._buffers[_pipeline._cameraCorrectionLocation].reset();
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection));
|
||||
_uniform._buffers[gpu::slot::buffer::CameraCorrection] = {};
|
||||
auto& cameraCorrectionBuffer = _transform._viewCorrectionEnabled ?
|
||||
_pipeline._cameraCorrectionBuffer._buffer :
|
||||
_pipeline._cameraCorrectionBufferIdentity._buffer;
|
||||
bindUniformBuffer(gpu::slot::buffer::CameraCorrection, cameraCorrectionBuffer, 0, sizeof(CameraCorrection));
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
_pipeline._invalidProgram = false;
|
||||
|
@ -138,15 +136,18 @@ void GLBackend::resetPipelineStage() {
|
|||
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) {
|
||||
auto& buf = _uniform._buffers[slot];
|
||||
if (buf) {
|
||||
auto* object = Backend::getGPUObject<GLBuffer>(*buf);
|
||||
if (buf.buffer) {
|
||||
auto* object = Backend::getGPUObject<GLBuffer>(*buf.buffer);
|
||||
if (object) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
||||
(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) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
||||
BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
GLintptr rangeStart = batch._params[paramOffset + 1]._uint;
|
||||
GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint;
|
||||
|
||||
if (!uniformBuffer) {
|
||||
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;
|
||||
}
|
||||
bindUniformBuffer(slot, uniformBuffer, rangeStart, rangeSize);
|
||||
}
|
||||
|
||||
void GLBackend::releaseResourceTexture(uint32_t slot) {
|
||||
|
|
|
@ -13,7 +13,6 @@ using namespace gpu;
|
|||
using namespace gpu::gl;
|
||||
using CachedShader = ::gl::CachedShader;
|
||||
|
||||
|
||||
// Shader domain
|
||||
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");
|
||||
|
@ -178,24 +177,22 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
GLuint glprogram = 0;
|
||||
|
||||
// If we have a cached binary program, try to load it instead of compiling the individual shaders
|
||||
if (cachedBinary) {
|
||||
glprogram = ::gl::compileProgram({}, compilationLogs[version].message, cachedBinary);
|
||||
glprogram = ::gl::buildProgram(cachedBinary);
|
||||
if (0 != glprogram) {
|
||||
++gpuBinaryShadersLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
{
|
||||
} else {
|
||||
cachedBinary = CachedShader();
|
||||
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||
_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
|
||||
std::vector<GLuint> shaderGLObjects;
|
||||
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);
|
||||
if (cachedBinary) {
|
||||
glprogram = ::gl::buildProgram(shaderGLObjects);
|
||||
|
||||
if (!::gl::linkProgram(glprogram, compilationLogs[version].message)) {
|
||||
glDeleteProgram(glprogram);
|
||||
glprogram = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!cachedBinary) {
|
||||
::gl::getProgramBinary(glprogram, cachedBinary);
|
||||
cachedBinary.source = programSource;
|
||||
std::unique_lock<std::mutex> shaderCacheLock{ _shaderBinaryCache._mutex };
|
||||
_shaderBinaryCache._binaries[hash] = cachedBinary;
|
||||
|
@ -228,7 +233,7 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
|||
|
||||
compilationLogs[version].compiled = true;
|
||||
programObject.glprogram = glprogram;
|
||||
makeProgramBindings(programObject);
|
||||
postLinkProgram(programObject, program);
|
||||
}
|
||||
// Compilation feedback
|
||||
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
|
||||
GLShader* object = new GLShader(this->shared_from_this());
|
||||
object->_shaderObjects = programObjects;
|
||||
|
||||
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) {
|
||||
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_ARRAY uimage2DMSArray},
|
||||
//{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() {
|
||||
GLint numBinFormats = 0;
|
||||
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 {
|
||||
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()).");
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize,
|
||||
sizeof(CameraBufferElement));
|
||||
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, slot::buffer::Buffer::CameraTransform, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize, sizeof(CameraBufferElement));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "GLShader.h"
|
||||
#include "GLState.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
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
|
||||
// uniform will automatically have it provided without any client code necessary.
|
||||
// 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->_state = stateObject;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
GLState* _state { nullptr };
|
||||
// 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.
|
||||
int32 _cameraCorrection { -1 };
|
||||
bool _cameraCorrection{ false };
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -56,52 +56,5 @@ GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader:
|
|||
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 {
|
||||
|
||||
struct ShaderObject {
|
||||
using Uniforms = ::gl::Uniforms;
|
||||
GLuint glshader { 0 };
|
||||
GLuint glprogram { 0 };
|
||||
GLint transformCameraSlot { -1 };
|
||||
GLint transformObjectSlot { -1 };
|
||||
Uniforms uniforms;
|
||||
|
||||
using LocationMap = std::unordered_map <GLuint, GLuint>;
|
||||
LocationMap uniformRemap;
|
||||
};
|
||||
|
||||
class GLShader : public GPUObject {
|
||||
public:
|
||||
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 {
|
||||
Mono = 0,
|
||||
|
@ -44,22 +42,11 @@ public:
|
|||
~GLShader();
|
||||
|
||||
ShaderObjects _shaderObjects;
|
||||
UniformMappingVersions _uniformMappings;
|
||||
|
||||
GLuint getProgram(Version version = Mono) const {
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -129,9 +129,10 @@ void GLBackend::killTextureManagementStage() {
|
|||
}
|
||||
|
||||
std::vector<TexturePointer> GLTextureTransferEngine::getAllTextures() {
|
||||
std::remove_if(_registeredTextures.begin(), _registeredTextures.end(), [&](const std::weak_ptr<Texture>& weak) -> bool {
|
||||
return weak.expired();
|
||||
auto expiredBegin = std::remove_if(_registeredTextures.begin(), _registeredTextures.end(), [&](const std::weak_ptr<Texture>& weak) -> bool {
|
||||
return weak.expired();
|
||||
});
|
||||
_registeredTextures.erase(expiredBegin, _registeredTextures.end());
|
||||
|
||||
std::vector<TexturePointer> result;
|
||||
result.reserve(_registeredTextures.size());
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
#include <gpu/gl/GLShader.h>
|
||||
|
||||
#include "../gl41/GL41Backend.h"
|
||||
|
@ -24,9 +25,6 @@
|
|||
using namespace gpu;
|
||||
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 };
|
||||
|
||||
BackendPointer GLBackend::createBackend() {
|
||||
|
@ -34,7 +32,7 @@ BackendPointer GLBackend::createBackend() {
|
|||
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
|
||||
auto version = QOpenGLContextWrapper::currentContextVersion();
|
||||
std::shared_ptr<GLBackend> result;
|
||||
if (!disableOpenGL45 && version >= 0x0405) {
|
||||
if (!::gl::disableGl45() && version >= 0x0405) {
|
||||
qCDebug(gpugllogging) << "Using OpenGL 4.5 backend";
|
||||
result = std::make_shared<gpu::gl45::GL45Backend>();
|
||||
} else {
|
||||
|
@ -57,7 +55,3 @@ GLBackend& getBackend() {
|
|||
}
|
||||
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_43 430
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#define GPU_INPUT_PROFILE GPU_CORE_41
|
||||
#else
|
||||
#define GPU_INPUT_PROFILE GPU_CORE_43
|
||||
#endif
|
||||
|
||||
namespace gpu { namespace gl41 {
|
||||
|
||||
|
@ -35,7 +31,6 @@ class GL41Backend : public GLBackend {
|
|||
friend class Context;
|
||||
|
||||
public:
|
||||
static const GLint TRANSFORM_OBJECT_SLOT { 31 };
|
||||
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
|
||||
static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 };
|
||||
static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 };
|
||||
|
@ -172,9 +167,8 @@ protected:
|
|||
void do_blit(const Batch& batch, size_t paramOffset) 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;
|
||||
}
|
||||
|
||||
int GL41Backend::makeResourceBufferSlots(const ShaderObject& shaderProgram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) {
|
||||
GLint ssboCount = 0;
|
||||
const auto& glprogram = shaderProgram.glprogram;
|
||||
for (const auto& uniform : shaderProgram.uniforms) {
|
||||
const auto& name = uniform.name;
|
||||
const auto& type = uniform.type;
|
||||
const auto& location = uniform.location;
|
||||
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 == 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));
|
||||
}
|
||||
void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& program) const {
|
||||
Parent::postLinkProgram(programObject, program);
|
||||
const auto& glprogram = programObject.glprogram;
|
||||
// For the UBOs, use glUniformBlockBinding to fixup the locations based on the reflection
|
||||
{
|
||||
const auto expectedUbos = program.getUniformBuffers().getLocationsByName();
|
||||
auto ubos = ::gl::UniformBlock::load(glprogram);
|
||||
for (const auto& ubo : ubos) {
|
||||
const auto& name = ubo.name;
|
||||
if (0 == expectedUbos.count(name)) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||
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);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + GL41Backend::TRANSFORM_OBJECT_SLOT);
|
||||
glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
||||
if (!batch._objects.empty()) {
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer);
|
||||
|
|
|
@ -18,8 +18,26 @@ Q_LOGGING_CATEGORY(gpugl45logging, "hifi.gpu.gl45")
|
|||
using namespace gpu;
|
||||
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" };
|
||||
|
||||
GL45Backend::GL45Backend(bool syncCache) : Parent(syncCache) {
|
||||
staticInit();
|
||||
}
|
||||
|
||||
GL45Backend::GL45Backend() : Parent() {
|
||||
staticInit();
|
||||
}
|
||||
|
||||
void GL45Backend::recycle() const {
|
||||
Parent::recycle();
|
||||
}
|
||||
|
|
|
@ -33,18 +33,14 @@ class GL45Backend : public GLBackend {
|
|||
friend class Context;
|
||||
|
||||
public:
|
||||
static GLint MAX_COMBINED_SHADER_STORAGE_BLOCKS;
|
||||
static GLint MAX_UNIFORM_LOCATIONS;
|
||||
#if GPU_BINDLESS_TEXTURES
|
||||
virtual bool supportsBindless() const override { return true; }
|
||||
#endif
|
||||
|
||||
#ifdef GPU_SSBO_TRANSFORM_OBJECT
|
||||
static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot
|
||||
#else
|
||||
static const GLint TRANSFORM_OBJECT_SLOT { 31 }; // TBO binding slot
|
||||
#endif
|
||||
|
||||
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
|
||||
GL45Backend() : Parent() {}
|
||||
explicit GL45Backend(bool syncCache);
|
||||
GL45Backend();
|
||||
virtual ~GL45Backend() {
|
||||
// call resetStages here rather than in ~GLBackend dtor because it will call releaseResourceBuffer
|
||||
// which is pure virtual from GLBackend's dtor.
|
||||
|
@ -273,8 +269,6 @@ protected:
|
|||
|
||||
// Shader Stage
|
||||
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
|
||||
void initTextureManagementStage() override;
|
||||
|
|
|
@ -26,152 +26,3 @@ std::string GL45Backend::getBackendShaderHeader() const {
|
|||
);
|
||||
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
|
||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||
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
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GL45Backend::TRANSFORM_OBJECT_SLOT, _transform._objectBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot::storage::ObjectTransforms, _transform._objectBuffer);
|
||||
#else
|
||||
glActiveTexture(GL_TEXTURE0 + GL45Backend::TRANSFORM_OBJECT_SLOT);
|
||||
glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture);
|
||||
glTextureBuffer(_transform._objectBufferTexture, GL_RGBA32F, _transform._objectBuffer);
|
||||
#endif
|
||||
|
|
|
@ -50,7 +50,3 @@ GLBackend& getBackend() {
|
|||
}
|
||||
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;
|
||||
|
||||
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)
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -24,93 +24,3 @@ std::string GLESBackend::getBackendShaderHeader() const {
|
|||
)SHADER");
|
||||
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);
|
||||
glGenTextures(1, &_transform._objectBufferTexture);
|
||||
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
|
||||
while (_transform._cameraUboSize < cameraSize) {
|
||||
_transform._cameraUboSize += _uboAlignment;
|
||||
if (UNIFORM_BUFFER_OFFSET_ALIGNMENT > 0) {
|
||||
while (_transform._cameraUboSize < cameraSize) {
|
||||
_transform._cameraUboSize += UNIFORM_BUFFER_OFFSET_ALIGNMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
set(TARGET_NAME gpu)
|
||||
autoscribe_shader_lib(gpu)
|
||||
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared ktx)
|
||||
link_hifi_libraries(shared ktx shaders)
|
||||
|
||||
target_nsight()
|
||||
|
|
|
@ -24,15 +24,12 @@
|
|||
#include "Stream.h"
|
||||
#include "Texture.h"
|
||||
#include "Transform.h"
|
||||
#include "ShaderConstants.h"
|
||||
|
||||
class QDebug;
|
||||
#define BATCH_PREALLOCATE_MIN 128
|
||||
namespace gpu {
|
||||
|
||||
enum ReservedSlot {
|
||||
TRANSFORM_CAMERA_SLOT = 15,
|
||||
};
|
||||
|
||||
// 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
|
||||
// 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 setViewTransform(const Transform& view, bool camera = true);
|
||||
void setProjectionTransform(const Mat4& proj);
|
||||
void setProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
||||
// Very simple 1 level stack management of jitter.
|
||||
void pushProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
||||
void popProjectionJitter();
|
||||
void setProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
||||
// Very simple 1 level stack management of jitter.
|
||||
void pushProjectionJitter(float jx = 0.0f, float jy = 0.0f);
|
||||
void popProjectionJitter();
|
||||
// Viewport is xy = low left corner in framebuffer, zw = width height of the viewport, expressed in pixels
|
||||
void setViewportTransform(const Vec4i& viewport);
|
||||
void setDepthRangeTransform(float nearDepth, float farDepth);
|
||||
|
@ -299,9 +296,9 @@ public:
|
|||
|
||||
COMMAND_setModelTransform,
|
||||
COMMAND_setViewTransform,
|
||||
COMMAND_setProjectionTransform,
|
||||
COMMAND_setProjectionJitter,
|
||||
COMMAND_setViewportTransform,
|
||||
COMMAND_setProjectionTransform,
|
||||
COMMAND_setProjectionJitter,
|
||||
COMMAND_setViewportTransform,
|
||||
COMMAND_setDepthRangeTransform,
|
||||
|
||||
COMMAND_setPipeline,
|
||||
|
@ -504,7 +501,7 @@ public:
|
|||
|
||||
NamedBatchDataMap _namedData;
|
||||
|
||||
glm::vec2 _projectionJitter{ 0.0f, 0.0f };
|
||||
glm::vec2 _projectionJitter{ 0.0f, 0.0f };
|
||||
bool _enableStereo{ true };
|
||||
bool _enableSkybox { false };
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ void ContextStats::evalDelta(const ContextStats& begin, const ContextStats& end)
|
|||
|
||||
|
||||
Context::CreateBackend Context::_createBackendCallback = nullptr;
|
||||
Context::MakeProgram Context::_makeProgramCallback = nullptr;
|
||||
std::once_flag Context::_initialized;
|
||||
|
||||
Context::Context() {
|
||||
|
@ -139,20 +138,6 @@ void Context::executeFrame(const FramePointer& frame) const {
|
|||
_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) {
|
||||
_stereo._enable = enable;
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ public:
|
|||
static ContextMetricSize textureResourceIdealGPUMemSize;
|
||||
|
||||
protected:
|
||||
virtual bool isStereo() {
|
||||
virtual bool isStereo() const {
|
||||
return _stereo.isStereo();
|
||||
}
|
||||
|
||||
|
@ -140,14 +140,12 @@ class Context {
|
|||
public:
|
||||
using Size = Resource::Size;
|
||||
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
|
||||
template <class T>
|
||||
static void init() {
|
||||
std::call_once(_initialized, [] {
|
||||
_createBackendCallback = T::createBackend;
|
||||
_makeProgramCallback = T::makeProgram;
|
||||
T::init();
|
||||
});
|
||||
}
|
||||
|
@ -261,14 +259,7 @@ protected:
|
|||
// Sampled at the end of every frame, the stats of all the counters
|
||||
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 MakeProgram _makeProgramCallback;
|
||||
static std::once_flag _initialized;
|
||||
|
||||
friend class Shader;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawColor.frag
|
||||
//
|
||||
// Draw with color uniform
|
||||
//
|
||||
// Created by Olivier Prat on 25/10/2017
|
||||
|
@ -10,9 +12,12 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// 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) {
|
||||
outFragColor = color;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawColoredTexture.frag
|
||||
//
|
||||
// Draw texture 0 fetched at texcoord.xy, Blend with color uniform
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
||||
<@include gpu/ShaderConstants.h@>
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
uniform vec4 color;
|
||||
layout(binding=0) uniform sampler2D colorMap;
|
||||
layout(location=GPU_UNIFORM_COLOR) uniform vec4 color;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
layout(location=0) in vec2 varTexCoord0;
|
||||
layout(location=0) out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
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@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTexcoordRectTransformUnitQuad.vert
|
||||
|
||||
//
|
||||
// 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]
|
||||
|
@ -14,12 +17,13 @@
|
|||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
<@include gpu/ShaderConstants.h@>
|
||||
|
||||
<$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) {
|
||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTexture.frag
|
||||
//
|
||||
// Draw texture 0 fetched at texcoord.xy
|
||||
//
|
||||
// Created by Sam Gateau on 6/22/2015
|
||||
|
@ -12,10 +14,10 @@
|
|||
//
|
||||
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
layout(binding=0) uniform sampler2D colorMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
layout(location=0) in vec2 varTexCoord0;
|
||||
layout(location=0) out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(colorMap, varTexCoord0);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTextureMirroredX.frag
|
||||
//
|
||||
// Draw texture 0 fetched at (1.0 - texcoord.x, texcoord.y)
|
||||
//
|
||||
// Created by Sam Gondelman on 10/24/2017
|
||||
|
@ -12,10 +14,10 @@
|
|||
//
|
||||
|
||||
|
||||
uniform sampler2D colorMap;
|
||||
layout(binding=0) uniform sampler2D colorMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
layout(location=0) in vec2 varTexCoord0;
|
||||
layout(location=0) out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y));
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTextureOpaque.frag
|
||||
//
|
||||
// Draw texture 0 fetched at texcoord.xy
|
||||
// Alpha is 1
|
||||
//
|
||||
|
@ -12,11 +14,13 @@
|
|||
// 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;
|
||||
out vec4 outFragColor;
|
||||
layout(location=0) in vec2 varTexCoord0;
|
||||
|
||||
layout(location=0) out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = vec4(texture(colorMap, varTexCoord0).xyz, 1.0);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTransformUnitQuad.vert
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
@ -16,7 +18,7 @@
|
|||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec2 varTexCoord0;
|
||||
layout(location=0) out vec2 varTexCoord0;
|
||||
|
||||
void main(void) {
|
||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawTransformVertexPosition.vert
|
||||
//
|
||||
// Draw and transform the fed vertex position with the standard MVP stack
|
||||
// Output the clip position
|
||||
//
|
||||
|
@ -16,9 +18,9 @@
|
|||
|
||||
<$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) {
|
||||
// standard transform
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// 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.
|
||||
// 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.
|
||||
// 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) {
|
||||
const float depth = 1.0;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawVertexPosition.vert
|
||||
//
|
||||
// Draw the fed vertex position, pass straight as clip pos
|
||||
// Output the clip position
|
||||
//
|
||||
|
@ -12,7 +14,7 @@
|
|||
// 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) {
|
||||
gl_Position = inPosition;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// DrawViewportQuatTransformTexcoord.vert
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
@ -16,7 +18,7 @@
|
|||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec2 varTexCoord0;
|
||||
layout(location=0) out vec2 varTexCoord0;
|
||||
|
||||
void main(void) {
|
||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Draw white
|
||||
// DrawWhite.frag
|
||||
//
|
||||
// Created by Sam Gateau on 5/30/2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
|
@ -11,7 +11,7 @@
|
|||
// 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) {
|
||||
outFragColor = vec4(1.0);
|
||||
|
|
|
@ -10,15 +10,18 @@
|
|||
!>
|
||||
<@if not GPU_INPUTS_SLH@>
|
||||
<@def GPU_INPUTS_SLH@>
|
||||
layout(location = 0) in vec4 inPosition;
|
||||
layout(location = 1) in vec4 inNormal;
|
||||
layout(location = 2) in vec4 inColor;
|
||||
layout(location = 3) in vec4 inTexCoord0;
|
||||
layout(location = 4) in vec4 inTangent;
|
||||
layout(location = 5) in ivec4 inSkinClusterIndex;
|
||||
layout(location = 6) in vec4 inSkinClusterWeight;
|
||||
layout(location = 7) in vec4 inTexCoord1;
|
||||
layout(location = 8) in vec4 inTexCoord2;
|
||||
layout(location = 9) in vec4 inTexCoord3;
|
||||
layout(location = 10) in vec4 inTexCoord4;
|
||||
|
||||
<@include gpu/ShaderConstants.h@>
|
||||
|
||||
layout(location=GPU_ATTR_POSITION) in vec4 inPosition;
|
||||
layout(location=GPU_ATTR_NORMAL) in vec4 inNormal;
|
||||
layout(location=GPU_ATTR_COLOR) in vec4 inColor;
|
||||
layout(location=GPU_ATTR_TEXCOORD0) in vec4 inTexCoord0;
|
||||
layout(location=GPU_ATTR_TANGENT) in vec4 inTangent;
|
||||
layout(location=GPU_ATTR_SKIN_CLUSTER_INDEX) in ivec4 inSkinClusterIndex;
|
||||
layout(location=GPU_ATTR_SKIN_CLUSTER_WEIGHT) in vec4 inSkinClusterWeight;
|
||||
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@>
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
#include "Shader.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
#include <set>
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <shaders/Shaders.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) {
|
||||
auto found = _domainShaderMaps[type].find(source);
|
||||
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));
|
||||
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));
|
||||
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) {
|
||||
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
|
||||
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));
|
||||
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 {
|
||||
_compilationLogs.clear();
|
||||
for (const auto& log : logs) {
|
||||
|
@ -153,3 +174,124 @@ void Shader::incrementCompilationAttempt() const {
|
|||
_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 <memory>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Shader {
|
||||
|
@ -26,30 +28,71 @@ public:
|
|||
// unique identifier of a shader
|
||||
using ID = uint32_t;
|
||||
|
||||
typedef std::shared_ptr< Shader > Pointer;
|
||||
typedef std::vector< Pointer > Shaders;
|
||||
enum Type
|
||||
{
|
||||
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 {
|
||||
public:
|
||||
enum Language {
|
||||
enum Language
|
||||
{
|
||||
INVALID = -1,
|
||||
GLSL = 0,
|
||||
SPIRV = 1,
|
||||
MSL = 2,
|
||||
HLSL = 3,
|
||||
};
|
||||
|
||||
Source() {}
|
||||
Source(const std::string& code, Language lang = GLSL) : _code(code), _lang(lang) {}
|
||||
Source(const Source& source) : _code(source._code), _lang(source._lang) {}
|
||||
Source(const std::string& code, const ReflectionMap& reflection, Language lang = GLSL) :
|
||||
_code(code), _reflection(reflection), _lang(lang) {}
|
||||
Source(const Source& source) : _code(source._code), _reflection(source._reflection), _lang(source._lang) {}
|
||||
virtual ~Source() {}
|
||||
|
||||
|
||||
virtual const std::string& getCode() const { return _code; }
|
||||
virtual const ReflectionMap& getReflection() const { return _reflection; }
|
||||
|
||||
class Less {
|
||||
public:
|
||||
bool operator() (const Source& x, const Source& y) const { if (x._lang == y._lang) { return x._code < y._code; } else { return (x._lang < y._lang); } }
|
||||
bool operator()(const Source& x, const Source& y) const {
|
||||
if (x._lang == y._lang) {
|
||||
return x._code < y._code;
|
||||
} else {
|
||||
return (x._lang < y._lang);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
std::string _code;
|
||||
Language _lang = GLSL;
|
||||
ReflectionMap _reflection;
|
||||
Language _lang;
|
||||
};
|
||||
|
||||
struct CompilationLog {
|
||||
|
@ -57,30 +100,40 @@ public:
|
|||
bool compiled{ false };
|
||||
|
||||
CompilationLog() {}
|
||||
CompilationLog(const CompilationLog& src) :
|
||||
message(src.message),
|
||||
compiled(src.compiled) {}
|
||||
CompilationLog(const CompilationLog& src) : message(src.message), compiled(src.compiled) {}
|
||||
};
|
||||
using CompilationLogs = std::vector<CompilationLog>;
|
||||
|
||||
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 {
|
||||
public:
|
||||
|
||||
std::string _name;
|
||||
int32 _location{INVALID_LOCATION};
|
||||
int32 _location{ INVALID_LOCATION };
|
||||
Element _element;
|
||||
uint16 _resourceType{Resource::BUFFER};
|
||||
uint32 _size { 0 };
|
||||
|
||||
Slot(const Slot& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
||||
Slot(Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
||||
Slot(const std::string& name, int32 location, const Element& element, uint16 resourceType = Resource::BUFFER, uint32 size = 0) :
|
||||
_name(name), _location(location), _element(element), _resourceType(resourceType), _size(size) {}
|
||||
uint16 _resourceType{ Resource::BUFFER };
|
||||
uint32 _size{ 0 };
|
||||
|
||||
Slot(const Slot& s) :
|
||||
_name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
||||
Slot(Slot&& s) :
|
||||
_name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {}
|
||||
Slot(const std::string& name,
|
||||
int32 location,
|
||||
const Element& element,
|
||||
uint16 resourceType = Resource::BUFFER,
|
||||
uint32 size = 0) :
|
||||
_name(name),
|
||||
_location(location), _element(element), _resourceType(resourceType), _size(size) {}
|
||||
Slot(const std::string& name) : _name(name) {}
|
||||
|
||||
Slot& operator= (const Slot& s) {
|
||||
Slot& operator=(const Slot& s) {
|
||||
_name = s._name;
|
||||
_location = s._location;
|
||||
_element = s._element;
|
||||
|
@ -90,54 +143,62 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class Binding {
|
||||
public:
|
||||
std::string _name;
|
||||
int32 _location;
|
||||
Binding(const std::string& name, int32 loc = INVALID_LOCATION) : _name(name), _location(loc) {}
|
||||
};
|
||||
class SlotSet : protected std::set<Slot, Less<Slot>> {
|
||||
using Parent = std::set<Slot, Less<Slot>>;
|
||||
|
||||
template <typename T> class Less {
|
||||
public:
|
||||
bool operator() (const T& x, const T& y) const { return x._name < y._name; }
|
||||
};
|
||||
|
||||
class SlotSet : public std::set<Slot, Less<Slot>> {
|
||||
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);
|
||||
void insert(const Parent::value_type& value) {
|
||||
Parent::insert(value);
|
||||
if (value._location != INVALID_LOCATION) {
|
||||
_validSlots.insert(value._location);
|
||||
}
|
||||
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:
|
||||
std::unordered_set<int> _validSlots;
|
||||
};
|
||||
|
||||
typedef std::set<Binding, Less<Binding>> BindingSet;
|
||||
|
||||
|
||||
enum Type {
|
||||
VERTEX = 0,
|
||||
PIXEL,
|
||||
GEOMETRY,
|
||||
NUM_DOMAINS,
|
||||
|
||||
PROGRAM,
|
||||
};
|
||||
static Source getShaderSource(uint32_t id);
|
||||
static Source getVertexShaderSource(uint32_t id) { return getShaderSource(id); }
|
||||
static Source getFragmentShaderSource(uint32_t id) { return getShaderSource(id); }
|
||||
|
||||
static Pointer createVertex(const Source& source);
|
||||
static Pointer createPixel(const Source& source);
|
||||
static Pointer createGeometry(const Source& source);
|
||||
static Pointer createVertex(uint32_t shaderId);
|
||||
static Pointer createPixel(uint32_t shaderId);
|
||||
static Pointer createGeometry(uint32_t shaderId);
|
||||
|
||||
static Pointer createProgram(uint32_t programId);
|
||||
static Pointer createProgram(const Pointer& vertexShader, const Pointer& pixelShader);
|
||||
static Pointer createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader);
|
||||
|
||||
|
||||
~Shader();
|
||||
|
||||
ID getID() const { return _ID; }
|
||||
|
@ -156,22 +217,6 @@ public:
|
|||
const SlotSet& getResourceBuffers() const { return _resourceBuffers; }
|
||||
const SlotSet& getTextures() const { return _textures; }
|
||||
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
|
||||
// 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
|
||||
// @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
|
||||
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);
|
||||
using CompilationHandler = std::function<bool(const Shader&, const std::string&, CompilationLog&, std::string&)>;
|
||||
|
||||
// Check the compilation state
|
||||
bool compilationHasFailed() const { return _compilationHasFailed; }
|
||||
|
@ -207,16 +237,14 @@ public:
|
|||
void setCompilationLogs(const CompilationLogs& logs) const;
|
||||
void incrementCompilationAttempt() const;
|
||||
|
||||
|
||||
const GPUObjectPointer gpuObject {};
|
||||
const GPUObjectPointer gpuObject{};
|
||||
|
||||
protected:
|
||||
Shader(Type type, const Source& source);
|
||||
Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel);
|
||||
|
||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
||||
|
||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
||||
|
||||
// Source contains the actual source code or nothing if the shader is a program
|
||||
Source _source;
|
||||
|
@ -245,32 +273,29 @@ protected:
|
|||
mutable CompilationLogs _compilationLogs;
|
||||
|
||||
// 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
|
||||
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>;
|
||||
static DomainShaderMaps _domainShaderMaps;
|
||||
|
||||
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 {
|
||||
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.y == r.y) {
|
||||
return (l.z < r.z);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return (l.y < r.y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return (l.x < r.x);
|
||||
}
|
||||
}
|
||||
|
@ -278,13 +303,15 @@ protected:
|
|||
using ProgramMap = std::map<ProgramMapKey, std::weak_ptr<Shader>, ProgramKeyLess>;
|
||||
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 std::vector< ShaderPointer > Shaders;
|
||||
|
||||
};
|
||||
typedef std::vector<ShaderPointer> Shaders;
|
||||
|
||||
}; // namespace gpu
|
||||
|
||||
#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