Merge branch 'master' into M17217-b

# Conflicts:
#	plugins/openvr/src/OpenVrDisplayPlugin.cpp
This commit is contained in:
David Rowe 2018-08-08 10:43:58 +12:00
commit 96767c1103
403 changed files with 6614 additions and 5921 deletions

View file

@ -15,6 +15,7 @@ include("cmake/compiler.cmake")
if (BUILD_SCRIBE_ONLY)
add_subdirectory(tools/scribe)
add_subdirectory(tools/shader_reflect)
return()
endif()

View file

@ -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,

View file

@ -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) {

View file

@ -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
View 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")

View file

@ -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()

View file

@ -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()

View 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()

View 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)

View file

@ -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
}
]
},

View file

@ -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

View file

@ -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

View file

@ -62,6 +62,7 @@ Windows.ScrollingWindow {
url: "about:blank"
anchors.fill: parent
focus: true
profile: HFWebEngineProfile;
property string userScriptUrl: ""

View file

@ -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" },

View file

@ -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());

View file

@ -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 {

View file

@ -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());

View file

@ -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>();

View file

@ -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) &ndash;
* <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> &ndash; <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 &mdash; configured on the server &mdash; 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> &ndash;
* <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) &ndash; <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();

View file

@ -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; };

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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;
}

View file

@ -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> &ndash; <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, &ge;
* <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.";

View file

@ -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}
*/

View file

@ -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 &mdash; Web, ATP, or file. See {@link SoundObject} for supported
* formats.
* @returns {SoundObject} The sound ready for playback.
*/
Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url);
};

View file

@ -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)

View file

@ -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);
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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();

View file

@ -102,7 +102,6 @@ private:
gpu::BufferPointer indices;
uint32_t indexCount { 0 };
gpu::PipelinePointer pipeline;
int32_t uniformsLocation { -1 };
gpu::BufferPointer uniformsBuffer;

View file

@ -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);

View file

@ -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()

View file

@ -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;

View file

@ -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));

View file

@ -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);

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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

View file

@ -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;
};

View file

@ -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) {

View file

@ -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;
};

View file

@ -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) {

View file

@ -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));

View file

@ -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

View file

@ -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()$>

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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__)

View file

@ -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) {

View file

@ -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

View file

@ -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));

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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;

View file

@ -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 };
};
} }

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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());

View file

@ -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);
}

View file

@ -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;
};
} }

View file

@ -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();
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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();
}

View file

@ -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;
}
}
}

View file

@ -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()

View file

@ -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 };

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1,5 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
void main(void) { }

View file

@ -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](

View file

@ -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);

View file

@ -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));

View file

@ -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);

View file

@ -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](

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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](

View file

@ -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);

View file

@ -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@>

View file

@ -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 };
}

View file

@ -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

View 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