mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 15:13:41 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into serverless-domains
This commit is contained in:
commit
bea7ee42e2
112 changed files with 1043 additions and 6878 deletions
CMakeLists.txt
assignment-client/src/scripts
cmake
macros
templates
interface
libraries
entities-renderer/src
RenderableMaterialEntityItem.cppRenderableMaterialEntityItem.hRenderableShapeEntityItem.cppRenderableShapeEntityItem.h
gl/src/gl
gpu-gl-common
CMakeLists.txt
src/gpu/gl
GLBackend.cppGLBackend.hGLBackendInput.cppGLBackendOutput.cppGLBackendPipeline.cppGLBackendQuery.cppGLBackendShader.cppGLBackendState.cppGLBackendTexture.cppGLBackendTransform.cppGLBuffer.cppGLBuffer.hGLFramebuffer.cppGLFramebuffer.hGLInputFormat.cppGLInputFormat.hGLPipeline.cppGLPipeline.hGLQuery.hGLShader.cppGLShader.hGLShared.cppGLShared.hGLState.cppGLState.hGLTexelFormat.cppGLTexelFormat.hGLTexture.cppGLTexture.h
gpu-gl
CMakeLists.txt
src/gpu
gpu-gles
CMakeLists.txt
src/gpu
gl
GLBackend.hGLBackendOutput.cppGLBackendPipeline.cppGLBackendQuery.cppGLBackendShader.cppGLBackendState.cppGLBackendTexture.cppGLBackendTransform.cppGLBuffer.cppGLBuffer.hGLESBackend.cppGLFramebuffer.cppGLFramebuffer.hGLInputFormat.cppGLInputFormat.hGLPipeline.cppGLPipeline.hGLQuery.hGLShader.cppGLShader.hGLShared.cppGLShared.hGLState.cppGLState.hGLTexelFormat.cppGLTexelFormat.hGLTexture.cppGLTexture.h
gles
render-utils/src
|
@ -14,8 +14,12 @@ include("cmake/init.cmake")
|
|||
include("cmake/compiler.cmake")
|
||||
|
||||
if (BUILD_SCRIBE_ONLY)
|
||||
add_subdirectory(tools/scribe)
|
||||
return()
|
||||
add_subdirectory(tools/scribe)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED CLIENT_ONLY)
|
||||
set(CLIENT_ONLY 0)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED SERVER_ONLY)
|
||||
|
@ -23,59 +27,67 @@ if (NOT DEFINED SERVER_ONLY)
|
|||
endif()
|
||||
|
||||
if (ANDROID OR UWP)
|
||||
set(MOBILE 1)
|
||||
set(MOBILE 1)
|
||||
else()
|
||||
set(MOBILE 0)
|
||||
set(MOBILE 0)
|
||||
endif()
|
||||
|
||||
set(BUILD_CLIENT_OPTION ON)
|
||||
set(BUILD_SERVER_OPTION ON)
|
||||
set(BUILD_TESTS_OPTION ON)
|
||||
set(BUILD_TOOLS_OPTION ON)
|
||||
set(BUILD_INSTALLER_OPTION ON)
|
||||
set(GLES_OPTION OFF)
|
||||
set(DISABLE_QML_OPTION OFF)
|
||||
|
||||
if (ANDROID OR UWP)
|
||||
option(BUILD_SERVER "Build server components" OFF)
|
||||
option(BUILD_TOOLS "Build tools" OFF)
|
||||
option(BUILD_INSTALLER "Build installer" OFF)
|
||||
else()
|
||||
option(BUILD_SERVER "Build server components" ON)
|
||||
option(BUILD_TOOLS "Build tools" ON)
|
||||
option(BUILD_INSTALLER "Build installer" ON)
|
||||
set(BUILD_SERVER_OPTION OFF)
|
||||
set(BUILD_TOOLS_OPTION OFF)
|
||||
set(BUILD_INSTALLER OFF)
|
||||
endif()
|
||||
|
||||
if (CLIENT_ONLY)
|
||||
set(BUILD_SERVER_OPTION OFF)
|
||||
endif()
|
||||
|
||||
if (SERVER_ONLY)
|
||||
option(BUILD_CLIENT "Build client components" OFF)
|
||||
option(BUILD_TESTS "Build tests" OFF)
|
||||
else()
|
||||
option(BUILD_CLIENT "Build client components" ON)
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
set(BUILD_CLIENT_OPTION OFF)
|
||||
set(BUILD_TESTS_OPTION OFF)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
option(USE_GLES "Use OpenGL ES" ON)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
|
||||
set(GLES_OPTION ON)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras WebView)
|
||||
else ()
|
||||
option(USE_GLES "Use OpenGL ES" OFF)
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
endif ()
|
||||
|
||||
if (USE_GLES AND (NOT ANDROID))
|
||||
option(DISABLE_QML "Disable QML" ON)
|
||||
else()
|
||||
option(DISABLE_QML "Disable QML" OFF)
|
||||
set(DISABLE_QML_OPTION ON)
|
||||
endif()
|
||||
|
||||
option(BUILD_CLIENT "Build client components" ${BUILD_CLIENT_OPTION})
|
||||
option(BUILD_SERVER "Build server components" ${BUILD_SERVER_OPTION})
|
||||
option(BUILD_TESTS "Build tests" ${BUILD_TESTS_OPTION})
|
||||
option(BUILD_TOOLS "Build tools" ${BUILD_TOOLS_OPTION})
|
||||
option(BUILD_INSTALLER "Build installer" ${BUILD_INSTALLER_OPTION})
|
||||
option(USE_GLES "Use OpenGL ES" ${GLES_OPTION})
|
||||
option(DISABLE_QML "Disable QML" ${DISABLE_QML_OPTION})
|
||||
option(DISABLE_KTX_CACHE "Disable KTX Cache" OFF)
|
||||
|
||||
set(PLATFORM_QT_GL OpenGL)
|
||||
|
||||
if (USE_GLES)
|
||||
add_definitions(-DUSE_GLES)
|
||||
set(PLATFORM_GL_BACKEND gpu-gles)
|
||||
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gles)
|
||||
else()
|
||||
set(PLATFORM_GL_BACKEND gpu-gl)
|
||||
set(PLATFORM_GL_BACKEND gpu-gl-common gpu-gl)
|
||||
endif()
|
||||
|
||||
|
||||
foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS})
|
||||
list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}")
|
||||
endforeach()
|
||||
|
||||
|
||||
MESSAGE(STATUS "Build server: " ${BUILD_SERVER})
|
||||
MESSAGE(STATUS "Build client: " ${BUILD_CLIENT})
|
||||
MESSAGE(STATUS "Build tests: " ${BUILD_TESTS})
|
||||
|
@ -84,17 +96,17 @@ MESSAGE(STATUS "Build installer: " ${BUILD_INSTALLER})
|
|||
MESSAGE(STATUS "GL ES: " ${USE_GLES})
|
||||
|
||||
if (DISABLE_QML)
|
||||
MESSAGE(STATUS "QML disabled!")
|
||||
add_definitions(-DDISABLE_QML)
|
||||
MESSAGE(STATUS "QML disabled!")
|
||||
add_definitions(-DDISABLE_QML)
|
||||
endif()
|
||||
|
||||
if (DISABLE_KTX_CACHE)
|
||||
MESSAGE(STATUS "KTX cache disabled!")
|
||||
add_definitions(-DDISABLE_KTX_CACHE)
|
||||
MESSAGE(STATUS "KTX cache disabled!")
|
||||
add_definitions(-DDISABLE_KTX_CACHE)
|
||||
endif()
|
||||
|
||||
if (UNIX AND DEFINED ENV{HIFI_MEMORY_DEBUGGING})
|
||||
MESSAGE(STATUS "Memory debugging is enabled")
|
||||
MESSAGE(STATUS "Memory debugging is enabled")
|
||||
endif()
|
||||
|
||||
#
|
||||
|
@ -160,16 +172,16 @@ endif()
|
|||
add_subdirectory(tools)
|
||||
|
||||
if (BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (BUILD_INSTALLER)
|
||||
if (UNIX)
|
||||
install(
|
||||
DIRECTORY "${CMAKE_SOURCE_DIR}/scripts"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
generate_installers()
|
||||
if (UNIX)
|
||||
install(
|
||||
DIRECTORY "${CMAKE_SOURCE_DIR}/scripts"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/interface
|
||||
COMPONENT ${CLIENT_COMPONENT}
|
||||
)
|
||||
endif()
|
||||
generate_installers()
|
||||
endif()
|
||||
|
|
|
@ -476,6 +476,7 @@ void EntityScriptServer::clear() {
|
|||
// do this here (instead of in deleter) to avoid marshalling unload signals back to this thread
|
||||
_entitiesScriptEngine->unloadAllEntityScripts();
|
||||
_entitiesScriptEngine->stop();
|
||||
_entitiesScriptEngine->waitTillDoneRunning();
|
||||
}
|
||||
|
||||
_entityViewer.clear();
|
||||
|
@ -565,8 +566,15 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
|
|||
void EntityScriptServer::aboutToFinish() {
|
||||
shutdownScriptEngine();
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||
entityScriptingInterface->setEntityTree(nullptr);
|
||||
|
||||
// Should always be true as they are singletons.
|
||||
if (entityScriptingInterface->getPacketSender() == &_entityEditSender) {
|
||||
// The packet sender is about to go away.
|
||||
entityScriptingInterface->setPacketSender(nullptr);
|
||||
}
|
||||
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ macro(GENERATE_INSTALLERS)
|
|||
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
|
||||
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
|
||||
if (PR_BUILD)
|
||||
set(CPACK_NSIS_COMPRESSOR "/SOLID bzip2")
|
||||
set(CPACK_NSIS_COMPRESSOR "bzip2")
|
||||
endif ()
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME})
|
||||
|
||||
|
@ -58,6 +58,23 @@ macro(GENERATE_INSTALLERS)
|
|||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ${INTERFACE_INSTALL_DIR})
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT ${CLIENT_COMPONENT})
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
if (CLIENT_ONLY OR SERVER_ONLY)
|
||||
set(CPACK_MONOLITHIC_INSTALL 1)
|
||||
endif ()
|
||||
|
||||
# setup conditional checks for server component selection depending on
|
||||
# the inclusion of the server component at all
|
||||
if (CLIENT_ONLY)
|
||||
set(SERVER_COMPONENT_CONDITIONAL "0 == 1")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "1 == 1")
|
||||
elseif (SERVER_ONLY)
|
||||
set(SERVER_COMPONENT_CONDITIONAL "1 == 1")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "0 == 1")
|
||||
else ()
|
||||
set(SERVER_COMPONENT_CONDITIONAL "\\\${SectionIsSelected} \\\${${SERVER_COMPONENT}}")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "\\\${SectionIsSelected} \\\${${CLIENT_COMPONENT}}")
|
||||
endif ()
|
||||
elseif (APPLE)
|
||||
# produce a drag and drop DMG on OS X
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
@ -88,8 +105,13 @@ macro(GENERATE_INSTALLERS)
|
|||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
|
||||
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
|
||||
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
|
||||
if (BUILD_CLIENT)
|
||||
cpack_add_component(${CLIENT_COMPONENT} DISPLAY_NAME "High Fidelity Interface")
|
||||
endif ()
|
||||
|
||||
if (BUILD_SERVER)
|
||||
cpack_add_component(${SERVER_COMPONENT} DISPLAY_NAME "High Fidelity Sandbox")
|
||||
endif ()
|
||||
|
||||
include(CPack)
|
||||
endmacro()
|
||||
|
|
|
@ -27,6 +27,11 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
message(STATUS "The BRANCH environment variable is: $ENV{BRANCH}")
|
||||
message(STATUS "The RELEASE_TYPE variable is: ${RELEASE_TYPE}")
|
||||
|
||||
# setup component categories for installer
|
||||
set(DDE_COMPONENT dde)
|
||||
set(CLIENT_COMPONENT client)
|
||||
set(SERVER_COMPONENT server)
|
||||
|
||||
if (RELEASE_TYPE STREQUAL "PRODUCTION")
|
||||
set(DEPLOY_PACKAGE TRUE)
|
||||
set(PRODUCTION_BUILD 1)
|
||||
|
@ -153,11 +158,6 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(GA_TRACKING_ID $ENV{GA_TRACKING_ID})
|
||||
endif ()
|
||||
|
||||
# setup component categories for installer
|
||||
set(DDE_COMPONENT dde)
|
||||
set(CLIENT_COMPONENT client)
|
||||
set(SERVER_COMPONENT server)
|
||||
|
||||
# print out some results for testing this new build feature
|
||||
message(STATUS "The BUILD_GLOBAL_SERVICES variable is: ${BUILD_GLOBAL_SERVICES}")
|
||||
message(STATUS "The USE_STABLE_GLOBAL_SERVICES variable is: ${USE_STABLE_GLOBAL_SERVICES}")
|
||||
|
|
|
@ -46,3 +46,5 @@ set(CLIENT_ID_REG_KEY "@CLIENT_ID_REG_KEY@")
|
|||
set(INSTALLER_HEADER_IMAGE "@INSTALLER_HEADER_IMAGE@")
|
||||
set(UNINSTALLER_HEADER_IMAGE "@UNINSTALLER_HEADER_IMAGE@")
|
||||
set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")
|
||||
set(SERVER_COMPONENT_CONDITIONAL "@SERVER_COMPONENT_CONDITIONAL@")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "@CLIENT_COMPONENT_CONDITIONAL@")
|
||||
|
|
|
@ -437,6 +437,12 @@ SectionEnd
|
|||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageComponentsPre
|
||||
@CPACK_NSIS_PAGE_COMPONENTS@
|
||||
|
||||
; the MUI_PAGE_CUSTOMFUNCTION_PRE shouldn't be defined here
|
||||
; which can happen for a component-less (like client only) install
|
||||
!ifdef MUI_PAGE_CUSTOMFUNCTION_PRE
|
||||
!undef MUI_PAGE_CUSTOMFUNCTION_PRE
|
||||
!endif
|
||||
|
||||
Page custom PostInstallOptionsPage ReadPostInstallOptions
|
||||
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE PageInstallFilesPre
|
||||
|
@ -612,10 +618,11 @@ Function InstallTypesPage
|
|||
|
||||
${If} $CustomInstallTemporaryState == ${BST_UNCHECKED}
|
||||
${NSD_Check} $ExpressInstallRadioButton
|
||||
Call ChangeExpressLabel
|
||||
${Else}
|
||||
Call ChangeCustomLabel
|
||||
${EndIf}
|
||||
|
||||
Call ChangeExpressLabel
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
|
@ -649,7 +656,7 @@ Function PostInstallOptionsPage
|
|||
StrCpy $CurrentOffset 0
|
||||
StrCpy $OffsetUnits u
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @INTERFACE_HF_SHORTCUT_NAME@"
|
||||
Pop $DesktopClientCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -658,7 +665,7 @@ Function PostInstallOptionsPage
|
|||
!insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
|
||||
Pop $DesktopServerCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -667,7 +674,7 @@ Function PostInstallOptionsPage
|
|||
!insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install"
|
||||
Pop $LaunchServerNowCheckbox
|
||||
|
||||
|
@ -681,7 +688,7 @@ Function PostInstallOptionsPage
|
|||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
|
||||
Pop $LaunchClientNowCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 30
|
||||
|
@ -694,7 +701,7 @@ Function PostInstallOptionsPage
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
|
||||
Pop $ServerStartupCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -703,7 +710,7 @@ Function PostInstallOptionsPage
|
|||
!insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
|
||||
Pop $CleanInstallCheckbox
|
||||
IntOp $CurrentOffset $CurrentOffset + 15
|
||||
|
@ -711,11 +718,11 @@ Function PostInstallOptionsPage
|
|||
|
||||
${If} @PR_BUILD@ == 1
|
||||
; a PR build defaults all install options expect LaunchServerNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${NSD_SetState} $DesktopClientCheckbox ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED}
|
||||
${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED}
|
||||
${EndIf}
|
||||
|
@ -774,12 +781,12 @@ Function ReadInstallTypes
|
|||
FunctionEnd
|
||||
|
||||
Function ReadPostInstallOptions
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to High Fidelity
|
||||
${NSD_GetState} $DesktopClientCheckbox $DesktopClientState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to Sandbox
|
||||
${NSD_GetState} $DesktopServerCheckbox $DesktopServerState
|
||||
|
||||
|
@ -792,24 +799,24 @@ Function ReadPostInstallOptions
|
|||
${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
; check if we need to launch the server post-install
|
||||
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if we need to launch the client post-install
|
||||
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a clean install
|
||||
${NSD_GetState} $CleanInstallCheckbox $CleanInstallState
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function HandlePostInstallOptions
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to High Fidelity
|
||||
${If} $DesktopClientState == ${BST_CHECKED}
|
||||
CreateShortCut "$DESKTOP\@INTERFACE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
|
||||
|
@ -820,7 +827,7 @@ Function HandlePostInstallOptions
|
|||
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a desktop shortcut to Sandbox
|
||||
${If} $DesktopServerState == ${BST_CHECKED}
|
||||
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
|
@ -849,7 +856,7 @@ Function HandlePostInstallOptions
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
; check if the user asked for a clean install
|
||||
${If} $CleanInstallState == ${BST_CHECKED}
|
||||
SetShellVarContext current
|
||||
|
@ -886,7 +893,8 @@ Function HandlePostInstallOptions
|
|||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
${If} $LaunchServerNowState == ${BST_CHECKED}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
${AndIf} $LaunchServerNowState == ${BST_CHECKED}
|
||||
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES
|
||||
|
||||
; both launches use the explorer trick in case the user has elevated permissions for the installer
|
||||
|
@ -900,7 +908,7 @@ Function HandlePostInstallOptions
|
|||
Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"'
|
||||
${EndIf}
|
||||
|
||||
${Else}
|
||||
${ElseIf} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
!insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ NO
|
||||
|
||||
; launch uses the explorer trick in case the user has elevated permissions for the installer
|
||||
|
@ -1026,7 +1034,7 @@ Section "-Core installation"
|
|||
@CPACK_NSIS_CREATE_ICONS_EXTRA@
|
||||
|
||||
; Conditional handling for Interface specific options
|
||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${If} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@INTERFACE_SHORTCUT_NAME@.lnk" \
|
||||
"$INSTDIR\@INTERFACE_WIN_EXEC_NAME@"
|
||||
|
||||
|
@ -1041,7 +1049,7 @@ Section "-Core installation"
|
|||
${EndIf}
|
||||
|
||||
; Conditional handling for server console shortcut
|
||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
|
||||
"$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
${EndIf}
|
||||
|
@ -1185,8 +1193,8 @@ Function .onSelChange
|
|||
!insertmacro SectionList MaybeSelectionChanged
|
||||
|
||||
; if neither component is selected, disable the install button
|
||||
${IfNot} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||
${AndIfNot} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||
${IfNot} @CLIENT_COMPONENT_CONDITIONAL@
|
||||
${AndIfNot} @SERVER_COMPONENT_CONDITIONAL@
|
||||
GetDlgItem $0 $HWNDPARENT 1
|
||||
EnableWindow $0 0
|
||||
${Else}
|
||||
|
|
|
@ -26,17 +26,17 @@ generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources
|
|||
if (ANDROID)
|
||||
# on Android, don't compress the rcc binary
|
||||
add_custom_command(
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -no-compress -binary -o ${RESOURCES_RCC}
|
||||
)
|
||||
else ()
|
||||
add_custom_command(
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
|
||||
OUTPUT ${RESOURCES_RCC}
|
||||
DEPENDS ${RESOURCES_QRC} ${GENERATE_QRC_DEPENDS}
|
||||
COMMAND "${QT_DIR}/bin/rcc"
|
||||
ARGS ${RESOURCES_QRC} -binary -o ${RESOURCES_RCC}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -203,12 +203,6 @@ if (WIN32)
|
|||
add_dependency_external_projects(steamworks)
|
||||
endif()
|
||||
|
||||
# include OPENSSL
|
||||
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||
|
||||
# append OpenSSL to our list of libraries to link
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
# disable /OPT:REF and /OPT:ICF for the Debug builds
|
||||
# This will prevent the following linker warnings
|
||||
# LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification
|
||||
|
@ -232,6 +226,9 @@ link_hifi_libraries(
|
|||
# include the binary directory of render-utils for shader includes
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
|
||||
|
||||
# include OpenSSL
|
||||
target_openssl()
|
||||
|
||||
target_bullet()
|
||||
target_opengl()
|
||||
add_crashpad()
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "RenderableMaterialEntityItem.h"
|
||||
|
||||
#include "RenderPipelines.h"
|
||||
#include "GeometryCache.h"
|
||||
|
||||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
@ -90,138 +91,6 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) {
|
||||
return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi));
|
||||
}
|
||||
|
||||
glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) {
|
||||
return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi));
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) {
|
||||
buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z);
|
||||
buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z);
|
||||
buffer.push_back(uv.x); buffer.push_back(uv.y);
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::addTriangleFan(std::vector<float>& buffer, int stack, int step) {
|
||||
float v1 = ((float)stack) / STACKS;
|
||||
float theta1 = v1 * (float)M_PI;
|
||||
glm::vec3 tip = getVertexPos(0, theta1);
|
||||
float v2 = ((float)(stack + step)) / STACKS;
|
||||
float theta2 = v2 * (float)M_PI;
|
||||
for (int i = 0; i < SLICES; i++) {
|
||||
float u1 = ((float)i) / SLICES;
|
||||
float u2 = ((float)(i + step)) / SLICES;
|
||||
float phi1 = u1 * M_PI_TIMES_2;
|
||||
float phi2 = u2 * M_PI_TIMES_2;
|
||||
/* (flipped for negative step)
|
||||
p1
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
p3 ------ p2
|
||||
*/
|
||||
|
||||
glm::vec3 pos2 = getVertexPos(phi2, theta2);
|
||||
glm::vec3 pos3 = getVertexPos(phi1, theta2);
|
||||
|
||||
glm::vec3 tan1 = getTangent(0, theta1);
|
||||
glm::vec3 tan2 = getTangent(phi2, theta2);
|
||||
glm::vec3 tan3 = getTangent(phi1, theta2);
|
||||
|
||||
glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1);
|
||||
glm::vec2 uv2 = glm::vec2(u2, v2);
|
||||
glm::vec2 uv3 = glm::vec2(u1, v2);
|
||||
|
||||
addVertex(buffer, tip, tan1, uv1);
|
||||
addVertex(buffer, pos2, tan2, uv2);
|
||||
addVertex(buffer, pos3, tan3, uv3);
|
||||
|
||||
_numVertices += 3;
|
||||
}
|
||||
}
|
||||
|
||||
int MaterialEntityRenderer::_numVertices = 0;
|
||||
std::shared_ptr<gpu::Stream::Format> MaterialEntityRenderer::_streamFormat = nullptr;
|
||||
std::shared_ptr<gpu::BufferStream> MaterialEntityRenderer::_stream = nullptr;
|
||||
std::shared_ptr<gpu::Buffer> MaterialEntityRenderer::_verticesBuffer = nullptr;
|
||||
|
||||
void MaterialEntityRenderer::generateMesh() {
|
||||
_streamFormat = std::make_shared<gpu::Stream::Format>();
|
||||
_stream = std::make_shared<gpu::BufferStream>();
|
||||
_verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||
|
||||
const int NUM_POS_COORDS = 3;
|
||||
const int NUM_TANGENT_COORDS = 3;
|
||||
const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float);
|
||||
const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float);
|
||||
|
||||
_streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
_streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||
_streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET);
|
||||
_streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
|
||||
|
||||
_stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride);
|
||||
|
||||
std::vector<float> vertexBuffer;
|
||||
|
||||
// Top
|
||||
addTriangleFan(vertexBuffer, 0, 1);
|
||||
|
||||
// Middle section
|
||||
for (int j = 1; j < STACKS - 1; j++) {
|
||||
float v1 = ((float)j) / STACKS;
|
||||
float v2 = ((float)(j + 1)) / STACKS;
|
||||
float theta1 = v1 * (float)M_PI;
|
||||
float theta2 = v2 * (float)M_PI;
|
||||
for (int i = 0; i < SLICES; i++) {
|
||||
float u1 = ((float)i) / SLICES;
|
||||
float u2 = ((float)(i + 1)) / SLICES;
|
||||
float phi1 = u1 * M_PI_TIMES_2;
|
||||
float phi2 = u2 * M_PI_TIMES_2;
|
||||
|
||||
/*
|
||||
p2 ---- p3
|
||||
| / |
|
||||
| / |
|
||||
| / |
|
||||
p1 ---- p4
|
||||
*/
|
||||
|
||||
glm::vec3 pos1 = getVertexPos(phi1, theta2);
|
||||
glm::vec3 pos2 = getVertexPos(phi1, theta1);
|
||||
glm::vec3 pos3 = getVertexPos(phi2, theta1);
|
||||
glm::vec3 pos4 = getVertexPos(phi2, theta2);
|
||||
|
||||
glm::vec3 tan1 = getTangent(phi1, theta2);
|
||||
glm::vec3 tan2 = getTangent(phi1, theta1);
|
||||
glm::vec3 tan3 = getTangent(phi2, theta1);
|
||||
glm::vec3 tan4 = getTangent(phi2, theta2);
|
||||
|
||||
glm::vec2 uv1 = glm::vec2(u1, v2);
|
||||
glm::vec2 uv2 = glm::vec2(u1, v1);
|
||||
glm::vec2 uv3 = glm::vec2(u2, v1);
|
||||
glm::vec2 uv4 = glm::vec2(u2, v2);
|
||||
|
||||
addVertex(vertexBuffer, pos1, tan1, uv1);
|
||||
addVertex(vertexBuffer, pos2, tan2, uv2);
|
||||
addVertex(vertexBuffer, pos3, tan3, uv3);
|
||||
|
||||
addVertex(vertexBuffer, pos3, tan3, uv3);
|
||||
addVertex(vertexBuffer, pos4, tan4, uv4);
|
||||
addVertex(vertexBuffer, pos1, tan1, uv1);
|
||||
|
||||
_numVertices += 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom
|
||||
addTriangleFan(vertexBuffer, STACKS, -1);
|
||||
|
||||
_verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data());
|
||||
}
|
||||
|
||||
void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
|
||||
Q_ASSERT(args->_batch);
|
||||
|
@ -252,14 +121,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
|||
args->_details._materialSwitches++;
|
||||
|
||||
// Draw!
|
||||
if (_numVertices == 0) {
|
||||
generateMesh();
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(batch);
|
||||
|
||||
batch.setInputFormat(_streamFormat);
|
||||
batch.setInputStream(0, *_stream);
|
||||
batch.draw(gpu::TRIANGLES, _numVertices, 0);
|
||||
|
||||
const int NUM_VERTICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE;
|
||||
args->_details._trianglesRendered += (int)DependencyManager::get<GeometryCache>()->getSphereTriangleCount();
|
||||
}
|
||||
|
|
|
@ -40,20 +40,6 @@ private:
|
|||
Transform _renderTransform;
|
||||
|
||||
std::shared_ptr<NetworkMaterial> _drawMaterial;
|
||||
|
||||
static int _numVertices;
|
||||
static std::shared_ptr<gpu::Stream::Format> _streamFormat;
|
||||
static std::shared_ptr<gpu::BufferStream> _stream;
|
||||
static std::shared_ptr<gpu::Buffer> _verticesBuffer;
|
||||
|
||||
void generateMesh();
|
||||
void addTriangleFan(std::vector<float>& buffer, int stack, int step);
|
||||
static glm::vec3 getVertexPos(float phi, float theta);
|
||||
static glm::vec3 getTangent(float phi, float theta);
|
||||
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
|
||||
const int SLICES = 15;
|
||||
const int STACKS = 9;
|
||||
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "render-utils/simple_vert.h"
|
||||
#include "render-utils/simple_frag.h"
|
||||
|
||||
#include "RenderPipelines.h"
|
||||
|
||||
//#define SHAPE_ENTITY_USE_FADE_EFFECT
|
||||
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
|
||||
#include <FadeEffect.h>
|
||||
|
@ -108,11 +110,94 @@ bool ShapeEntityRenderer::isTransparent() const {
|
|||
if (_procedural.isEnabled() && _procedural.isFading()) {
|
||||
return Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f;
|
||||
}
|
||||
|
||||
// return _entity->getLocalRenderAlpha() < 1.0f || Parent::isTransparent();
|
||||
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end()) {
|
||||
if (mat->second.top().material) {
|
||||
auto matKey = mat->second.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::isTransparent();
|
||||
}
|
||||
|
||||
ItemKey ShapeEntityRenderer::getKey() {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape().withTypeMeta().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||
|
||||
withReadLock([&] {
|
||||
if (isTransparent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::useMaterialPipeline() const {
|
||||
bool proceduralReady = resultWithReadLock<bool>([&] {
|
||||
return _procedural.isReady();
|
||||
});
|
||||
if (proceduralReady) {
|
||||
return false;
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.top().material) {
|
||||
drawMaterialKey = mat->second.top().material->getKey();
|
||||
}
|
||||
|
||||
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the material is using any map, we need to use a material ShapeKey
|
||||
for (int i = 0; i < graphics::Material::MapChannel::NUM_MAP_CHANNELS; i++) {
|
||||
if (drawMaterialKey.isMapChannel(graphics::Material::MapChannel(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ShapeKey ShapeEntityRenderer::getShapeKey() {
|
||||
if (useMaterialPipeline()) {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_materials["0"].top().material) {
|
||||
drawMaterialKey = _materials["0"].top().material->getKey();
|
||||
}
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap();
|
||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||
bool isUnlit = drawMaterialKey.isUnlit();
|
||||
|
||||
ShapeKey::Builder builder;
|
||||
builder.withMaterial();
|
||||
|
||||
if (isTranslucent) {
|
||||
builder.withTranslucent();
|
||||
}
|
||||
if (hasTangents) {
|
||||
builder.withTangents();
|
||||
}
|
||||
if (hasLightmap) {
|
||||
builder.withLightmap();
|
||||
}
|
||||
if (isUnlit) {
|
||||
builder.withUnlit();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
} else {
|
||||
return Parent::getShapeKey();
|
||||
}
|
||||
}
|
||||
|
||||
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
||||
Q_ASSERT(args->_batch);
|
||||
|
@ -149,7 +234,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
} else {
|
||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||
}
|
||||
} else {
|
||||
} else if (!useMaterialPipeline()) {
|
||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
|
||||
|
@ -158,6 +243,11 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
} else {
|
||||
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||
}
|
||||
} else {
|
||||
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
|
||||
geometryCache->renderShape(batch, geometryShape);
|
||||
}
|
||||
|
||||
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);
|
||||
|
|
|
@ -24,6 +24,10 @@ public:
|
|||
|
||||
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
||||
|
||||
protected:
|
||||
ItemKey getKey() override;
|
||||
ShapeKey getShapeKey() override;
|
||||
|
||||
private:
|
||||
virtual bool needsRenderUpdate() const override;
|
||||
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||
|
@ -32,6 +36,8 @@ private:
|
|||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual bool isTransparent() const override;
|
||||
|
||||
bool useMaterialPipeline() const;
|
||||
|
||||
Procedural _procedural;
|
||||
QString _lastUserData;
|
||||
Transform _renderTransform;
|
||||
|
|
|
@ -70,6 +70,7 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined(USE_GLES)
|
||||
if (gl::Context::enableDebugLogger()) {
|
||||
_context->makeCurrent(_offscreenSurface);
|
||||
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
|
||||
|
@ -79,6 +80,7 @@ bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) {
|
|||
logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||
_context->doneCurrent();
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
6
libraries/gpu-gl-common/CMakeLists.txt
Normal file
6
libraries/gpu-gl-common/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
set(TARGET_NAME gpu-gl-common)
|
||||
setup_hifi_library(Concurrent)
|
||||
link_hifi_libraries(shared gl gpu)
|
||||
GroupSources("src")
|
||||
target_opengl()
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// GLBackend.cpp
|
||||
// libraries/gpu-gl-android/src/gpu/gl
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Cristian Duarte & Gabriel Calero on 9/21/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
// Created by Sam Gateau on 10/27/2014.
|
||||
// Copyright 2014 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
|
||||
|
@ -16,16 +16,11 @@
|
|||
#include <functional>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "../gles/GLESBackend.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
#endif
|
||||
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include "GLTexture.h"
|
||||
#include "GLShader.h"
|
||||
|
@ -33,39 +28,6 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
static GLBackend* INSTANCE{ nullptr };
|
||||
|
||||
BackendPointer GLBackend::createBackend() {
|
||||
// FIXME provide a mechanism to override the backend for testing
|
||||
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
|
||||
//auto version = QOpenGLContextWrapper::currentContextVersion();
|
||||
std::shared_ptr<GLBackend> result;
|
||||
|
||||
qDebug() << "Using OpenGL ES backend";
|
||||
result = std::make_shared<gpu::gles::GLESBackend>();
|
||||
|
||||
result->initInput();
|
||||
result->initTransform();
|
||||
result->initTextureManagementStage();
|
||||
|
||||
INSTANCE = result.get();
|
||||
void* voidInstance = &(*result);
|
||||
qApp->setProperty(hifi::properties::gl::BACKEND, QVariant::fromValue(voidInstance));
|
||||
return result;
|
||||
}
|
||||
|
||||
GLBackend& getBackend() {
|
||||
if (!INSTANCE) {
|
||||
INSTANCE = static_cast<GLBackend*>(qApp->property(hifi::properties::gl::BACKEND).value<void*>());
|
||||
}
|
||||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
||||
}
|
||||
|
||||
|
||||
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||
{
|
||||
(&::gpu::gl::GLBackend::do_draw),
|
||||
|
@ -151,6 +113,9 @@ void GLBackend::init() {
|
|||
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
|
||||
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
|
||||
qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
|
||||
#if !defined(USE_GLES)
|
||||
qCDebug(gpugllogging, "V-Sync is %s\n", (::gl::getSwapInterval() > 0 ? "ON" : "OFF"));
|
||||
#endif
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// This has to happen on the main thread in order to give the thread
|
||||
// pool a reasonable parent object
|
||||
|
@ -228,7 +193,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
|
|||
}
|
||||
|
||||
{ // Sync the transform buffers
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "transferGPUTransform");
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "syncGPUTransform");
|
||||
transferTransformState(batch);
|
||||
}
|
||||
|
||||
|
@ -296,7 +261,7 @@ void GLBackend::render(const Batch& batch) {
|
|||
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
if (_stereo.isStereo()) {
|
||||
glEnable(GL_CLIP_DISTANCE0_EXT);
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
|
@ -305,7 +270,7 @@ void GLBackend::render(const Batch& batch) {
|
|||
}
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
if (_stereo.isStereo()) {
|
||||
glDisable(GL_CLIP_DISTANCE0_EXT);
|
||||
glDisable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -32,9 +32,13 @@
|
|||
|
||||
// Different versions for the stereo drawcall
|
||||
// Current preferred is "instanced" which draw the shape twice but instanced and rely on clipping plane to draw left/right side only
|
||||
//#define GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
|
||||
#if defined(USE_GLES)
|
||||
#define GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
|
||||
#else
|
||||
//#define GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER
|
||||
#define GPU_STEREO_TECHNIQUE_INSTANCED
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Let these be configured by the one define picked above
|
|
@ -17,6 +17,11 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
#if defined(USE_GLES)
|
||||
#define GL_FRAMEBUFFER_SRGB GL_FRAMEBUFFER_SRGB_EXT
|
||||
#define glClearDepth glClearDepthf
|
||||
#endif
|
||||
|
||||
void GLBackend::syncOutputStateCache() {
|
||||
GLint currentFBO;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO);
|
||||
|
@ -88,7 +93,7 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
if (masks & Framebuffer::BUFFER_STENCIL) {
|
||||
glClearStencil(stencil);
|
||||
glmask |= GL_STENCIL_BUFFER_BIT;
|
||||
|
||||
|
||||
cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront();
|
||||
if (cacheStencilMask != 0xFF) {
|
||||
restoreStencilMask = true;
|
||||
|
@ -182,7 +187,11 @@ void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, co
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(USE_GLES)
|
||||
GLenum format = GL_RGBA;
|
||||
#else
|
||||
GLenum format = GL_BGRA;
|
||||
#endif
|
||||
if (destImage.format() != QImage::Format_ARGB32) {
|
||||
qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer";
|
||||
return;
|
|
@ -25,6 +25,7 @@ static bool timeElapsed = false;
|
|||
#endif
|
||||
|
||||
void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
|
@ -43,9 +44,11 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
|||
glquery->_rangeQueryDepth = _queryStage._rangeQueryDepth;
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
|
@ -66,9 +69,11 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
|||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
|
@ -90,6 +95,7 @@ void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::resetQueryStage() {
|
|
@ -14,15 +14,34 @@ using namespace gpu::gl;
|
|||
|
||||
// GLSL version
|
||||
std::string GLBackend::getBackendShaderHeader() const {
|
||||
return std::string("#version 410 core");
|
||||
|
||||
#if defined(USE_GLES)
|
||||
static const std::string header(
|
||||
R"SHADER(
|
||||
#version 310 es
|
||||
#extension GL_EXT_texture_buffer : enable
|
||||
precision lowp float; // check precision 2
|
||||
precision lowp samplerBuffer;
|
||||
precision lowp sampler2DShadow;
|
||||
)SHADER");
|
||||
#else
|
||||
static const std::string header(
|
||||
R"SHADER(
|
||||
#version 410 core
|
||||
)SHADER");
|
||||
#endif
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
// 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");
|
||||
|
||||
// GL Shader type enums
|
||||
// Must match the order of type specified in gpu::Shader::Type
|
||||
static const std::array<GLenum, NUM_SHADER_DOMAINS> SHADER_DOMAINS { {
|
||||
static const std::array<GLenum, NUM_SHADER_DOMAINS> SHADER_DOMAINS{ {
|
||||
GL_VERTEX_SHADER,
|
||||
GL_FRAGMENT_SHADER,
|
||||
GL_GEOMETRY_SHADER,
|
||||
|
@ -30,22 +49,33 @@ static const std::array<GLenum, NUM_SHADER_DOMAINS> SHADER_DOMAINS { {
|
|||
|
||||
// Domain specific defines
|
||||
// Must match the order of type specified in gpu::Shader::Type
|
||||
static const std::array<std::string, NUM_SHADER_DOMAINS> DOMAIN_DEFINES { {
|
||||
static const std::array<std::string, NUM_SHADER_DOMAINS> DOMAIN_DEFINES{ {
|
||||
"#define GPU_VERTEX_SHADER",
|
||||
"#define GPU_PIXEL_SHADER",
|
||||
"#define GPU_GEOMETRY_SHADER",
|
||||
} };
|
||||
|
||||
// Stereo specific defines
|
||||
static const std::string stereoVersion {
|
||||
static const std::string stereoVersion{
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
"#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED\n#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN"
|
||||
R"SHADER(
|
||||
#define GPU_TRANSFORM_IS_STEREO
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED
|
||||
#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN
|
||||
)SHADER"
|
||||
#endif
|
||||
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
"#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED"
|
||||
R"SHADER(
|
||||
#define GPU_TRANSFORM_IS_STEREO
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA
|
||||
#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED
|
||||
)SHADER"
|
||||
#else
|
||||
"#define GPU_TRANSFORM_IS_STEREO"
|
||||
R"SHADER(
|
||||
#define GPU_TRANSFORM_IS_STEREO
|
||||
)SHADER"
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
@ -67,7 +97,10 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
|
|||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& shaderObject = shaderObjects[version];
|
||||
|
||||
std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version];
|
||||
std::string shaderDefines = getBackendShaderHeader() + "\n"
|
||||
+ DOMAIN_DEFINES[shader.getType()] + "\n"
|
||||
+ VERSION_DEFINES[version];
|
||||
|
||||
if (handler) {
|
||||
bool retest = true;
|
||||
std::string currentSrc = shaderSource;
|
||||
|
@ -154,149 +187,173 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
|
|||
return object;
|
||||
}
|
||||
|
||||
|
||||
GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) {
|
||||
switch (gltype) {
|
||||
case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
/*
|
||||
case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
*/
|
||||
case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_UNSIGNED_INT:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_BOOL:
|
||||
return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_FLOAT_MAT2:
|
||||
return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT3:
|
||||
return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT4:
|
||||
return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_SAMPLER_2D:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_3D:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_SAMPLER_CUBE:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_BUFFER:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, RESOURCE_BUFFER), Resource::BUFFER);
|
||||
case GL_INT_SAMPLER_2D:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_3D:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_INT_SAMPLER_CUBE:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
case GL_INT_SAMPLER_2D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
#if !defined(USE_GLES)
|
||||
case GL_SAMPLER_1D:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_INT_SAMPLER_1D:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_INT_SAMPLER_1D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
#endif
|
||||
|
||||
case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
|
||||
|
||||
case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
/* {GL_FLOAT_MAT2x3 mat2x3},
|
||||
{GL_FLOAT_MAT2x4 mat2x4},
|
||||
{GL_FLOAT_MAT3x2 mat3x2},
|
||||
{GL_FLOAT_MAT3x4 mat3x4},
|
||||
{GL_FLOAT_MAT4x2 mat4x2},
|
||||
{GL_FLOAT_MAT4x3 mat4x3},
|
||||
{GL_DOUBLE_MAT2 dmat2},
|
||||
{GL_DOUBLE_MAT3 dmat3},
|
||||
{GL_DOUBLE_MAT4 dmat4},
|
||||
{GL_DOUBLE_MAT2x3 dmat2x3},
|
||||
{GL_DOUBLE_MAT2x4 dmat2x4},
|
||||
{GL_DOUBLE_MAT3x2 dmat3x2},
|
||||
{GL_DOUBLE_MAT3x4 dmat3x4},
|
||||
{GL_DOUBLE_MAT4x2 dmat4x2},
|
||||
{GL_DOUBLE_MAT4x3 dmat4x3},
|
||||
*/
|
||||
|
||||
case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
|
||||
|
||||
case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
|
||||
case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
|
||||
// {GL_SAMPLER_1D_SHADOW sampler1DShadow},
|
||||
// {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
|
||||
|
||||
case GL_SAMPLER_BUFFER: return ElementResource(Element(SCALAR, gpu::FLOAT, RESOURCE_BUFFER), Resource::BUFFER);
|
||||
|
||||
// {GL_SAMPLER_2D_RECT sampler2DRect},
|
||||
// {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
// {GL_INT_SAMPLER_BUFFER isamplerBuffer},
|
||||
// {GL_INT_SAMPLER_2D_RECT isampler2DRect},
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
#endif
|
||||
// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
|
||||
// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
|
||||
/*
|
||||
{GL_IMAGE_1D image1D},
|
||||
{GL_IMAGE_2D image2D},
|
||||
{GL_IMAGE_3D image3D},
|
||||
{GL_IMAGE_2D_RECT image2DRect},
|
||||
{GL_IMAGE_CUBE imageCube},
|
||||
{GL_IMAGE_BUFFER imageBuffer},
|
||||
{GL_IMAGE_1D_ARRAY image1DArray},
|
||||
{GL_IMAGE_2D_ARRAY image2DArray},
|
||||
{GL_IMAGE_2D_MULTISAMPLE image2DMS},
|
||||
{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
|
||||
{GL_INT_IMAGE_1D iimage1D},
|
||||
{GL_INT_IMAGE_2D iimage2D},
|
||||
{GL_INT_IMAGE_3D iimage3D},
|
||||
{GL_INT_IMAGE_2D_RECT iimage2DRect},
|
||||
{GL_INT_IMAGE_CUBE iimageCube},
|
||||
{GL_INT_IMAGE_BUFFER iimageBuffer},
|
||||
{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
|
||||
{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
|
||||
{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
|
||||
{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
|
||||
{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
|
||||
{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot
|
||||
|
||||
{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
|
||||
{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
||||
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
||||
{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
||||
*/
|
||||
default:
|
||||
return ElementResource(Element(), Resource::BUFFER);
|
||||
}
|
||||
|
||||
// Non-covered types
|
||||
//{GL_FLOAT_MAT2x3 mat2x3},
|
||||
//{GL_FLOAT_MAT2x4 mat2x4},
|
||||
//{GL_FLOAT_MAT3x2 mat3x2},
|
||||
//{GL_FLOAT_MAT3x4 mat3x4},
|
||||
//{GL_FLOAT_MAT4x2 mat4x2},
|
||||
//{GL_FLOAT_MAT4x3 mat4x3},
|
||||
//{GL_DOUBLE_MAT2 dmat2},
|
||||
//{GL_DOUBLE_MAT3 dmat3},
|
||||
//{GL_DOUBLE_MAT4 dmat4},
|
||||
//{GL_DOUBLE_MAT2x3 dmat2x3},
|
||||
//{GL_DOUBLE_MAT2x4 dmat2x4},
|
||||
//{GL_DOUBLE_MAT3x2 dmat3x2},
|
||||
//{GL_DOUBLE_MAT3x4 dmat3x4},
|
||||
//{GL_DOUBLE_MAT4x2 dmat4x2},
|
||||
//{GL_DOUBLE_MAT4x3 dmat4x3},
|
||||
//{GL_SAMPLER_1D_SHADOW sampler1DShadow},
|
||||
//{GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
|
||||
//{GL_SAMPLER_2D_RECT sampler2DRect},
|
||||
//{GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
|
||||
//{GL_INT_SAMPLER_BUFFER isamplerBuffer},
|
||||
//{GL_INT_SAMPLER_2D_RECT isampler2DRect},
|
||||
//{GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
|
||||
//{GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
|
||||
//{GL_IMAGE_1D image1D},
|
||||
//{GL_IMAGE_2D image2D},
|
||||
//{GL_IMAGE_3D image3D},
|
||||
//{GL_IMAGE_2D_RECT image2DRect},
|
||||
//{GL_IMAGE_CUBE imageCube},
|
||||
//{GL_IMAGE_BUFFER imageBuffer},
|
||||
//{GL_IMAGE_1D_ARRAY image1DArray},
|
||||
//{GL_IMAGE_2D_ARRAY image2DArray},
|
||||
//{GL_IMAGE_2D_MULTISAMPLE image2DMS},
|
||||
//{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
|
||||
//{GL_INT_IMAGE_1D iimage1D},
|
||||
//{GL_INT_IMAGE_2D iimage2D},
|
||||
//{GL_INT_IMAGE_3D iimage3D},
|
||||
//{GL_INT_IMAGE_2D_RECT iimage2DRect},
|
||||
//{GL_INT_IMAGE_CUBE iimageCube},
|
||||
//{GL_INT_IMAGE_BUFFER iimageBuffer},
|
||||
//{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
|
||||
//{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
|
||||
//{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
|
||||
//{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
|
||||
//{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
|
||||
//{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
|
||||
//{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},
|
||||
//{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
|
||||
//{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
|
||||
//{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(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
||||
|
@ -550,4 +607,3 @@ void GLBackend::makeProgramBindings(ShaderObject& shaderObject) {
|
|||
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
||||
}
|
||||
}
|
||||
|
|
@ -29,18 +29,19 @@ void GLBackend::resetPipelineState(State::Signature nextSignature) {
|
|||
}
|
||||
}
|
||||
|
||||
// Default line width accross the board
|
||||
glLineWidth(1.0f);
|
||||
#if !defined(USE_GLES)
|
||||
// force a few states regardless
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
// Point size is always on
|
||||
// FIXME CORE
|
||||
//glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE_EXT);
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
// Default line width accross the board
|
||||
glLineWidth(1.0f);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -48,17 +49,19 @@ void GLBackend::syncPipelineStateCache() {
|
|||
State::Data state;
|
||||
|
||||
// force a few states regardless
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
// Point size is always on
|
||||
// FIXME CORE
|
||||
//glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE_EXT);
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
// Default line width accross the board
|
||||
glLineWidth(1.0f);
|
||||
|
||||
#if !defined(USE_GLES)
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
// Point size is always on
|
||||
//glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE_EXT);
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
#endif
|
||||
|
||||
getCurrentGLState(state);
|
||||
State::Signature signature = State::evalSignature(state);
|
||||
|
@ -70,11 +73,13 @@ void GLBackend::syncPipelineStateCache() {
|
|||
|
||||
void GLBackend::do_setStateFillMode(int32 mode) {
|
||||
if (_pipeline._stateCache.fillMode != mode) {
|
||||
#if !defined(USE_GLES)
|
||||
static GLenum GL_FILL_MODES[] = { GL_POINT, GL_LINE, GL_FILL };
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.fillMode = State::FillMode(mode);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,14 +111,15 @@ void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) {
|
|||
|
||||
void GLBackend::do_setStateDepthClampEnable(bool enable) {
|
||||
if (_pipeline._stateCache.depthClampEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
} else {
|
||||
glDisable(GL_DEPTH_CLAMP);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.depthClampEnable = enable;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +138,7 @@ void GLBackend::do_setStateScissorEnable(bool enable) {
|
|||
|
||||
void GLBackend::do_setStateMultisampleEnable(bool enable) {
|
||||
if (_pipeline._stateCache.multisampleEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
} else {
|
||||
|
@ -140,11 +147,13 @@ void GLBackend::do_setStateMultisampleEnable(bool enable) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.multisampleEnable = enable;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
|
||||
if (_pipeline._stateCache.antialisedLineEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
} else {
|
||||
|
@ -153,6 +162,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.antialisedLineEnable = enable;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,13 +170,17 @@ void GLBackend::do_setStateDepthBias(Vec2 bias) {
|
|||
if ((bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) {
|
||||
if ((bias.x != 0.0f) || (bias.y != 0.0f)) {
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
#if !defined(USE_GLES)
|
||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
glEnable(GL_POLYGON_OFFSET_POINT);
|
||||
#endif
|
||||
glPolygonOffset(bias.x, bias.y);
|
||||
} else {
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
#if !defined(USE_GLES)
|
||||
glDisable(GL_POLYGON_OFFSET_LINE);
|
||||
glDisable(GL_POLYGON_OFFSET_POINT);
|
||||
#endif
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
|
@ -33,14 +33,18 @@ bool GLFramebuffer::checkStatus() const {
|
|||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
|
||||
break;
|
||||
#if !defined(USE_GLES)
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
|
@ -24,6 +24,7 @@ namespace gpu { namespace gl {
|
|||
|
||||
gpu::Size getFreeDedicatedMemory() {
|
||||
Size result { 0 };
|
||||
#if !defined(USE_GLES)
|
||||
static bool nvidiaMemorySupported { true };
|
||||
static bool atiMemorySupported { true };
|
||||
if (nvidiaMemorySupported) {
|
||||
|
@ -45,6 +46,7 @@ gpu::Size getFreeDedicatedMemory() {
|
|||
atiMemorySupported = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -144,6 +146,9 @@ State::BlendArg blendArgFromGL(GLenum blendArg) {
|
|||
|
||||
void getCurrentGLState(State::Data& state) {
|
||||
{
|
||||
#if defined(USE_GLES)
|
||||
state.fillMode = State::FILL_FACE;
|
||||
#else
|
||||
GLint modes[2];
|
||||
glGetIntegerv(GL_POLYGON_MODE, modes);
|
||||
if (modes[0] == GL_FILL) {
|
||||
|
@ -155,6 +160,7 @@ void getCurrentGLState(State::Data& state) {
|
|||
state.fillMode = State::FILL_POINT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
{
|
||||
if (glIsEnabled(GL_CULL_FACE)) {
|
||||
|
@ -169,10 +175,16 @@ void getCurrentGLState(State::Data& state) {
|
|||
GLint winding;
|
||||
glGetIntegerv(GL_FRONT_FACE, &winding);
|
||||
state.frontFaceClockwise = (winding == GL_CW);
|
||||
state.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
|
||||
state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
|
||||
#if defined(USE_GLES)
|
||||
state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE_EXT);
|
||||
state.antialisedLineEnable = false;
|
||||
state.depthClampEnable = false;
|
||||
#else
|
||||
state.multisampleEnable = glIsEnabled(GL_MULTISAMPLE);
|
||||
state.antialisedLineEnable = glIsEnabled(GL_LINE_SMOOTH);
|
||||
state.depthClampEnable = glIsEnabled(GL_DEPTH_CLAMP);
|
||||
#endif
|
||||
state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
|
||||
}
|
||||
{
|
||||
if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) {
|
||||
|
@ -269,6 +281,7 @@ void getCurrentGLState(State::Data& state) {
|
|||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void serverWait() {
|
||||
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
assert(fence);
|
|
@ -11,15 +11,81 @@
|
|||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
#if defined(USE_GLES)
|
||||
// Missing GL formats
|
||||
#define GL_R16 GL_R16_EXT
|
||||
#define GL_R16_SNORM GL_R16_SNORM_EXT
|
||||
#define GL_RG16 GL_RG16_EXT
|
||||
#define GL_RG16_SNORM GL_RG16_SNORM_EXT
|
||||
#define GL_RGBA2 GL_RGBA8
|
||||
#define GL_RGBA16 GL_RGBA16_EXT
|
||||
#define GL_RGBA16_SNORM GL_RGBA16_SNORM_EXT
|
||||
#define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES
|
||||
#define GL_SLUMINANCE8_EXT GL_SLUMINANCE8_NV
|
||||
// Missing GL compressed formats
|
||||
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
|
||||
#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
|
||||
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
|
||||
#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
|
||||
#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
|
||||
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
|
||||
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
|
||||
#endif
|
||||
|
||||
bool GLTexelFormat::isCompressed() const {
|
||||
switch (internalFormat) {
|
||||
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
|
||||
|
||||
case GL_COMPRESSED_R11_EAC:
|
||||
case GL_COMPRESSED_SIGNED_R11_EAC:
|
||||
case GL_COMPRESSED_RG11_EAC:
|
||||
case GL_COMPRESSED_SIGNED_RG11_EAC:
|
||||
case GL_COMPRESSED_RGB8_ETC2:
|
||||
case GL_COMPRESSED_SRGB8_ETC2:
|
||||
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||
case GL_COMPRESSED_RGBA8_ETC2_EAC:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
|
||||
case GL_COMPRESSED_RED_RGTC1:
|
||||
case GL_COMPRESSED_RG_RGTC2:
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
|
||||
|
||||
#if defined(USE_GLES)
|
||||
case GL_COMPRESSED_RGBA_ASTC_4x4:
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x4:
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x6:
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x6:
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x8:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x6:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x8:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x10:
|
||||
case GL_COMPRESSED_RGBA_ASTC_12x10:
|
||||
case GL_COMPRESSED_RGBA_ASTC_12x12:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12:
|
||||
#endif
|
||||
|
||||
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -390,7 +456,11 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
switch (srcFormat.getSemantic()) {
|
||||
case gpu::BGRA:
|
||||
case gpu::SBGRA:
|
||||
#if defined(USE_GLES)
|
||||
texel.format = GL_RGBA;
|
||||
#else
|
||||
texel.format = GL_BGRA;
|
||||
#endif
|
||||
break;
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
|
@ -427,8 +497,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
switch (srcFormat.getSemantic()) {
|
||||
case gpu::BGRA:
|
||||
case gpu::SBGRA:
|
||||
#if !defined(USE_GLES)
|
||||
texel.format = GL_BGRA;
|
||||
break;
|
||||
#endif
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
|
@ -478,6 +550,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
|
||||
case gpu::RED:
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
|
@ -788,8 +861,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
|||
switch (srcFormat.getSemantic()) {
|
||||
case gpu::BGRA:
|
||||
case gpu::SBGRA:
|
||||
#if !defined(USE_GLES)
|
||||
texel.format = GL_BGRA;
|
||||
break;
|
||||
#endif
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
|
@ -1,6 +1,6 @@
|
|||
set(TARGET_NAME gpu-gl)
|
||||
setup_hifi_library(Concurrent)
|
||||
link_hifi_libraries(shared gl gpu)
|
||||
link_hifi_libraries(shared gl gpu gpu-gl-common)
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} pthread)
|
||||
endif(UNIX)
|
||||
|
|
|
@ -1,772 +0,0 @@
|
|||
//
|
||||
// GLBackend.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 10/27/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "../gl41/GL41Backend.h"
|
||||
#include "../gl45/GL45Backend.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
#endif
|
||||
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include "GLTexture.h"
|
||||
#include "GLShader.h"
|
||||
|
||||
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() {
|
||||
// FIXME provide a mechanism to override the backend for testing
|
||||
// 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) {
|
||||
qCDebug(gpugllogging) << "Using OpenGL 4.5 backend";
|
||||
result = std::make_shared<gpu::gl45::GL45Backend>();
|
||||
} else {
|
||||
qCDebug(gpugllogging) << "Using OpenGL 4.1 backend";
|
||||
result = std::make_shared<gpu::gl41::GL41Backend>();
|
||||
}
|
||||
result->initInput();
|
||||
result->initTransform();
|
||||
result->initTextureManagementStage();
|
||||
|
||||
INSTANCE = result.get();
|
||||
void* voidInstance = &(*result);
|
||||
qApp->setProperty(hifi::properties::gl::BACKEND, QVariant::fromValue(voidInstance));
|
||||
return result;
|
||||
}
|
||||
|
||||
GLBackend& getBackend() {
|
||||
if (!INSTANCE) {
|
||||
INSTANCE = static_cast<GLBackend*>(qApp->property(hifi::properties::gl::BACKEND).value<void*>());
|
||||
}
|
||||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
||||
}
|
||||
|
||||
GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
||||
{
|
||||
(&::gpu::gl::GLBackend::do_draw),
|
||||
(&::gpu::gl::GLBackend::do_drawIndexed),
|
||||
(&::gpu::gl::GLBackend::do_drawInstanced),
|
||||
(&::gpu::gl::GLBackend::do_drawIndexedInstanced),
|
||||
(&::gpu::gl::GLBackend::do_multiDrawIndirect),
|
||||
(&::gpu::gl::GLBackend::do_multiDrawIndexedIndirect),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_setInputFormat),
|
||||
(&::gpu::gl::GLBackend::do_setInputBuffer),
|
||||
(&::gpu::gl::GLBackend::do_setIndexBuffer),
|
||||
(&::gpu::gl::GLBackend::do_setIndirectBuffer),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_setModelTransform),
|
||||
(&::gpu::gl::GLBackend::do_setViewTransform),
|
||||
(&::gpu::gl::GLBackend::do_setProjectionTransform),
|
||||
(&::gpu::gl::GLBackend::do_setViewportTransform),
|
||||
(&::gpu::gl::GLBackend::do_setDepthRangeTransform),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_setPipeline),
|
||||
(&::gpu::gl::GLBackend::do_setStateBlendFactor),
|
||||
(&::gpu::gl::GLBackend::do_setStateScissorRect),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_setUniformBuffer),
|
||||
(&::gpu::gl::GLBackend::do_setResourceBuffer),
|
||||
(&::gpu::gl::GLBackend::do_setResourceTexture),
|
||||
(&::gpu::gl::GLBackend::do_setResourceFramebufferSwapChainTexture),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_setFramebuffer),
|
||||
(&::gpu::gl::GLBackend::do_setFramebufferSwapChain),
|
||||
(&::gpu::gl::GLBackend::do_clearFramebuffer),
|
||||
(&::gpu::gl::GLBackend::do_blit),
|
||||
(&::gpu::gl::GLBackend::do_generateTextureMips),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_advance),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_beginQuery),
|
||||
(&::gpu::gl::GLBackend::do_endQuery),
|
||||
(&::gpu::gl::GLBackend::do_getQuery),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_resetStages),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_disableContextViewCorrection),
|
||||
(&::gpu::gl::GLBackend::do_restoreContextViewCorrection),
|
||||
(&::gpu::gl::GLBackend::do_disableContextStereo),
|
||||
(&::gpu::gl::GLBackend::do_restoreContextStereo),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_runLambda),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_startNamedCall),
|
||||
(&::gpu::gl::GLBackend::do_stopNamedCall),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_glUniform1i),
|
||||
(&::gpu::gl::GLBackend::do_glUniform1f),
|
||||
(&::gpu::gl::GLBackend::do_glUniform2f),
|
||||
(&::gpu::gl::GLBackend::do_glUniform3f),
|
||||
(&::gpu::gl::GLBackend::do_glUniform4f),
|
||||
(&::gpu::gl::GLBackend::do_glUniform3fv),
|
||||
(&::gpu::gl::GLBackend::do_glUniform4fv),
|
||||
(&::gpu::gl::GLBackend::do_glUniform4iv),
|
||||
(&::gpu::gl::GLBackend::do_glUniformMatrix3fv),
|
||||
(&::gpu::gl::GLBackend::do_glUniformMatrix4fv),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_glColor4f),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_pushProfileRange),
|
||||
(&::gpu::gl::GLBackend::do_popProfileRange),
|
||||
};
|
||||
|
||||
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) };
|
||||
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;
|
||||
qCDebug(gpugllogging) << "GL Renderer: " << renderer;
|
||||
GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer);
|
||||
// From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers.
|
||||
qCDebug(gpugllogging) << "GPU:";
|
||||
qCDebug(gpugllogging) << "\tcard:" << gpu->getName();
|
||||
qCDebug(gpugllogging) << "\tdriver:" << gpu->getDriver();
|
||||
qCDebug(gpugllogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
|
||||
qCDebug(gpugllogging, "V-Sync is %s\n", (::gl::getSwapInterval() > 0 ? "ON" : "OFF"));
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// This has to happen on the main thread in order to give the thread
|
||||
// pool a reasonable parent object
|
||||
GLVariableAllocationSupport::TransferJob::startBufferingThread();
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
GLBackend::GLBackend() {
|
||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uboAlignment);
|
||||
}
|
||||
|
||||
|
||||
GLBackend::~GLBackend() {
|
||||
killInput();
|
||||
killTransform();
|
||||
}
|
||||
|
||||
void GLBackend::renderPassTransfer(const Batch& batch) {
|
||||
const size_t numCommands = batch.getCommands().size();
|
||||
const Batch::Commands::value_type* command = batch.getCommands().data();
|
||||
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
|
||||
|
||||
_inRenderTransferPass = true;
|
||||
{ // Sync all the buffers
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "syncGPUBuffer");
|
||||
|
||||
for (auto& cached : batch._buffers._items) {
|
||||
if (cached._data) {
|
||||
syncGPUObject(*cached._data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Sync all the transform states
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "syncCPUTransform");
|
||||
_transform._cameras.clear();
|
||||
_transform._cameraOffsets.clear();
|
||||
|
||||
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
|
||||
switch (*command) {
|
||||
case Batch::COMMAND_draw:
|
||||
case Batch::COMMAND_drawIndexed:
|
||||
case Batch::COMMAND_drawInstanced:
|
||||
case Batch::COMMAND_drawIndexedInstanced:
|
||||
case Batch::COMMAND_multiDrawIndirect:
|
||||
case Batch::COMMAND_multiDrawIndexedIndirect:
|
||||
_transform.preUpdate(_commandIndex, _stereo);
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_disableContextStereo:
|
||||
_stereo._contextDisable = true;
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_restoreContextStereo:
|
||||
_stereo._contextDisable = false;
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_setViewportTransform:
|
||||
case Batch::COMMAND_setViewTransform:
|
||||
case Batch::COMMAND_setProjectionTransform: {
|
||||
CommandCall call = _commandCalls[(*command)];
|
||||
(this->*(call))(batch, *offset);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
command++;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
{ // Sync the transform buffers
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "syncGPUTransform");
|
||||
transferTransformState(batch);
|
||||
}
|
||||
|
||||
_inRenderTransferPass = false;
|
||||
}
|
||||
|
||||
void GLBackend::renderPassDraw(const Batch& batch) {
|
||||
_currentDraw = -1;
|
||||
_transform._camerasItr = _transform._cameraOffsets.begin();
|
||||
const size_t numCommands = batch.getCommands().size();
|
||||
const Batch::Commands::value_type* command = batch.getCommands().data();
|
||||
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
|
||||
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
|
||||
switch (*command) {
|
||||
// Ignore these commands on this pass, taken care of in the transfer pass
|
||||
// Note we allow COMMAND_setViewportTransform to occur in both passes
|
||||
// as it both updates the transform object (and thus the uniforms in the
|
||||
// UBO) as well as executes the actual viewport call
|
||||
case Batch::COMMAND_setModelTransform:
|
||||
case Batch::COMMAND_setViewTransform:
|
||||
case Batch::COMMAND_setProjectionTransform:
|
||||
break;
|
||||
|
||||
case Batch::COMMAND_draw:
|
||||
case Batch::COMMAND_drawIndexed:
|
||||
case Batch::COMMAND_drawInstanced:
|
||||
case Batch::COMMAND_drawIndexedInstanced:
|
||||
case Batch::COMMAND_multiDrawIndirect:
|
||||
case Batch::COMMAND_multiDrawIndexedIndirect: {
|
||||
// updates for draw calls
|
||||
++_currentDraw;
|
||||
updateInput();
|
||||
updateTransform(batch);
|
||||
updatePipeline();
|
||||
|
||||
CommandCall call = _commandCalls[(*command)];
|
||||
(this->*(call))(batch, *offset);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
CommandCall call = _commandCalls[(*command)];
|
||||
(this->*(call))(batch, *offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
command++;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::render(const Batch& batch) {
|
||||
_transform._skybox = _stereo._skybox = batch.isSkyboxEnabled();
|
||||
// Allow the batch to override the rendering stereo settings
|
||||
// for things like full framebuffer copy operations (deferred lighting passes)
|
||||
bool savedStereo = _stereo._enable;
|
||||
if (!batch.isStereoEnabled()) {
|
||||
_stereo._enable = false;
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE_RANGE(render_gpu_gl_detail, "Transfer");
|
||||
renderPassTransfer(batch);
|
||||
}
|
||||
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
if (_stereo.isStereo()) {
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
PROFILE_RANGE(render_gpu_gl_detail, _stereo.isStereo() ? "Render Stereo" : "Render");
|
||||
renderPassDraw(batch);
|
||||
}
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
if (_stereo.isStereo()) {
|
||||
glDisable(GL_CLIP_DISTANCE0);
|
||||
}
|
||||
#endif
|
||||
// Restore the saved stereo state for the next batch
|
||||
_stereo._enable = savedStereo;
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::syncCache() {
|
||||
PROFILE_RANGE(render_gpu_gl_detail, __FUNCTION__);
|
||||
|
||||
syncTransformStateCache();
|
||||
syncPipelineStateCache();
|
||||
syncInputStateCache();
|
||||
syncOutputStateCache();
|
||||
}
|
||||
|
||||
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
|
||||
void GLBackend::setupStereoSide(int side) {
|
||||
ivec4 vp = _transform._viewport;
|
||||
vp.z /= 2;
|
||||
glViewport(vp.x + side * vp.z, vp.y, vp.z, vp.w);
|
||||
|
||||
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
|
||||
glVertexAttribI1i(14, side);
|
||||
#endif
|
||||
#else
|
||||
_transform.bindCurrentCamera(side);
|
||||
#endif
|
||||
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) {
|
||||
resetStages();
|
||||
}
|
||||
|
||||
void GLBackend::do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) {
|
||||
_transform._viewCorrectionEnabled = false;
|
||||
}
|
||||
|
||||
void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) {
|
||||
_transform._viewCorrectionEnabled = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
}
|
||||
|
||||
void GLBackend::do_restoreContextStereo(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
}
|
||||
|
||||
void GLBackend::do_runLambda(const Batch& batch, size_t paramOffset) {
|
||||
std::function<void()> f = batch._lambdas.get(batch._params[paramOffset]._uint);
|
||||
f();
|
||||
}
|
||||
|
||||
void GLBackend::do_startNamedCall(const Batch& batch, size_t paramOffset) {
|
||||
batch._currentNamedCall = batch._names.get(batch._params[paramOffset]._uint);
|
||||
_currentDraw = -1;
|
||||
}
|
||||
|
||||
void GLBackend::do_stopNamedCall(const Batch& batch, size_t paramOffset) {
|
||||
batch._currentNamedCall.clear();
|
||||
}
|
||||
|
||||
void GLBackend::resetStages() {
|
||||
resetInputStage();
|
||||
resetPipelineStage();
|
||||
resetTransformStage();
|
||||
resetUniformStage();
|
||||
resetResourceStage();
|
||||
resetOutputStage();
|
||||
resetQueryStage();
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_pushProfileRange(const Batch& batch, size_t paramOffset) {
|
||||
if (trace_render_gpu_gl_detail().isDebugEnabled()) {
|
||||
auto name = batch._profileRanges.get(batch._params[paramOffset]._uint);
|
||||
profileRanges.push_back(name);
|
||||
#if defined(NSIGHT_FOUND)
|
||||
nvtxRangePush(name.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) {
|
||||
if (trace_render_gpu_gl_detail().isDebugEnabled()) {
|
||||
profileRanges.pop_back();
|
||||
#if defined(NSIGHT_FOUND)
|
||||
nvtxRangePop();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
|
||||
glUniform1i(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
|
||||
batch._params[paramOffset + 0]._int);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform1f(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
|
||||
glUniform1f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform2f(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform2f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform3f(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform3f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform4f(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform4f(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 4]._int),
|
||||
batch._params[paramOffset + 3]._float,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform3fv(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform3fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform4fv(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
|
||||
GLint location = GET_UNIFORM_LOCATION(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);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniform4iv(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform4iv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 2]._int),
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLint*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniformMatrix3fv(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
|
||||
glUniformMatrix3fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glUniformMatrix4fv(const Batch& batch, size_t paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
|
||||
glUniformMatrix4fv(
|
||||
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
|
||||
batch._params[paramOffset + 2]._uint,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLfloat*)batch.readData(batch._params[paramOffset + 0]._uint));
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
glm::vec4 newColor(
|
||||
batch._params[paramOffset + 3]._float,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
|
||||
if (_input._colorAttribute != newColor) {
|
||||
_input._colorAttribute = newColor;
|
||||
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
|
||||
// Color has been changed and is not white. To prevent colors from bleeding
|
||||
// between different objects, we need to set the _hadColorAttribute flag
|
||||
// as if a previous render call had potential colors
|
||||
_input._hadColorAttribute = (newColor != glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::releaseBuffer(GLuint id, Size size) const {
|
||||
Lock lock(_trashMutex);
|
||||
_buffersTrash.push_back({ id, size });
|
||||
}
|
||||
|
||||
void GLBackend::releaseExternalTexture(GLuint id, const Texture::ExternalRecycler& recycler) const {
|
||||
Lock lock(_trashMutex);
|
||||
_externalTexturesTrash.push_back({ id, recycler });
|
||||
}
|
||||
|
||||
void GLBackend::releaseTexture(GLuint id, Size size) const {
|
||||
Lock lock(_trashMutex);
|
||||
_texturesTrash.push_back({ id, size });
|
||||
}
|
||||
|
||||
void GLBackend::releaseFramebuffer(GLuint id) const {
|
||||
Lock lock(_trashMutex);
|
||||
_framebuffersTrash.push_back(id);
|
||||
}
|
||||
|
||||
void GLBackend::releaseShader(GLuint id) const {
|
||||
Lock lock(_trashMutex);
|
||||
_shadersTrash.push_back(id);
|
||||
}
|
||||
|
||||
void GLBackend::releaseProgram(GLuint id) const {
|
||||
Lock lock(_trashMutex);
|
||||
_programsTrash.push_back(id);
|
||||
}
|
||||
|
||||
void GLBackend::releaseQuery(GLuint id) const {
|
||||
Lock lock(_trashMutex);
|
||||
_queriesTrash.push_back(id);
|
||||
}
|
||||
|
||||
void GLBackend::queueLambda(const std::function<void()> lambda) const {
|
||||
Lock lock(_trashMutex);
|
||||
_lambdaQueue.push_back(lambda);
|
||||
}
|
||||
|
||||
void GLBackend::recycle() const {
|
||||
PROFILE_RANGE(render_gpu_gl, __FUNCTION__)
|
||||
{
|
||||
std::list<std::function<void()>> lamdbasTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_lambdaQueue, lamdbasTrash);
|
||||
}
|
||||
for (auto lambda : lamdbasTrash) {
|
||||
lambda();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<GLuint> ids;
|
||||
std::list<std::pair<GLuint, Size>> buffersTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_buffersTrash, buffersTrash);
|
||||
}
|
||||
ids.reserve(buffersTrash.size());
|
||||
for (auto pair : buffersTrash) {
|
||||
ids.push_back(pair.first);
|
||||
}
|
||||
if (!ids.empty()) {
|
||||
glDeleteBuffers((GLsizei)ids.size(), ids.data());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<GLuint> ids;
|
||||
std::list<GLuint> framebuffersTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_framebuffersTrash, framebuffersTrash);
|
||||
}
|
||||
ids.reserve(framebuffersTrash.size());
|
||||
for (auto id : framebuffersTrash) {
|
||||
ids.push_back(id);
|
||||
}
|
||||
if (!ids.empty()) {
|
||||
glDeleteFramebuffers((GLsizei)ids.size(), ids.data());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<GLuint> ids;
|
||||
std::list<std::pair<GLuint, Size>> texturesTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_texturesTrash, texturesTrash);
|
||||
}
|
||||
ids.reserve(texturesTrash.size());
|
||||
for (auto pair : texturesTrash) {
|
||||
ids.push_back(pair.first);
|
||||
}
|
||||
if (!ids.empty()) {
|
||||
glDeleteTextures((GLsizei)ids.size(), ids.data());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::list<std::pair<GLuint, Texture::ExternalRecycler>> externalTexturesTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_externalTexturesTrash, externalTexturesTrash);
|
||||
}
|
||||
if (!externalTexturesTrash.empty()) {
|
||||
std::vector<GLsync> fences;
|
||||
fences.resize(externalTexturesTrash.size());
|
||||
for (size_t i = 0; i < externalTexturesTrash.size(); ++i) {
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
// External texture fences will be read in another thread/context, so we need a flush
|
||||
glFlush();
|
||||
size_t index = 0;
|
||||
for (auto pair : externalTexturesTrash) {
|
||||
auto fence = fences[index++];
|
||||
pair.second(pair.first, fence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::list<GLuint> programsTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_programsTrash, programsTrash);
|
||||
}
|
||||
for (auto id : programsTrash) {
|
||||
glDeleteProgram(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::list<GLuint> shadersTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_shadersTrash, shadersTrash);
|
||||
}
|
||||
for (auto id : shadersTrash) {
|
||||
glDeleteShader(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<GLuint> ids;
|
||||
std::list<GLuint> queriesTrash;
|
||||
{
|
||||
Lock lock(_trashMutex);
|
||||
std::swap(_queriesTrash, queriesTrash);
|
||||
}
|
||||
ids.reserve(queriesTrash.size());
|
||||
for (auto id : queriesTrash) {
|
||||
ids.push_back(id);
|
||||
}
|
||||
if (!ids.empty()) {
|
||||
glDeleteQueries((GLsizei)ids.size(), ids.data());
|
||||
}
|
||||
}
|
||||
|
||||
GLVariableAllocationSupport::manageMemory();
|
||||
GLVariableAllocationSupport::_frameTexturesCreated = 0;
|
||||
Texture::KtxStorage::releaseOpenKtxFiles();
|
||||
}
|
||||
|
||||
void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) {
|
||||
auto invCorrection = glm::inverse(correction);
|
||||
auto invPrevView = glm::inverse(prevRenderView);
|
||||
_transform._correction.prevView = (reset ? Mat4() : prevRenderView);
|
||||
_transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView);
|
||||
_transform._correction.correction = correction;
|
||||
_transform._correction.correctionInverse = invCorrection;
|
||||
_pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction);
|
||||
_pipeline._cameraCorrectionBuffer._buffer->flush();
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
//
|
||||
// GLBackendInput.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLShared.h"
|
||||
#include "GLInputFormat.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::do_setInputFormat(const Batch& batch, size_t paramOffset) {
|
||||
Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint);
|
||||
if (format != _input._format) {
|
||||
_input._format = format;
|
||||
if (format) {
|
||||
auto inputFormat = GLInputFormat::sync((*format));
|
||||
assert(inputFormat);
|
||||
if (_input._formatKey != inputFormat->key) {
|
||||
_input._formatKey = inputFormat->key;
|
||||
_input._invalidFormat = true;
|
||||
}
|
||||
} else {
|
||||
_input._formatKey.clear();
|
||||
_input._invalidFormat = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setInputBuffer(const Batch& batch, size_t paramOffset) {
|
||||
Offset stride = batch._params[paramOffset + 0]._uint;
|
||||
Offset offset = batch._params[paramOffset + 1]._uint;
|
||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint);
|
||||
uint32 channel = batch._params[paramOffset + 3]._uint;
|
||||
|
||||
if (channel < getNumInputBuffers()) {
|
||||
bool isModified = false;
|
||||
if (_input._buffers[channel] != buffer) {
|
||||
_input._buffers[channel] = buffer;
|
||||
|
||||
GLuint vbo = 0;
|
||||
if (buffer) {
|
||||
vbo = getBufferID((*buffer));
|
||||
}
|
||||
_input._bufferVBOs[channel] = vbo;
|
||||
|
||||
isModified = true;
|
||||
}
|
||||
|
||||
if (_input._bufferOffsets[channel] != offset) {
|
||||
_input._bufferOffsets[channel] = offset;
|
||||
isModified = true;
|
||||
}
|
||||
|
||||
if (_input._bufferStrides[channel] != stride) {
|
||||
_input._bufferStrides[channel] = stride;
|
||||
isModified = true;
|
||||
}
|
||||
|
||||
if (isModified) {
|
||||
_input._invalidBuffers.set(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::initInput() {
|
||||
if(!_input._defaultVAO) {
|
||||
glGenVertexArrays(1, &_input._defaultVAO);
|
||||
}
|
||||
glBindVertexArray(_input._defaultVAO);
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::killInput() {
|
||||
glBindVertexArray(0);
|
||||
if(_input._defaultVAO) {
|
||||
glDeleteVertexArrays(1, &_input._defaultVAO);
|
||||
}
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::syncInputStateCache() {
|
||||
for (uint32_t i = 0; i < _input._attributeActivation.size(); i++) {
|
||||
GLint active = 0;
|
||||
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &active);
|
||||
_input._attributeActivation[i] = active;
|
||||
}
|
||||
//_input._defaultVAO
|
||||
glBindVertexArray(_input._defaultVAO);
|
||||
}
|
||||
|
||||
void GLBackend::resetInputStage() {
|
||||
// Reset index buffer
|
||||
_input._indexBufferType = UINT32;
|
||||
_input._indexBufferOffset = 0;
|
||||
_input._indexBuffer.reset();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
(void) CHECK_GL_ERROR();
|
||||
|
||||
// Reset vertex buffer and format
|
||||
_input._format.reset();
|
||||
_input._formatKey.clear();
|
||||
_input._invalidFormat = false;
|
||||
_input._attributeActivation.reset();
|
||||
|
||||
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
|
||||
_input._buffers[i].reset();
|
||||
_input._bufferOffsets[i] = 0;
|
||||
_input._bufferStrides[i] = 0;
|
||||
_input._bufferVBOs[i] = 0;
|
||||
}
|
||||
_input._invalidBuffers.reset();
|
||||
|
||||
// THe vertex array binding MUST be reset in the specific Backend versions as they use different techniques
|
||||
}
|
||||
|
||||
void GLBackend::do_setIndexBuffer(const Batch& batch, size_t paramOffset) {
|
||||
_input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint;
|
||||
_input._indexBufferOffset = batch._params[paramOffset + 0]._uint;
|
||||
|
||||
BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint);
|
||||
if (indexBuffer != _input._indexBuffer) {
|
||||
_input._indexBuffer = indexBuffer;
|
||||
if (indexBuffer) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer));
|
||||
} else {
|
||||
// FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null?
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) {
|
||||
_input._indirectBufferOffset = batch._params[paramOffset + 1]._uint;
|
||||
_input._indirectBufferStride = batch._params[paramOffset + 2]._uint;
|
||||
|
||||
BufferPointer buffer = batch._buffers.get(batch._params[paramOffset]._uint);
|
||||
if (buffer != _input._indirectBuffer) {
|
||||
_input._indirectBuffer = buffer;
|
||||
if (buffer) {
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferID(*buffer));
|
||||
} else {
|
||||
// FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null?
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
63
libraries/gpu-gl/src/gpu/gl/GLDesktopBackend.cpp
Normal file
63
libraries/gpu-gl/src/gpu/gl/GLDesktopBackend.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// GLBackend.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 10/27/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gpu/gl/GLShader.h>
|
||||
|
||||
#include "../gl41/GL41Backend.h"
|
||||
#include "../gl45/GL45Backend.h"
|
||||
|
||||
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() {
|
||||
// FIXME provide a mechanism to override the backend for testing
|
||||
// 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) {
|
||||
qCDebug(gpugllogging) << "Using OpenGL 4.5 backend";
|
||||
result = std::make_shared<gpu::gl45::GL45Backend>();
|
||||
} else {
|
||||
qCDebug(gpugllogging) << "Using OpenGL 4.1 backend";
|
||||
result = std::make_shared<gpu::gl41::GL41Backend>();
|
||||
}
|
||||
result->initInput();
|
||||
result->initTransform();
|
||||
result->initTextureManagementStage();
|
||||
|
||||
INSTANCE = result.get();
|
||||
void* voidInstance = &(*result);
|
||||
qApp->setProperty(hifi::properties::gl::BACKEND, QVariant::fromValue(voidInstance));
|
||||
return result;
|
||||
}
|
||||
|
||||
GLBackend& getBackend() {
|
||||
if (!INSTANCE) {
|
||||
INSTANCE = static_cast<GLBackend*>(qApp->property(hifi::properties::gl::BACKEND).value<void*>());
|
||||
}
|
||||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
||||
}
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include "../gl/GLBackend.h"
|
||||
#include "../gl/GLTexture.h"
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <gpu/gl/GLTexture.h>
|
||||
|
||||
#define GPU_CORE_41 410
|
||||
#define GPU_CORE_43 430
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GL41Backend.h"
|
||||
#include "../gl/GLBuffer.h"
|
||||
#include <gpu/gl/GLBuffer.h>
|
||||
|
||||
namespace gpu {
|
||||
namespace gl41 {
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include "../gl/GLFramebuffer.h"
|
||||
#include "../gl/GLTexture.h"
|
||||
#include <gpu/gl/GLFramebuffer.h>
|
||||
#include <gpu/gl/GLTexture.h>
|
||||
|
||||
namespace gpu { namespace gl41 {
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
#include "GL41Backend.h"
|
||||
|
||||
#include "../gl/GLQuery.h"
|
||||
#include <gpu/gl/GLQuery.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GL41Backend.h"
|
||||
#include "../gl/GLShader.h"
|
||||
#include <gpu/gl/GLShader.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../gl/GLTexelFormat.h"
|
||||
#include <gpu/gl/GLTexelFormat.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
#ifndef hifi_gpu_45_GL45Backend_h
|
||||
#define hifi_gpu_45_GL45Backend_h
|
||||
|
||||
#include "../gl/GLBackend.h"
|
||||
#include "../gl/GLTexture.h"
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <gpu/gl/GLTexture.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#define INCREMENTAL_TRANSFER 0
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GL45Backend.h"
|
||||
#include "../gl/GLBuffer.h"
|
||||
#include <gpu/gl/GLBuffer.h>
|
||||
|
||||
namespace gpu { namespace gl45 {
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GL45Backend.h"
|
||||
#include "../gl/GLShared.h"
|
||||
#include <gpu/gl/GLShared.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl45;
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GL45Backend.h"
|
||||
#include "../gl/GLFramebuffer.h"
|
||||
#include "../gl/GLTexture.h"
|
||||
#include <gpu/gl/GLFramebuffer.h>
|
||||
#include <gpu/gl/GLTexture.h>
|
||||
|
||||
#include <QtGui/QImage>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
#include "GL45Backend.h"
|
||||
|
||||
#include "../gl/GLQuery.h"
|
||||
#include <gpu/gl/GLQuery.h>
|
||||
|
||||
namespace gpu { namespace gl45 {
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GL45Backend.h"
|
||||
#include "../gl/GLShader.h"
|
||||
#include <gpu/gl/GLShader.h>
|
||||
//#include <gl/GLShaders.h>
|
||||
|
||||
using namespace gpu;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <QtCore/QDebug>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include "../gl/GLTexelFormat.h"
|
||||
#include <gpu/gl/GLTexelFormat.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <QtCore/QThread>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include "../gl/GLTexelFormat.h"
|
||||
#include <gpu/gl/GLTexelFormat.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(TARGET_NAME gpu-gles)
|
||||
setup_hifi_library(Gui Concurrent)
|
||||
link_hifi_libraries(shared gl gpu)
|
||||
link_hifi_libraries(shared gl gpu gpu-gl-common)
|
||||
GroupSources("src")
|
||||
target_opengl()
|
||||
|
|
|
@ -1,482 +0,0 @@
|
|||
//
|
||||
// Created by Cristian Duarte & Gabriel Calero on 09/21/2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gles_Backend_h
|
||||
#define hifi_gpu_gles_Backend_h
|
||||
|
||||
#include <assert.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <list>
|
||||
#include <array>
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
|
||||
// Different versions for the stereo drawcall
|
||||
// Current preferred is "instanced" which draw the shape twice but instanced and rely on clipping plane to draw left/right side only
|
||||
#define GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
|
||||
//#define GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER
|
||||
//#define GPU_STEREO_TECHNIQUE_INSTANCED
|
||||
|
||||
|
||||
// Let these be configured by the one define picked above
|
||||
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
|
||||
#define GPU_STEREO_DRAWCALL_DOUBLED
|
||||
#endif
|
||||
|
||||
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER
|
||||
#define GPU_STEREO_DRAWCALL_DOUBLED
|
||||
#define GPU_STEREO_CAMERA_BUFFER
|
||||
#endif
|
||||
|
||||
#ifdef GPU_STEREO_TECHNIQUE_INSTANCED
|
||||
#define GPU_STEREO_DRAWCALL_INSTANCED
|
||||
#define GPU_STEREO_CAMERA_BUFFER
|
||||
#endif
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLBackend : public Backend, public std::enable_shared_from_this<GLBackend> {
|
||||
// Context Backend static interface required
|
||||
friend class gpu::Context;
|
||||
static void init();
|
||||
static BackendPointer createBackend();
|
||||
|
||||
protected:
|
||||
explicit GLBackend(bool syncCache);
|
||||
GLBackend();
|
||||
public:
|
||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet(), const Shader::CompilationHandler& handler = nullptr);
|
||||
|
||||
virtual ~GLBackend();
|
||||
|
||||
void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false);
|
||||
void render(const Batch& batch) final override;
|
||||
|
||||
// This call synchronize the Full Backend cache with the current GLState
|
||||
// THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync
|
||||
// the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls
|
||||
// Let's try to avoid to do that as much as possible!
|
||||
void syncCache() final override;
|
||||
|
||||
// This is the ugly "download the pixels to sysmem for taking a snapshot"
|
||||
// Just avoid using it, it's ugly and will break performances
|
||||
virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer,
|
||||
const Vec4i& region, QImage& destImage) final override;
|
||||
|
||||
|
||||
// this is the maximum numeber of available input buffers
|
||||
size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); }
|
||||
|
||||
// this is the maximum per shader stage on the low end apple
|
||||
// TODO make it platform dependant at init time
|
||||
static const int MAX_NUM_UNIFORM_BUFFERS = 12;
|
||||
size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; }
|
||||
|
||||
// this is the maximum per shader stage on the low end apple
|
||||
// TODO make it platform dependant at init time
|
||||
static const int MAX_NUM_RESOURCE_BUFFERS = 16;
|
||||
size_t getMaxNumResourceBuffers() const { return MAX_NUM_RESOURCE_BUFFERS; }
|
||||
static const int MAX_NUM_RESOURCE_TEXTURES = 16;
|
||||
size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; }
|
||||
|
||||
// Draw Stage
|
||||
virtual void do_draw(const Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_drawInstanced(const Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_drawIndexedInstanced(const Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_multiDrawIndirect(const Batch& batch, size_t paramOffset) = 0;
|
||||
virtual void do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOffset) = 0;
|
||||
|
||||
// Input Stage
|
||||
virtual void do_setInputFormat(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setInputBuffer(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setIndexBuffer(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setIndirectBuffer(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_generateTextureMips(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Transform Stage
|
||||
virtual void do_setModelTransform(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setViewTransform(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setProjectionTransform(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setViewportTransform(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setDepthRangeTransform(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Uniform Stage
|
||||
virtual void do_setUniformBuffer(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Resource Stage
|
||||
virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Pipeline Stage
|
||||
virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Output stage
|
||||
virtual void do_setFramebuffer(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setFramebufferSwapChain(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_clearFramebuffer(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_blit(const Batch& batch, size_t paramOffset) = 0;
|
||||
|
||||
virtual void do_advance(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Query section
|
||||
virtual void do_beginQuery(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_endQuery(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_getQuery(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// Reset stages
|
||||
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
|
||||
virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_runLambda(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_startNamedCall(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_stopNamedCall(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
|
||||
// The drawcall Info attribute channel is reserved and is the upper bound for the number of availables Input buffers
|
||||
static const int MAX_NUM_INPUT_BUFFERS = Stream::DRAW_CALL_INFO;
|
||||
|
||||
virtual void do_pushProfileRange(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_popProfileRange(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// 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
|
||||
virtual void do_glUniform1i(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform1f(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform2f(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform3f(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform4f(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform3fv(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform4fv(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniform4iv(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniformMatrix3fv(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_glUniformMatrix4fv(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_glColor4f(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
// The State setters called by the GLState::Commands when a new state is assigned
|
||||
virtual void do_setStateFillMode(int32 mode) final;
|
||||
virtual void do_setStateCullMode(int32 mode) final;
|
||||
virtual void do_setStateFrontFaceClockwise(bool isClockwise) final;
|
||||
virtual void do_setStateDepthClampEnable(bool enable) final;
|
||||
virtual void do_setStateScissorEnable(bool enable) final;
|
||||
virtual void do_setStateMultisampleEnable(bool enable) final;
|
||||
virtual void do_setStateAntialiasedLineEnable(bool enable) final;
|
||||
virtual void do_setStateDepthBias(Vec2 bias) final;
|
||||
virtual void do_setStateDepthTest(State::DepthTest test) final;
|
||||
virtual void do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) final;
|
||||
virtual void do_setStateAlphaToCoverageEnable(bool enable) final;
|
||||
virtual void do_setStateSampleMask(uint32 mask) final;
|
||||
virtual void do_setStateBlend(State::BlendFunction blendFunction) final;
|
||||
virtual void do_setStateColorWriteMask(uint32 mask) final;
|
||||
virtual void do_setStateBlendFactor(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_setStateScissorRect(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0;
|
||||
virtual GLuint getTextureID(const TexturePointer& texture) final;
|
||||
virtual GLuint getBufferID(const Buffer& buffer) = 0;
|
||||
virtual GLuint getQueryID(const QueryPointer& query) = 0;
|
||||
|
||||
virtual GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) = 0;
|
||||
virtual GLBuffer* syncGPUObject(const Buffer& buffer) = 0;
|
||||
virtual GLTexture* syncGPUObject(const TexturePointer& texture);
|
||||
virtual GLQuery* syncGPUObject(const Query& query) = 0;
|
||||
//virtual bool isTextureReady(const TexturePointer& texture);
|
||||
|
||||
virtual void releaseBuffer(GLuint id, Size size) const;
|
||||
virtual void releaseExternalTexture(GLuint id, const Texture::ExternalRecycler& recycler) const;
|
||||
virtual void releaseTexture(GLuint id, Size size) const;
|
||||
virtual void releaseFramebuffer(GLuint id) const;
|
||||
virtual void releaseShader(GLuint id) const;
|
||||
virtual void releaseProgram(GLuint id) const;
|
||||
virtual void releaseQuery(GLuint id) const;
|
||||
virtual void queueLambda(const std::function<void()> lambda) const;
|
||||
|
||||
bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); }
|
||||
|
||||
protected:
|
||||
|
||||
void recycle() const override;
|
||||
|
||||
static const size_t INVALID_OFFSET = (size_t)-1;
|
||||
bool _inRenderTransferPass { false };
|
||||
int32_t _uboAlignment { 0 };
|
||||
int _currentDraw { -1 };
|
||||
|
||||
std::list<std::string> profileRanges;
|
||||
mutable Mutex _trashMutex;
|
||||
mutable std::list<std::pair<GLuint, Size>> _buffersTrash;
|
||||
mutable std::list<std::pair<GLuint, Size>> _texturesTrash;
|
||||
mutable std::list<std::pair<GLuint, Texture::ExternalRecycler>> _externalTexturesTrash;
|
||||
mutable std::list<GLuint> _framebuffersTrash;
|
||||
mutable std::list<GLuint> _shadersTrash;
|
||||
mutable std::list<GLuint> _programsTrash;
|
||||
mutable std::list<GLuint> _queriesTrash;
|
||||
mutable std::list<std::function<void()>> _lambdaQueue;
|
||||
|
||||
void renderPassTransfer(const Batch& batch);
|
||||
void renderPassDraw(const Batch& batch);
|
||||
|
||||
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
|
||||
void setupStereoSide(int side);
|
||||
#endif
|
||||
|
||||
virtual void setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture);
|
||||
virtual void setFramebuffer(const FramebufferPointer& framebuffer);
|
||||
virtual void initInput() final;
|
||||
virtual void killInput() final;
|
||||
virtual void syncInputStateCache() final;
|
||||
virtual void resetInputStage();
|
||||
virtual void updateInput() = 0;
|
||||
|
||||
struct InputStageState {
|
||||
bool _invalidFormat { true };
|
||||
bool _hadColorAttribute{ true };
|
||||
Stream::FormatPointer _format;
|
||||
std::string _formatKey;
|
||||
|
||||
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
|
||||
ActivationCache _attributeActivation { 0 };
|
||||
|
||||
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
|
||||
|
||||
BuffersState _invalidBuffers{ 0 };
|
||||
BuffersState _attribBindingBuffers{ 0 };
|
||||
|
||||
Buffers _buffers;
|
||||
Offsets _bufferOffsets;
|
||||
Offsets _bufferStrides;
|
||||
std::vector<GLuint> _bufferVBOs;
|
||||
|
||||
glm::vec4 _colorAttribute{ 0.0f };
|
||||
|
||||
BufferPointer _indexBuffer;
|
||||
Offset _indexBufferOffset { 0 };
|
||||
Type _indexBufferType { UINT32 };
|
||||
|
||||
BufferPointer _indirectBuffer;
|
||||
Offset _indirectBufferOffset{ 0 };
|
||||
Offset _indirectBufferStride{ 0 };
|
||||
|
||||
GLuint _defaultVAO { 0 };
|
||||
|
||||
InputStageState() :
|
||||
_invalidFormat(true),
|
||||
_format(0),
|
||||
_formatKey(),
|
||||
_attributeActivation(0),
|
||||
_buffers(_invalidBuffers.size(), BufferPointer(0)),
|
||||
_bufferOffsets(_invalidBuffers.size(), 0),
|
||||
_bufferStrides(_invalidBuffers.size(), 0),
|
||||
_bufferVBOs(_invalidBuffers.size(), 0) {}
|
||||
} _input;
|
||||
|
||||
virtual void initTransform() = 0;
|
||||
void killTransform();
|
||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||
void syncTransformStateCache();
|
||||
virtual void updateTransform(const Batch& batch) = 0;
|
||||
virtual void resetTransformStage();
|
||||
|
||||
// Allows for correction of the camera pose to account for changes
|
||||
// between the time when a was recorded and the time(s) when it is
|
||||
// executed
|
||||
struct CameraCorrection {
|
||||
Mat4 correction;
|
||||
Mat4 correctionInverse;
|
||||
Mat4 prevView;
|
||||
Mat4 prevViewInverse;
|
||||
};
|
||||
|
||||
struct TransformStageState {
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
struct Cameras {
|
||||
TransformCamera _cams[2];
|
||||
|
||||
Cameras() {};
|
||||
Cameras(const TransformCamera& cam) { memcpy(_cams, &cam, sizeof(TransformCamera)); };
|
||||
Cameras(const TransformCamera& camL, const TransformCamera& camR) { memcpy(_cams, &camL, sizeof(TransformCamera)); memcpy(_cams + 1, &camR, sizeof(TransformCamera)); };
|
||||
};
|
||||
|
||||
using CameraBufferElement = Cameras;
|
||||
#else
|
||||
using CameraBufferElement = TransformCamera;
|
||||
#endif
|
||||
using TransformCameras = std::vector<CameraBufferElement>;
|
||||
|
||||
TransformCamera _camera;
|
||||
TransformCameras _cameras;
|
||||
|
||||
mutable std::map<std::string, GLvoid*> _drawCallInfoOffsets;
|
||||
|
||||
GLuint _objectBuffer { 0 };
|
||||
GLuint _cameraBuffer { 0 };
|
||||
GLuint _drawCallInfoBuffer { 0 };
|
||||
GLuint _objectBufferTexture { 0 };
|
||||
size_t _cameraUboSize { 0 };
|
||||
bool _viewIsCamera{ false };
|
||||
bool _skybox { false };
|
||||
Transform _view;
|
||||
CameraCorrection _correction;
|
||||
bool _viewCorrectionEnabled{ true };
|
||||
|
||||
|
||||
Mat4 _projection;
|
||||
Vec4i _viewport { 0, 0, 1, 1 };
|
||||
Vec2 _depthRange { 0.0f, 1.0f };
|
||||
bool _invalidView { false };
|
||||
bool _invalidProj { false };
|
||||
bool _invalidViewport { false };
|
||||
|
||||
bool _enabledDrawcallInfoBuffer{ false };
|
||||
|
||||
using Pair = std::pair<size_t, size_t>;
|
||||
using List = std::list<Pair>;
|
||||
List _cameraOffsets;
|
||||
mutable List::const_iterator _camerasItr;
|
||||
mutable size_t _currentCameraOffset{ INVALID_OFFSET };
|
||||
|
||||
void preUpdate(size_t commandIndex, const StereoState& stereo);
|
||||
void update(size_t commandIndex, const StereoState& stereo) const;
|
||||
void bindCurrentCamera(int stereoSide) const;
|
||||
} _transform;
|
||||
|
||||
virtual void transferTransformState(const Batch& batch) const = 0;
|
||||
|
||||
struct UniformStageState {
|
||||
std::array<BufferPointer, MAX_NUM_UNIFORM_BUFFERS> _buffers;
|
||||
//Buffers _buffers { };
|
||||
} _uniform;
|
||||
|
||||
void releaseUniformBuffer(uint32_t slot);
|
||||
void resetUniformStage();
|
||||
|
||||
// update resource cache and do the gl bind/unbind call with the current gpu::Buffer cached at slot s
|
||||
// This is using different gl object depending on the gl version
|
||||
virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0;
|
||||
virtual void releaseResourceBuffer(uint32_t slot) = 0;
|
||||
|
||||
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
|
||||
void releaseResourceTexture(uint32_t slot);
|
||||
|
||||
void resetResourceStage();
|
||||
|
||||
struct ResourceStageState {
|
||||
std::array<BufferPointer, MAX_NUM_RESOURCE_BUFFERS> _buffers;
|
||||
std::array<TexturePointer, MAX_NUM_RESOURCE_TEXTURES> _textures;
|
||||
//Textures _textures { { MAX_NUM_RESOURCE_TEXTURES } };
|
||||
int findEmptyTextureSlot() const;
|
||||
} _resource;
|
||||
|
||||
size_t _commandIndex{ 0 };
|
||||
|
||||
// Standard update pipeline check that the current Program and current State or good to go for a
|
||||
void updatePipeline();
|
||||
// Force to reset all the state fields indicated by the 'toBeReset" signature
|
||||
void resetPipelineState(State::Signature toBeReset);
|
||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||
void syncPipelineStateCache();
|
||||
void resetPipelineStage();
|
||||
|
||||
struct PipelineStageState {
|
||||
PipelinePointer _pipeline;
|
||||
|
||||
GLuint _program { 0 };
|
||||
GLint _cameraCorrectionLocation { -1 };
|
||||
GLShader* _programShader { nullptr };
|
||||
bool _invalidProgram { false };
|
||||
|
||||
BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
||||
BufferView _cameraCorrectionBufferIdentity { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
||||
|
||||
State::Data _stateCache{ State::DEFAULT };
|
||||
State::Signature _stateSignatureCache { 0 };
|
||||
|
||||
GLState* _state { nullptr };
|
||||
bool _invalidState { false };
|
||||
|
||||
PipelineStageState() {
|
||||
_cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection();
|
||||
_cameraCorrectionBufferIdentity.edit<CameraCorrection>() = CameraCorrection();
|
||||
_cameraCorrectionBufferIdentity._buffer->flush();
|
||||
}
|
||||
} _pipeline;
|
||||
|
||||
// Backend dependant compilation of the shader
|
||||
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;
|
||||
virtual void makeProgramBindings(ShaderObject& shaderObject);
|
||||
class ElementResource {
|
||||
public:
|
||||
gpu::Element _element;
|
||||
uint16 _resource;
|
||||
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(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers);
|
||||
virtual int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
|
||||
virtual int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& resourceBuffers) = 0;
|
||||
virtual int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
|
||||
virtual int makeOutputSlots(GLuint glprogram, 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();
|
||||
void resetOutputStage();
|
||||
|
||||
struct OutputStageState {
|
||||
FramebufferPointer _framebuffer { nullptr };
|
||||
GLuint _drawFBO { 0 };
|
||||
} _output;
|
||||
|
||||
void resetQueryStage();
|
||||
struct QueryStageState {
|
||||
uint32_t _rangeQueryDepth { 0 };
|
||||
} _queryStage;
|
||||
|
||||
void resetStages();
|
||||
|
||||
struct TextureManagementStageState {
|
||||
bool _sparseCapable { false };
|
||||
} _textureManagement;
|
||||
virtual void initTextureManagementStage() {}
|
||||
|
||||
typedef void (GLBackend::*CommandCall)(const Batch&, size_t);
|
||||
static CommandCall _commandCalls[Batch::NUM_COMMANDS];
|
||||
friend class GLState;
|
||||
friend class GLTexture;
|
||||
friend class GLShader;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
|
@ -1,195 +0,0 @@
|
|||
//
|
||||
// GLBackendTexture.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 1/19/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLShared.h"
|
||||
#include "GLFramebuffer.h"
|
||||
|
||||
#include <QtGui/QImage>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::syncOutputStateCache() {
|
||||
GLint currentFBO;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤tFBO);
|
||||
|
||||
_output._drawFBO = currentFBO;
|
||||
_output._framebuffer.reset();
|
||||
}
|
||||
|
||||
void GLBackend::resetOutputStage() {
|
||||
if (_output._framebuffer) {
|
||||
_output._framebuffer.reset();
|
||||
_output._drawFBO = 0;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
|
||||
}
|
||||
|
||||
void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||
auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint);
|
||||
setFramebuffer(framebuffer);
|
||||
}
|
||||
|
||||
void GLBackend::do_setFramebufferSwapChain(const Batch& batch, size_t paramOffset) {
|
||||
auto swapChain = batch._swapChains.get(batch._params[paramOffset]._uint);
|
||||
if (swapChain) {
|
||||
auto index = batch._params[paramOffset + 1]._uint;
|
||||
FramebufferPointer framebuffer = static_cast<const FramebufferSwapChain*>(swapChain.get())->get(index);
|
||||
setFramebuffer(framebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::setFramebuffer(const FramebufferPointer& framebuffer) {
|
||||
if (_output._framebuffer != framebuffer) {
|
||||
auto newFBO = getFramebufferID(framebuffer);
|
||||
if (_output._drawFBO != newFBO) {
|
||||
_output._drawFBO = newFBO;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, newFBO);
|
||||
}
|
||||
_output._framebuffer = framebuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_advance(const Batch& batch, size_t paramOffset) {
|
||||
auto ringbuffer = batch._swapChains.get(batch._params[paramOffset]._uint);
|
||||
if (ringbuffer) {
|
||||
ringbuffer->advance();
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
||||
if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) {
|
||||
qWarning("Clear without scissor in stereo mode");
|
||||
}
|
||||
|
||||
uint32 masks = batch._params[paramOffset + 7]._uint;
|
||||
Vec4 color;
|
||||
color.x = batch._params[paramOffset + 6]._float;
|
||||
color.y = batch._params[paramOffset + 5]._float;
|
||||
color.z = batch._params[paramOffset + 4]._float;
|
||||
color.w = batch._params[paramOffset + 3]._float;
|
||||
float depth = batch._params[paramOffset + 2]._float;
|
||||
int stencil = batch._params[paramOffset + 1]._int;
|
||||
int useScissor = batch._params[paramOffset + 0]._int;
|
||||
|
||||
GLuint glmask = 0;
|
||||
bool restoreStencilMask = false;
|
||||
uint8_t cacheStencilMask = 0xFF;
|
||||
if (masks & Framebuffer::BUFFER_STENCIL) {
|
||||
glClearStencil(stencil);
|
||||
glmask |= GL_STENCIL_BUFFER_BIT;
|
||||
cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront();
|
||||
if (cacheStencilMask != 0xFF) {
|
||||
restoreStencilMask = true;
|
||||
glStencilMask(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
bool restoreDepthMask = false;
|
||||
if (masks & Framebuffer::BUFFER_DEPTH) {
|
||||
glClearDepthf(depth);
|
||||
glmask |= GL_DEPTH_BUFFER_BIT;
|
||||
|
||||
bool cacheDepthMask = _pipeline._stateCache.depthTest.getWriteMask();
|
||||
if (!cacheDepthMask) {
|
||||
restoreDepthMask = true;
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<GLenum> drawBuffers;
|
||||
if (masks & Framebuffer::BUFFER_COLORS) {
|
||||
if (_output._framebuffer) {
|
||||
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
|
||||
if (masks & (1 << i)) {
|
||||
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!drawBuffers.empty()) {
|
||||
glDrawBuffers((GLsizei)drawBuffers.size(), drawBuffers.data());
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
glmask |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
} else {
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
glmask |= GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
|
||||
// Force the color mask cache to WRITE_ALL if not the case
|
||||
do_setStateColorWriteMask(State::ColorMask::WRITE_ALL);
|
||||
}
|
||||
|
||||
// Apply scissor if needed and if not already on
|
||||
bool doEnableScissor = (useScissor && (!_pipeline._stateCache.scissorEnable));
|
||||
if (doEnableScissor) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
// Clear!
|
||||
glClear(glmask);
|
||||
|
||||
// Restore scissor if needed
|
||||
if (doEnableScissor) {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
// Restore Stencil write mask
|
||||
if (restoreStencilMask) {
|
||||
glStencilMask(cacheStencilMask);
|
||||
}
|
||||
|
||||
// Restore write mask meaning turn back off
|
||||
if (restoreDepthMask) {
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
|
||||
// Restore the color draw buffers only if a frmaebuffer is bound
|
||||
if (_output._framebuffer && !drawBuffers.empty()) {
|
||||
auto glFramebuffer = syncGPUObject(*_output._framebuffer);
|
||||
if (glFramebuffer) {
|
||||
glDrawBuffers((GLsizei)glFramebuffer->_colorBuffers.size(), glFramebuffer->_colorBuffers.data());
|
||||
}
|
||||
}
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) {
|
||||
auto readFBO = getFramebufferID(srcFramebuffer);
|
||||
if (srcFramebuffer && readFBO) {
|
||||
if ((srcFramebuffer->getWidth() < (region.x + region.z)) || (srcFramebuffer->getHeight() < (region.y + region.w))) {
|
||||
qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : srcFramebuffer is too small to provide the region queried";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((destImage.width() < region.z) || (destImage.height() < region.w)) {
|
||||
qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : destImage is too small to receive the region of the framebuffer";
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
if (destImage.format() != QImage::Format_ARGB32) {
|
||||
qCWarning(gpugllogging) << "GLBackend::downloadFramebuffer : destImage format must be FORMAT_ARGB32 to receive the region of the framebuffer";
|
||||
return;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, getFramebufferID(srcFramebuffer));
|
||||
glReadPixels(region.x, region.y, region.z, region.w, format, GL_UNSIGNED_BYTE, destImage.bits());
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
|
@ -1,316 +0,0 @@
|
|||
//
|
||||
// GLBackendPipeline.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLShared.h"
|
||||
#include "GLPipeline.h"
|
||||
#include "GLShader.h"
|
||||
#include "GLState.h"
|
||||
#include "GLBuffer.h"
|
||||
#include "GLTexture.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
||||
PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (_pipeline._pipeline == pipeline) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A true new Pipeline
|
||||
_stats._PSNumSetPipelines++;
|
||||
|
||||
// null pipeline == reset
|
||||
if (!pipeline) {
|
||||
_pipeline._pipeline.reset();
|
||||
|
||||
_pipeline._program = 0;
|
||||
_pipeline._cameraCorrectionLocation = -1;
|
||||
_pipeline._programShader = nullptr;
|
||||
_pipeline._invalidProgram = true;
|
||||
|
||||
_pipeline._state = nullptr;
|
||||
_pipeline._invalidState = true;
|
||||
} else {
|
||||
auto pipelineObject = GLPipeline::sync(*this, *pipeline);
|
||||
if (!pipelineObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check the program cache
|
||||
// pick the program version
|
||||
// check the program cache
|
||||
// pick the program version
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
GLuint glprogram = pipelineObject->_program->getProgram((GLShader::Version) isStereo());
|
||||
#else
|
||||
GLuint glprogram = pipelineObject->_program->getProgram();
|
||||
#endif
|
||||
|
||||
if (_pipeline._program != glprogram) {
|
||||
_pipeline._program = glprogram;
|
||||
_pipeline._programShader = pipelineObject->_program;
|
||||
_pipeline._invalidProgram = true;
|
||||
_pipeline._cameraCorrectionLocation = pipelineObject->_cameraCorrection;
|
||||
}
|
||||
|
||||
// Now for the state
|
||||
if (_pipeline._state != pipelineObject->_state) {
|
||||
_pipeline._state = pipelineObject->_state;
|
||||
_pipeline._invalidState = true;
|
||||
}
|
||||
|
||||
// Remember the new pipeline
|
||||
_pipeline._pipeline = pipeline;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection));
|
||||
}
|
||||
(void) CHECK_GL_ERROR();
|
||||
_pipeline._invalidProgram = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::updatePipeline() {
|
||||
if (_pipeline._invalidProgram) {
|
||||
// doing it here is aproblem for calls to glUniform.... so will do it on assing...
|
||||
glUseProgram(_pipeline._program);
|
||||
(void) CHECK_GL_ERROR();
|
||||
_pipeline._invalidProgram = false;
|
||||
}
|
||||
|
||||
if (_pipeline._invalidState) {
|
||||
if (_pipeline._state) {
|
||||
// first reset to default what should be
|
||||
// the fields which were not to default and are default now
|
||||
resetPipelineState(_pipeline._state->_signature);
|
||||
|
||||
// Update the signature cache with what's going to be touched
|
||||
_pipeline._stateSignatureCache |= _pipeline._state->_signature;
|
||||
|
||||
// And perform
|
||||
for (auto command: _pipeline._state->_commands) {
|
||||
command->run(this);
|
||||
}
|
||||
} else {
|
||||
// No state ? anyway just reset everything
|
||||
resetPipelineState(0);
|
||||
}
|
||||
_pipeline._invalidState = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::resetPipelineStage() {
|
||||
// First reset State to default
|
||||
State::Signature resetSignature(0);
|
||||
resetPipelineState(resetSignature);
|
||||
_pipeline._state = nullptr;
|
||||
_pipeline._invalidState = false;
|
||||
|
||||
// Second the shader side
|
||||
_pipeline._invalidProgram = false;
|
||||
_pipeline._program = 0;
|
||||
_pipeline._programShader = nullptr;
|
||||
_pipeline._pipeline.reset();
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void GLBackend::releaseUniformBuffer(uint32_t slot) {
|
||||
auto& buf = _uniform._buffers[slot];
|
||||
if (buf) {
|
||||
auto* object = Backend::getGPUObject<GLBuffer>(*buf);
|
||||
if (object) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, slot, 0); // RELEASE
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
buf.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::resetUniformStage() {
|
||||
for (uint32_t i = 0; i < _uniform._buffers.size(); i++) {
|
||||
releaseUniformBuffer(i);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 3]._uint;
|
||||
if (slot >(GLuint)MAX_NUM_UNIFORM_BUFFERS) {
|
||||
qCDebug(gpugllogging) << "GLBackend::do_setUniformBuffer: Trying to set a uniform Buffer at slot #" << slot << " 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;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::releaseResourceTexture(uint32_t slot) {
|
||||
auto& tex = _resource._textures[slot];
|
||||
if (tex) {
|
||||
auto* object = Backend::getGPUObject<GLTexture>(*tex);
|
||||
if (object) {
|
||||
GLuint target = object->_target;
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(target, 0); // RELEASE
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
tex.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::resetResourceStage() {
|
||||
for (uint32_t i = 0; i < _resource._buffers.size(); i++) {
|
||||
releaseResourceBuffer(i);
|
||||
}
|
||||
for (uint32_t i = 0; i < _resource._textures.size(); i++) {
|
||||
releaseResourceTexture(i);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setResourceBuffer(const Batch& batch, size_t paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
if (slot >= (GLuint)MAX_NUM_RESOURCE_BUFFERS) {
|
||||
qCDebug(gpugllogging) << "GLBackend::do_setResourceBuffer: Trying to set a resource Buffer at slot #" << slot << " which doesn't exist. MaxNumResourceBuffers = " << getMaxNumResourceBuffers();
|
||||
return;
|
||||
}
|
||||
|
||||
auto resourceBuffer = batch._buffers.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (!resourceBuffer) {
|
||||
releaseResourceBuffer(slot);
|
||||
return;
|
||||
}
|
||||
// check cache before thinking
|
||||
if (_resource._buffers[slot] == resourceBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// One more True Buffer bound
|
||||
_stats._RSNumResourceBufferBounded++;
|
||||
|
||||
// If successful bind then cache it
|
||||
if (bindResourceBuffer(slot, resourceBuffer)) {
|
||||
_resource._buffers[slot] = resourceBuffer;
|
||||
} else { // else clear slot and cache
|
||||
releaseResourceBuffer(slot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
if (slot >= (GLuint) MAX_NUM_RESOURCE_TEXTURES) {
|
||||
qCDebug(gpugllogging) << "GLBackend::do_setResourceTexture: Trying to set a resource Texture at slot #" << slot << " which doesn't exist. MaxNumResourceTextures = " << getMaxNumResourceTextures();
|
||||
return;
|
||||
}
|
||||
|
||||
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (!resourceTexture) {
|
||||
releaseResourceTexture(slot);
|
||||
return;
|
||||
}
|
||||
setResourceTexture(slot, resourceTexture);
|
||||
}
|
||||
|
||||
void GLBackend::do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) {
|
||||
GLuint slot = batch._params[paramOffset + 1]._uint;
|
||||
if (slot >= (GLuint)MAX_NUM_RESOURCE_TEXTURES) {
|
||||
qCDebug(gpugllogging) << "GLBackend::do_setResourceFramebufferSwapChainTexture: Trying to set a resource Texture at slot #" << slot << " which doesn't exist. MaxNumResourceTextures = " << getMaxNumResourceTextures();
|
||||
return;
|
||||
}
|
||||
|
||||
SwapChainPointer swapChain = batch._swapChains.get(batch._params[paramOffset + 0]._uint);
|
||||
|
||||
if (!swapChain) {
|
||||
releaseResourceTexture(slot);
|
||||
return;
|
||||
}
|
||||
auto index = batch._params[paramOffset + 2]._uint;
|
||||
auto renderBufferSlot = batch._params[paramOffset + 3]._uint;
|
||||
FramebufferPointer resourceFramebuffer = static_cast<const FramebufferSwapChain*>(swapChain.get())->get(index);
|
||||
TexturePointer resourceTexture = resourceFramebuffer->getRenderBuffer(renderBufferSlot);
|
||||
|
||||
setResourceTexture(slot, resourceTexture);
|
||||
}
|
||||
|
||||
void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& resourceTexture) {
|
||||
// check cache before thinking
|
||||
if (_resource._textures[slot] == resourceTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
// One more True texture bound
|
||||
_stats._RSNumTextureBounded++;
|
||||
|
||||
// Always make sure the GLObject is in sync
|
||||
GLTexture* object = syncGPUObject(resourceTexture);
|
||||
if (object) {
|
||||
GLuint to = object->_texture;
|
||||
GLuint target = object->_target;
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(target, to);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_resource._textures[slot] = resourceTexture;
|
||||
|
||||
_stats._RSAmountTextureMemoryBounded += (int)object->size();
|
||||
|
||||
} else {
|
||||
releaseResourceTexture(slot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
|
||||
// start from the end of the slots, try to find an empty one that can be used
|
||||
for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {
|
||||
if (!_textures[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
//
|
||||
// GLBackendQuery.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 7/7/2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLQuery.h"
|
||||
#include "GLShared.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
// Eventually, we want to test with TIME_ELAPSED instead of TIMESTAMP
|
||||
#ifdef Q_OS_MAC
|
||||
//const uint32_t MAX_RANGE_QUERY_DEPTH = 1;
|
||||
static bool timeElapsed = true;
|
||||
#else
|
||||
//const uint32_t MAX_RANGE_QUERY_DEPTH = 10000;
|
||||
static bool timeElapsed = false;
|
||||
#endif
|
||||
|
||||
void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
//glGetInteger64v(GL_TIMESTAMP_EXT, (GLint64*)&glquery->_batchElapsedTime);
|
||||
glquery->_batchElapsedTime = 1;
|
||||
if (timeElapsed) {
|
||||
glBeginQuery(GL_TIME_ELAPSED_EXT, glquery->_endqo);
|
||||
} else {
|
||||
if (glQueryCounterEXT != NULL) {
|
||||
glQueryCounterEXT(glquery->_beginqo, GL_TIMESTAMP_EXT);
|
||||
}
|
||||
}
|
||||
glquery->_rangeQueryDepth = _queryStage._rangeQueryDepth;
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
if (timeElapsed) {
|
||||
glEndQuery(GL_TIME_ELAPSED_EXT);
|
||||
} else {
|
||||
if (glQueryCounterEXT != NULL) {
|
||||
glQueryCounterEXT(glquery->_endqo, GL_TIMESTAMP_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
--_queryStage._rangeQueryDepth;
|
||||
GLint64 now;
|
||||
//glGetInteger64v(GL_TIMESTAMP_EXT, &now);
|
||||
//glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
|
||||
now = 1;
|
||||
glquery->_batchElapsedTime = 1;
|
||||
|
||||
PROFILE_RANGE_END(render_gpu_gl, glquery->_profileRangeId);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::do_getQuery(const Batch& batch, size_t paramOffset) {
|
||||
#if !defined(USE_GLES)
|
||||
auto query = batch._queries.get(batch._params[paramOffset]._uint);
|
||||
if (glGetQueryObjectui64vEXT == NULL)
|
||||
return;
|
||||
GLQuery* glquery = syncGPUObject(*query);
|
||||
if (glquery) {
|
||||
glGetQueryObjectui64vEXT(glquery->_endqo, GL_QUERY_RESULT_AVAILABLE, &glquery->_result);
|
||||
if (glquery->_result == GL_TRUE) {
|
||||
if (timeElapsed) {
|
||||
glGetQueryObjectui64vEXT(glquery->_endqo, GL_QUERY_RESULT, &glquery->_result);
|
||||
} else {
|
||||
GLuint64 start, end;
|
||||
glGetQueryObjectui64vEXT(glquery->_beginqo, GL_QUERY_RESULT, &start);
|
||||
glGetQueryObjectui64vEXT(glquery->_endqo, GL_QUERY_RESULT, &end);
|
||||
glquery->_result = end - start;
|
||||
}
|
||||
query->triggerReturnHandler(glquery->_result, glquery->_batchElapsedTime);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLBackend::resetQueryStage() {
|
||||
}
|
|
@ -1,583 +0,0 @@
|
|||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on 2017/12/28
|
||||
// Copyright 2013-2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLShader.h"
|
||||
#include <gl/GLShaders.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
// GLSL version
|
||||
std::string GLBackend::getBackendShaderHeader() const {
|
||||
return std::string("#version 310 es");
|
||||
}
|
||||
|
||||
// Shader domain
|
||||
static const size_t NUM_SHADER_DOMAINS = 2;
|
||||
|
||||
// GL Shader type enums
|
||||
// Must match the order of type specified in gpu::Shader::Type
|
||||
static const std::array<GLenum, NUM_SHADER_DOMAINS> SHADER_DOMAINS{ {
|
||||
GL_VERTEX_SHADER,
|
||||
GL_FRAGMENT_SHADER,
|
||||
// GL_GEOMETRY_SHADER,
|
||||
} };
|
||||
|
||||
// Domain specific defines
|
||||
// Must match the order of type specified in gpu::Shader::Type
|
||||
static const std::array<std::string, NUM_SHADER_DOMAINS> DOMAIN_DEFINES{ {
|
||||
"#define GPU_VERTEX_SHADER",
|
||||
"#define GPU_PIXEL_SHADER",
|
||||
// "#define GPU_GEOMETRY_SHADER",
|
||||
} };
|
||||
|
||||
// Stereo specific defines
|
||||
static const std::string stereoVersion{
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
"#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED\n#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN"
|
||||
#endif
|
||||
#ifdef GPU_STEREO_DRAWCALL_DOUBLED
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
"#define GPU_TRANSFORM_IS_STEREO\n#define GPU_TRANSFORM_STEREO_CAMERA\n#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED"
|
||||
#else
|
||||
"#define GPU_TRANSFORM_IS_STEREO"
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
// Versions specific of the shader
|
||||
static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
|
||||
"",
|
||||
stereoVersion
|
||||
} };
|
||||
|
||||
GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||
// Any GLSLprogram ? normally yes...
|
||||
const std::string& shaderSource = shader.getSource().getCode();
|
||||
GLenum shaderDomain = SHADER_DOMAINS[shader.getType()];
|
||||
GLShader::ShaderObjects shaderObjects;
|
||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||
|
||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& shaderObject = shaderObjects[version];
|
||||
|
||||
std::string shaderDefines = getBackendShaderHeader() + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version]
|
||||
+ "\n#extension GL_EXT_texture_buffer : enable"
|
||||
+ "\nprecision lowp float; // check precision 2"
|
||||
+ "\nprecision lowp samplerBuffer;"
|
||||
+ "\nprecision lowp sampler2DShadow;";
|
||||
if (handler) {
|
||||
bool retest = true;
|
||||
std::string currentSrc = shaderSource;
|
||||
// When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails.
|
||||
// The retest bool is set to false as soon as the compilation succeed to wexit the while loop.
|
||||
// The handler tells us if we should retry or not while returning a modified version of the source.
|
||||
while (retest) {
|
||||
bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
||||
compilationLogs[version].compiled = result;
|
||||
if (!result) {
|
||||
std::string newSrc;
|
||||
retest = handler(shader, currentSrc, compilationLogs[version], newSrc);
|
||||
currentSrc = newSrc;
|
||||
} else {
|
||||
retest = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
|
||||
}
|
||||
|
||||
if (!compilationLogs[version].compiled) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
|
||||
shader.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Compilation feedback
|
||||
shader.setCompilationLogs(compilationLogs);
|
||||
|
||||
// So far so good, the shader is created successfully
|
||||
GLShader* object = new GLShader(this->shared_from_this());
|
||||
object->_shaderObjects = shaderObjects;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler) {
|
||||
if (!program.isProgram()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLShader::ShaderObjects programObjects;
|
||||
|
||||
Shader::CompilationLogs compilationLogs(GLShader::NumVersions);
|
||||
|
||||
for (int version = 0; version < GLShader::NumVersions; version++) {
|
||||
auto& programObject = programObjects[version];
|
||||
|
||||
// Let's go through every shaders and make sure they are ready to go
|
||||
std::vector< GLuint > shaderGLObjects;
|
||||
for (auto subShader : program.getShaders()) {
|
||||
auto object = GLShader::sync((*this), *subShader, handler);
|
||||
if (object) {
|
||||
shaderGLObjects.push_back(object->_shaderObjects[version].glshader);
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?";
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint glprogram = ::gl::compileProgram(shaderGLObjects, compilationLogs[version].message, compilationLogs[version].binary);
|
||||
if (glprogram == 0) {
|
||||
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
programObject.glprogram = glprogram;
|
||||
|
||||
makeProgramBindings(programObject);
|
||||
}
|
||||
// Compilation feedback
|
||||
program.setCompilationLogs(compilationLogs);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
GLBackend::ElementResource GLBackend::getFormatFromGLUniform(GLenum gltype) {
|
||||
switch (gltype) {
|
||||
case GL_FLOAT:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_INT:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_INT_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_UNSIGNED_INT:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_BOOL:
|
||||
return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC2:
|
||||
return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC3:
|
||||
return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
case GL_BOOL_VEC4:
|
||||
return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
|
||||
|
||||
case GL_FLOAT_MAT2:
|
||||
return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT3:
|
||||
return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_FLOAT_MAT4:
|
||||
return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
|
||||
//{GL_FLOAT_MAT2x3 mat2x3},
|
||||
//{GL_FLOAT_MAT2x4 mat2x4},
|
||||
//{GL_FLOAT_MAT3x2 mat3x2},
|
||||
//{GL_FLOAT_MAT3x4 mat3x4},
|
||||
//{GL_FLOAT_MAT4x2 mat4x2},
|
||||
//{GL_FLOAT_MAT4x3 mat4x3},
|
||||
//{GL_DOUBLE_MAT2 dmat2},
|
||||
//{GL_DOUBLE_MAT3 dmat3},
|
||||
//{GL_DOUBLE_MAT4 dmat4},
|
||||
//{GL_DOUBLE_MAT2x3 dmat2x3},
|
||||
//{GL_DOUBLE_MAT2x4 dmat2x4},
|
||||
//{GL_DOUBLE_MAT3x2 dmat3x2},
|
||||
//{GL_DOUBLE_MAT3x4 dmat3x4},
|
||||
//{GL_DOUBLE_MAT4x2 dmat4x2},
|
||||
//{GL_DOUBLE_MAT4x3 dmat4x3},
|
||||
|
||||
case GL_SAMPLER_2D:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
|
||||
|
||||
case GL_SAMPLER_3D:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_SAMPLER_CUBE:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
// {GL_SAMPLER_1D_SHADOW sampler1DShadow},
|
||||
// {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
|
||||
|
||||
case GL_SAMPLER_BUFFER:
|
||||
return ElementResource(Element(SCALAR, gpu::FLOAT, RESOURCE_BUFFER), Resource::BUFFER);
|
||||
|
||||
// {GL_SAMPLER_2D_RECT sampler2DRect},
|
||||
// {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
|
||||
|
||||
case GL_INT_SAMPLER_2D:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_INT_SAMPLER_3D:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_INT_SAMPLER_CUBE:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_INT_SAMPLER_2D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
|
||||
// {GL_INT_SAMPLER_BUFFER isamplerBuffer},
|
||||
// {GL_INT_SAMPLER_2D_RECT isampler2DRect},
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
|
||||
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
|
||||
//{GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
|
||||
//{GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
|
||||
|
||||
//{GL_IMAGE_1D image1D},
|
||||
//{GL_IMAGE_2D image2D},
|
||||
//{GL_IMAGE_3D image3D},
|
||||
//{GL_IMAGE_2D_RECT image2DRect},
|
||||
//{GL_IMAGE_CUBE imageCube},
|
||||
//{GL_IMAGE_BUFFER imageBuffer},
|
||||
//{GL_IMAGE_1D_ARRAY image1DArray},
|
||||
//{GL_IMAGE_2D_ARRAY image2DArray},
|
||||
//{GL_IMAGE_2D_MULTISAMPLE image2DMS},
|
||||
//{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
|
||||
//{GL_INT_IMAGE_1D iimage1D},
|
||||
//{GL_INT_IMAGE_2D iimage2D},
|
||||
//{GL_INT_IMAGE_3D iimage3D},
|
||||
//{GL_INT_IMAGE_2D_RECT iimage2DRect},
|
||||
//{GL_INT_IMAGE_CUBE iimageCube},
|
||||
//{GL_INT_IMAGE_BUFFER iimageBuffer},
|
||||
//{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
|
||||
//{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
|
||||
//{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
|
||||
//{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
|
||||
//{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
|
||||
//{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
|
||||
//{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot
|
||||
|
||||
//{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
|
||||
//{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
|
||||
//{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
|
||||
//{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
|
||||
#if 0
|
||||
case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
|
||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
|
||||
case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return ElementResource(Element(), Resource::BUFFER);
|
||||
}
|
||||
};
|
||||
|
||||
int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
|
||||
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) {
|
||||
GLint uniformsCount = 0;
|
||||
|
||||
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
|
||||
|
||||
for (int i = 0; i < uniformsCount; i++) {
|
||||
const GLint NAME_LENGTH = 256;
|
||||
GLchar name[NAME_LENGTH];
|
||||
GLint length = 0;
|
||||
GLint size = 0;
|
||||
GLenum type = 0;
|
||||
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
|
||||
GLint location = glGetUniformLocation(glprogram, 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) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
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 uniformsCount;
|
||||
}
|
||||
|
||||
int GLBackend::makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
|
||||
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(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
|
||||
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(GLuint glprogram, 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;
|
||||
}
|
||||
GLuint glprogram = shaderObject.glprogram;
|
||||
GLint loc = -1;
|
||||
|
||||
//Check for gpu specific attribute slotBindings
|
||||
loc = glGetAttribLocation(glprogram, "inPosition");
|
||||
if (loc >= 0 && loc != gpu::Stream::POSITION) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inNormal");
|
||||
if (loc >= 0 && loc != gpu::Stream::NORMAL) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inColor");
|
||||
if (loc >= 0 && loc != gpu::Stream::COLOR) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inTexCoord0");
|
||||
if (loc >= 0 && loc != gpu::Stream::TEXCOORD) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inTangent");
|
||||
if (loc >= 0 && loc != gpu::Stream::TANGENT) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
|
||||
}
|
||||
|
||||
char attribName[] = "inTexCoordn";
|
||||
for (auto i = 0; i < 4; i++) {
|
||||
auto streamId = gpu::Stream::TEXCOORD1 + i;
|
||||
|
||||
attribName[strlen(attribName) - 1] = '1' + i;
|
||||
loc = glGetAttribLocation(glprogram, attribName);
|
||||
if (loc >= 0 && loc != streamId) {
|
||||
glBindAttribLocation(glprogram, streamId, attribName);
|
||||
}
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");
|
||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "inSkinClusterWeight");
|
||||
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
|
||||
}
|
||||
|
||||
loc = glGetAttribLocation(glprogram, "_drawCallInfo");
|
||||
if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) {
|
||||
glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo");
|
||||
}
|
||||
|
||||
// Link again to take into account the assigned attrib location
|
||||
glLinkProgram(glprogram);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
|
||||
if (!linked) {
|
||||
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
|
||||
}
|
||||
}
|
|
@ -1,334 +0,0 @@
|
|||
//
|
||||
// GLBackendState.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/22/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLState.h"
|
||||
|
||||
#include <gpu/GPULogging.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
void GLBackend::resetPipelineState(State::Signature nextSignature) {
|
||||
auto currentNotSignature = ~_pipeline._stateSignatureCache;
|
||||
auto nextNotSignature = ~nextSignature;
|
||||
auto fieldsToBeReset = currentNotSignature ^ (currentNotSignature | nextNotSignature);
|
||||
if (fieldsToBeReset.any()) {
|
||||
for (auto i = 0; i < State::NUM_FIELDS; i++) {
|
||||
if (fieldsToBeReset[i]) {
|
||||
GLState::_resetStateCommands[i]->run(this);
|
||||
_pipeline._stateSignatureCache.reset(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::syncPipelineStateCache() {
|
||||
State::Data state;
|
||||
|
||||
//glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
qDebug() << "TODO: GLBackendState.cpp:syncPipelineStateCache GL_TEXTURE_CUBE_MAP_SEAMLESS";
|
||||
|
||||
// Point size is always on
|
||||
// FIXME CORE
|
||||
//glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
||||
//glEnable(GL_PROGRAM_POINT_SIZE_EXT);
|
||||
qDebug() << "TODO: GLBackendState.cpp:syncPipelineStateCache GL_PROGRAM_POINT_SIZE_EXT";
|
||||
|
||||
//glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
qDebug() << "TODO: GLBackendState.cpp:syncPipelineStateCache GL_VERTEX_PROGRAM_POINT_SIZE";
|
||||
|
||||
// Default line width accross the board
|
||||
glLineWidth(1.0f);
|
||||
|
||||
getCurrentGLState(state);
|
||||
State::Signature signature = State::evalSignature(state);
|
||||
|
||||
_pipeline._stateCache = state;
|
||||
_pipeline._stateSignatureCache = signature;
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_setStateFillMode(int32 mode) {
|
||||
if (_pipeline._stateCache.fillMode != mode) {
|
||||
//static GLenum GL_FILL_MODES[] = { /*GL_POINT, GL_LINE, GL_FILL*/ };
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL_MODES[mode]);
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_POINT";
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_LINE";
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode GL_FILL";
|
||||
qDebug() << "TODO: GLBackendState.cpp:do_setStateFillMode glPolygonMode";
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.fillMode = State::FillMode(mode);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateCullMode(int32 mode) {
|
||||
if (_pipeline._stateCache.cullMode != mode) {
|
||||
static GLenum GL_CULL_MODES[] = { GL_FRONT_AND_BACK, GL_FRONT, GL_BACK };
|
||||
if (mode == State::CULL_NONE) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
glCullFace(GL_FRONT_AND_BACK);
|
||||
} else {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_CULL_MODES[mode]);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.cullMode = State::CullMode(mode);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateFrontFaceClockwise(bool isClockwise) {
|
||||
if (_pipeline._stateCache.frontFaceClockwise != isClockwise) {
|
||||
static GLenum GL_FRONT_FACES[] = { GL_CCW, GL_CW };
|
||||
glFrontFace(GL_FRONT_FACES[isClockwise]);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.frontFaceClockwise = isClockwise;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateDepthClampEnable(bool enable) {
|
||||
if (_pipeline._stateCache.depthClampEnable != enable) {
|
||||
//if (enable) {
|
||||
// glEnable(GL_DEPTH_CLAMP);
|
||||
//} else {
|
||||
// glDisable(GL_DEPTH_CLAMP);
|
||||
//}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.depthClampEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateScissorEnable(bool enable) {
|
||||
if (_pipeline._stateCache.scissorEnable != enable) {
|
||||
if (enable) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.scissorEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateMultisampleEnable(bool enable) {
|
||||
if (_pipeline._stateCache.multisampleEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
} else {
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
#endif
|
||||
|
||||
_pipeline._stateCache.multisampleEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
|
||||
if (_pipeline._stateCache.antialisedLineEnable != enable) {
|
||||
#if !defined(USE_GLES)
|
||||
if (enable) {
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
} else {
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
#endif
|
||||
|
||||
_pipeline._stateCache.antialisedLineEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateDepthBias(Vec2 bias) {
|
||||
if ((bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) {
|
||||
if ((bias.x != 0.0f) || (bias.y != 0.0f)) {
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
#if !defined(USE_GLES)
|
||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
glEnable(GL_POLYGON_OFFSET_POINT);
|
||||
#endif
|
||||
glPolygonOffset(bias.x, bias.y);
|
||||
} else {
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
#if !defined(USE_GLES)
|
||||
glDisable(GL_POLYGON_OFFSET_LINE);
|
||||
glDisable(GL_POLYGON_OFFSET_POINT);
|
||||
#endif
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.depthBias = bias.x;
|
||||
_pipeline._stateCache.depthBiasSlopeScale = bias.y;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateDepthTest(State::DepthTest test) {
|
||||
const auto& current = _pipeline._stateCache.depthTest;
|
||||
if (current != test) {
|
||||
if (test.isEnabled()) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
if (test.getWriteMask() != current.getWriteMask()) {
|
||||
glDepthMask(test.getWriteMask());
|
||||
}
|
||||
if (test.getFunction() != current.getFunction()) {
|
||||
glDepthFunc(COMPARISON_TO_GL[test.getFunction()]);
|
||||
}
|
||||
if (CHECK_GL_ERROR()) {
|
||||
qCDebug(gpulogging) << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled")
|
||||
<< "Mask=" << (test.getWriteMask() ? "Write" : "no Write")
|
||||
<< "Func=" << test.getFunction()
|
||||
<< "Raw=" << test.getRaw();
|
||||
}
|
||||
_pipeline._stateCache.depthTest = test;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest testFront, State::StencilTest testBack) {
|
||||
const auto& currentActivation = _pipeline._stateCache.stencilActivation;
|
||||
const auto& currentTestFront = _pipeline._stateCache.stencilTestFront;
|
||||
const auto& currentTestBack = _pipeline._stateCache.stencilTestBack;
|
||||
if ((currentActivation != activation)
|
||||
|| (currentTestFront != testFront)
|
||||
|| (currentTestBack != testBack)) {
|
||||
|
||||
if (activation.isEnabled()) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
} else {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) {
|
||||
glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront());
|
||||
glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack());
|
||||
} else {
|
||||
glStencilMask(activation.getWriteMaskFront());
|
||||
}
|
||||
|
||||
static GLenum STENCIL_OPS[State::NUM_STENCIL_OPS] = {
|
||||
GL_KEEP,
|
||||
GL_ZERO,
|
||||
GL_REPLACE,
|
||||
GL_INCR_WRAP,
|
||||
GL_DECR_WRAP,
|
||||
GL_INVERT,
|
||||
GL_INCR,
|
||||
GL_DECR };
|
||||
|
||||
if (testFront != testBack) {
|
||||
glStencilOpSeparate(GL_FRONT, STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]);
|
||||
glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask());
|
||||
|
||||
glStencilOpSeparate(GL_BACK, STENCIL_OPS[testBack.getFailOp()], STENCIL_OPS[testBack.getDepthFailOp()], STENCIL_OPS[testBack.getPassOp()]);
|
||||
glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[testBack.getFunction()], testBack.getReference(), testBack.getReadMask());
|
||||
} else {
|
||||
glStencilOp(STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getDepthFailOp()], STENCIL_OPS[testFront.getPassOp()]);
|
||||
glStencilFunc(COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask());
|
||||
}
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.stencilActivation = activation;
|
||||
_pipeline._stateCache.stencilTestFront = testFront;
|
||||
_pipeline._stateCache.stencilTestBack = testBack;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateAlphaToCoverageEnable(bool enable) {
|
||||
if (_pipeline._stateCache.alphaToCoverageEnable != enable) {
|
||||
if (enable) {
|
||||
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
} else {
|
||||
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.alphaToCoverageEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateSampleMask(uint32 mask) {
|
||||
if (_pipeline._stateCache.sampleMask != mask) {
|
||||
if (mask == 0xFFFFFFFF) {
|
||||
glDisable(GL_SAMPLE_MASK);
|
||||
} else {
|
||||
glEnable(GL_SAMPLE_MASK);
|
||||
glSampleMaski(0, mask);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
_pipeline._stateCache.sampleMask = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateBlend(State::BlendFunction function) {
|
||||
if (_pipeline._stateCache.blendFunction != function) {
|
||||
if (function.isEnabled()) {
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glBlendEquationSeparate(BLEND_OPS_TO_GL[function.getOperationColor()], BLEND_OPS_TO_GL[function.getOperationAlpha()]);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
|
||||
glBlendFuncSeparate(BLEND_ARGS_TO_GL[function.getSourceColor()], BLEND_ARGS_TO_GL[function.getDestinationColor()],
|
||||
BLEND_ARGS_TO_GL[function.getSourceAlpha()], BLEND_ARGS_TO_GL[function.getDestinationAlpha()]);
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.blendFunction = function;
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateColorWriteMask(uint32 mask) {
|
||||
if (_pipeline._stateCache.colorWriteMask != mask) {
|
||||
glColorMask(mask & State::ColorMask::WRITE_RED,
|
||||
mask & State::ColorMask::WRITE_GREEN,
|
||||
mask & State::ColorMask::WRITE_BLUE,
|
||||
mask & State::ColorMask::WRITE_ALPHA);
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
_pipeline._stateCache.colorWriteMask = mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_setStateBlendFactor(const Batch& batch, size_t paramOffset) {
|
||||
Vec4 factor(batch._params[paramOffset + 0]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 3]._float);
|
||||
|
||||
glBlendColor(factor.x, factor.y, factor.z, factor.w);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::do_setStateScissorRect(const Batch& batch, size_t paramOffset) {
|
||||
Vec4i rect;
|
||||
memcpy(&rect, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
|
||||
if (_stereo._enable) {
|
||||
rect.z /= 2;
|
||||
if (_stereo._pass) {
|
||||
rect.x += rect.z;
|
||||
}
|
||||
}
|
||||
glScissor(rect.x, rect.y, rect.z, rect.w);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
//
|
||||
//
|
||||
// GLBackendTexture.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 1/19/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
#include "GLTexture.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
|
||||
GLuint GLBackend::getTextureID(const TexturePointer& texture) {
|
||||
GLTexture* object = syncGPUObject(texture);
|
||||
|
||||
if (!object) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return object->_id;
|
||||
}
|
||||
|
||||
GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePointer) {
|
||||
const Texture& texture = *texturePointer;
|
||||
// Special case external textures
|
||||
if (TextureUsageType::EXTERNAL == texture.getUsageType()) {
|
||||
Texture::ExternalUpdates updates = texture.getUpdates();
|
||||
if (!updates.empty()) {
|
||||
Texture::ExternalRecycler recycler = texture.getExternalRecycler();
|
||||
Q_ASSERT(recycler);
|
||||
// Discard any superfluous updates
|
||||
while (updates.size() > 1) {
|
||||
const auto& update = updates.front();
|
||||
// Superfluous updates will never have been read, but we want to ensure the previous
|
||||
// writes to them are complete before they're written again, so return them with the
|
||||
// same fences they arrived with. This can happen on any thread because no GL context
|
||||
// work is involved
|
||||
recycler(update.first, update.second);
|
||||
updates.pop_front();
|
||||
}
|
||||
|
||||
// The last texture remaining is the one we'll use to create the GLTexture
|
||||
const auto& update = updates.front();
|
||||
// Check for a fence, and if it exists, inject a wait into the command stream, then destroy the fence
|
||||
if (update.second) {
|
||||
GLsync fence = static_cast<GLsync>(update.second);
|
||||
glWaitSync(fence, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fence);
|
||||
}
|
||||
|
||||
// Create the new texture object (replaces any previous texture object)
|
||||
new GLExternalTexture(shared_from_this(), texture, update.first);
|
||||
}
|
||||
|
||||
// Return the texture object (if any) associated with the texture, without extensive logic
|
||||
// (external textures are
|
||||
return Backend::getGPUObject<GLTexture>(texture);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) {
|
||||
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
if (!resourceTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
// DO not transfer the texture, this call is expected for rendering texture
|
||||
GLTexture* object = syncGPUObject(resourceTexture);
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
object->generateMips();
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
//
|
||||
// GLBackendTransform.cpp
|
||||
// libraries/gpu/src/gpu
|
||||
//
|
||||
// Created by Sam Gateau on 3/8/2015.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
// Transform Stage
|
||||
void GLBackend::do_setModelTransform(const Batch& batch, size_t paramOffset) {
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewTransform(const Batch& batch, size_t paramOffset) {
|
||||
_transform._view = batch._transforms.get(batch._params[paramOffset]._uint);
|
||||
_transform._viewIsCamera = batch._params[paramOffset + 1]._uint != 0;
|
||||
_transform._invalidView = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setProjectionTransform(const Batch& batch, size_t paramOffset) {
|
||||
memcpy(&_transform._projection, batch.readData(batch._params[paramOffset]._uint), sizeof(Mat4));
|
||||
_transform._invalidProj = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewportTransform(const Batch& batch, size_t paramOffset) {
|
||||
memcpy(&_transform._viewport, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
|
||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
||||
{
|
||||
ivec4& vp = _transform._viewport;
|
||||
glViewport(vp.x, vp.y, vp.z, vp.w);
|
||||
|
||||
// Where we assign the GL viewport
|
||||
if (_stereo.isStereo()) {
|
||||
vp.z /= 2;
|
||||
if (_stereo._pass) {
|
||||
vp.x += vp.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!_inRenderTransferPass && !isStereo()) {
|
||||
ivec4& vp = _transform._viewport;
|
||||
glViewport(vp.x, vp.y, vp.z, vp.w);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The Viewport is tagged invalid because the CameraTransformUBO is not up to date and will need update on next drawcall
|
||||
_transform._invalidViewport = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setDepthRangeTransform(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
Vec2 depthRange(batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float);
|
||||
|
||||
if ((depthRange.x != _transform._depthRange.x) || (depthRange.y != _transform._depthRange.y)) {
|
||||
_transform._depthRange = depthRange;
|
||||
|
||||
glDepthRangef(depthRange.x, depthRange.y);
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::killTransform() {
|
||||
glDeleteBuffers(1, &_transform._objectBuffer);
|
||||
glDeleteBuffers(1, &_transform._cameraBuffer);
|
||||
glDeleteBuffers(1, &_transform._drawCallInfoBuffer);
|
||||
glDeleteTextures(1, &_transform._objectBufferTexture);
|
||||
}
|
||||
|
||||
void GLBackend::syncTransformStateCache() {
|
||||
_transform._invalidViewport = true;
|
||||
_transform._invalidProj = true;
|
||||
_transform._invalidView = true;
|
||||
|
||||
glGetIntegerv(GL_VIEWPORT, (GLint*) &_transform._viewport);
|
||||
|
||||
glGetFloatv(GL_DEPTH_RANGE, (GLfloat*)&_transform._depthRange);
|
||||
|
||||
Mat4 modelView;
|
||||
auto modelViewInv = glm::inverse(modelView);
|
||||
_transform._view.evalFromRawMatrix(modelViewInv);
|
||||
|
||||
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO);
|
||||
_transform._enabledDrawcallInfoBuffer = false;
|
||||
}
|
||||
|
||||
void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const StereoState& stereo) {
|
||||
// Check all the dirty flags and update the state accordingly
|
||||
if (_invalidViewport) {
|
||||
_camera._viewport = glm::vec4(_viewport);
|
||||
}
|
||||
|
||||
if (_invalidProj) {
|
||||
_camera._projection = _projection;
|
||||
}
|
||||
|
||||
if (_invalidView) {
|
||||
// Apply the correction
|
||||
if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) {
|
||||
// FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out?
|
||||
Transform result;
|
||||
_view.mult(result, _view, _correction.correctionInverse);
|
||||
if (_skybox) {
|
||||
result.setTranslation(vec3());
|
||||
}
|
||||
_view = result;
|
||||
}
|
||||
// This is when the _view matrix gets assigned
|
||||
_view.getInverseMatrix(_camera._view);
|
||||
}
|
||||
|
||||
if (_invalidView || _invalidProj || _invalidViewport) {
|
||||
size_t offset = _cameraUboSize * _cameras.size();
|
||||
_cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset));
|
||||
|
||||
if (stereo.isStereo()) {
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
_cameras.push_back(CameraBufferElement(_camera.getEyeCamera(0, stereo, _view), _camera.getEyeCamera(1, stereo, _view)));
|
||||
#else
|
||||
_cameras.push_back((_camera.getEyeCamera(0, stereo, _view)));
|
||||
_cameras.push_back((_camera.getEyeCamera(1, stereo, _view)));
|
||||
#endif
|
||||
} else {
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
_cameras.push_back(CameraBufferElement(_camera.recomputeDerived(_view)));
|
||||
#else
|
||||
_cameras.push_back((_camera.recomputeDerived(_view)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Flags are clean
|
||||
_invalidView = _invalidProj = _invalidViewport = false;
|
||||
}
|
||||
|
||||
void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const {
|
||||
size_t offset = INVALID_OFFSET;
|
||||
while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) {
|
||||
offset = (*_camerasItr).second;
|
||||
_currentCameraOffset = offset;
|
||||
++_camerasItr;
|
||||
}
|
||||
|
||||
if (offset != INVALID_OFFSET) {
|
||||
#ifdef GPU_STEREO_CAMERA_BUFFER
|
||||
bindCurrentCamera(0);
|
||||
#else
|
||||
if (!stereo.isStereo()) {
|
||||
bindCurrentCamera(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void GLBackend::TransformStageState::bindCurrentCamera(int eye) const {
|
||||
if (_currentCameraOffset != INVALID_OFFSET) {
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize, sizeof(CameraBufferElement));
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::resetTransformStage() {
|
||||
glDisableVertexAttribArray(gpu::Stream::DRAW_CALL_INFO);
|
||||
_transform._enabledDrawcallInfoBuffer = false;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on 09/27/2016
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GLBuffer.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLBuffer::~GLBuffer() {
|
||||
Backend::bufferCount.decrement();
|
||||
Backend::bufferGPUMemSize.update(_size, 0);
|
||||
|
||||
if (_id) {
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
backend->releaseBuffer(_id, _size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLBuffer::GLBuffer(const std::weak_ptr<GLBackend>& backend, const Buffer& buffer, GLuint id) :
|
||||
GLObject(backend, buffer, id),
|
||||
_size((GLuint)buffer._renderSysmem.getSize()),
|
||||
_stamp(buffer._renderSysmem.getStamp())
|
||||
{
|
||||
Backend::bufferCount.increment();
|
||||
Backend::bufferGPUMemSize.update(0, _size);
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLBuffer_h
|
||||
#define hifi_gpu_gl_GLBuffer_h
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLBuffer : public GLObject<Buffer> {
|
||||
public:
|
||||
template <typename GLBufferType>
|
||||
static GLBufferType* sync(GLBackend& backend, const Buffer& buffer) {
|
||||
if (buffer.getSysmem().getSize() != 0) {
|
||||
if (buffer._getUpdateCount == 0) {
|
||||
qWarning() << "Unsynced buffer";
|
||||
}
|
||||
if (buffer._getUpdateCount < buffer._applyUpdateCount) {
|
||||
qWarning() << "Unsynced buffer " << buffer._getUpdateCount << " " << buffer._applyUpdateCount;
|
||||
}
|
||||
}
|
||||
GLBufferType* object = Backend::getGPUObject<GLBufferType>(buffer);
|
||||
|
||||
// Has the storage size changed?
|
||||
if (!object || object->_stamp != buffer._renderSysmem.getStamp()) {
|
||||
object = new GLBufferType(backend.shared_from_this(), buffer, object);
|
||||
}
|
||||
|
||||
if (0 != (buffer._renderPages._flags & PageManager::DIRTY)) {
|
||||
object->transfer();
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
template <typename GLBufferType>
|
||||
static GLuint getId(GLBackend& backend, const Buffer& buffer) {
|
||||
GLBuffer* bo = sync<GLBufferType>(backend, buffer);
|
||||
if (bo) {
|
||||
return bo->_buffer;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const GLuint& _buffer { _id };
|
||||
const GLuint _size;
|
||||
const Stamp _stamp;
|
||||
|
||||
~GLBuffer();
|
||||
|
||||
virtual void transfer() = 0;
|
||||
|
||||
protected:
|
||||
GLBuffer(const std::weak_ptr<GLBackend>& backend, const Buffer& buffer, GLuint id);
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
56
libraries/gpu-gles/src/gpu/gl/GLESBackend.cpp
Normal file
56
libraries/gpu-gles/src/gpu/gl/GLESBackend.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// GLBackend.cpp
|
||||
// libraries/gpu-gl-android/src/gpu/gl
|
||||
//
|
||||
// Created by Cristian Duarte & Gabriel Calero on 9/21/2016.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
|
||||
#include <shared/GlobalAppProperties.h>
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/QOpenGLContextWrapper.h>
|
||||
#include <gpu/gl/GLShader.h>
|
||||
|
||||
#include "../gles/GLESBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
static GLBackend* INSTANCE{ nullptr };
|
||||
|
||||
BackendPointer GLBackend::createBackend() {
|
||||
// FIXME provide a mechanism to override the backend for testing
|
||||
// Where the gpuContext is initialized and where the TRUE Backend is created and assigned
|
||||
//auto version = QOpenGLContextWrapper::currentContextVersion();
|
||||
std::shared_ptr<GLBackend> result;
|
||||
|
||||
qDebug() << "Using OpenGL ES backend";
|
||||
result = std::make_shared<gpu::gles::GLESBackend>();
|
||||
|
||||
result->initInput();
|
||||
result->initTransform();
|
||||
result->initTextureManagementStage();
|
||||
|
||||
INSTANCE = result.get();
|
||||
void* voidInstance = &(*result);
|
||||
qApp->setProperty(hifi::properties::gl::BACKEND, QVariant::fromValue(voidInstance));
|
||||
return result;
|
||||
}
|
||||
|
||||
GLBackend& getBackend() {
|
||||
if (!INSTANCE) {
|
||||
INSTANCE = static_cast<GLBackend*>(qApp->property(hifi::properties::gl::BACKEND).value<void*>());
|
||||
}
|
||||
return *INSTANCE;
|
||||
}
|
||||
|
||||
bool GLBackend::makeProgram(Shader& shader, const Shader::BindingSet& slotBindings, const Shader::CompilationHandler& handler) {
|
||||
return GLShader::makeProgram(getBackend(), shader, slotBindings, handler);
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on 09/27/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GLFramebuffer.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLFramebuffer::~GLFramebuffer() {
|
||||
if (_id) {
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
backend->releaseFramebuffer(_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GLFramebuffer::checkStatus() const {
|
||||
switch (_status) {
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
// Success !
|
||||
return true;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT.";
|
||||
break;
|
||||
//case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
// qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.";
|
||||
// break;
|
||||
//case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
// qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER.";
|
||||
// break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
qCWarning(gpugllogging) << "GLFramebuffer::syncGPUObject : Framebuffer not valid, GL_FRAMEBUFFER_UNSUPPORTED.";
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on 09/27/2016
|
||||
// Copyright 2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLFramebuffer_h
|
||||
#define hifi_gpu_gl_GLFramebuffer_h
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLFramebuffer : public GLObject<Framebuffer> {
|
||||
public:
|
||||
template <typename GLFramebufferType>
|
||||
static GLFramebufferType* sync(GLBackend& backend, const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* object = Backend::getGPUObject<GLFramebufferType>(framebuffer);
|
||||
|
||||
bool needsUpate { false };
|
||||
if (!object ||
|
||||
framebuffer.getDepthStamp() != object->_depthStamp ||
|
||||
framebuffer.getColorStamps() != object->_colorStamps) {
|
||||
needsUpate = true;
|
||||
}
|
||||
|
||||
// If GPU object already created and in sync
|
||||
if (!needsUpate) {
|
||||
return object;
|
||||
} else if (framebuffer.isEmpty()) {
|
||||
// NO framebuffer definition yet so let's avoid thinking
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
// All is green, assign the gpuobject to the Framebuffer
|
||||
object = new GLFramebufferType(backend.shared_from_this(), framebuffer);
|
||||
Backend::setGPUObject(framebuffer, object);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
object->update();
|
||||
return object;
|
||||
}
|
||||
|
||||
template <typename GLFramebufferType>
|
||||
static GLuint getId(GLBackend& backend, const Framebuffer& framebuffer) {
|
||||
GLFramebufferType* fbo = sync<GLFramebufferType>(backend, framebuffer);
|
||||
if (fbo) {
|
||||
return fbo->_id;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const GLuint& _fbo { _id };
|
||||
std::vector<GLenum> _colorBuffers;
|
||||
Stamp _depthStamp { 0 };
|
||||
std::vector<Stamp> _colorStamps;
|
||||
|
||||
protected:
|
||||
GLenum _status { GL_FRAMEBUFFER_COMPLETE };
|
||||
virtual void update() = 0;
|
||||
bool checkStatus() const;
|
||||
|
||||
GLFramebuffer(const std::weak_ptr<GLBackend>& backend, const Framebuffer& framebuffer, GLuint id) : GLObject(backend, framebuffer, id) {}
|
||||
~GLFramebuffer();
|
||||
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
#endif
|
|
@ -1,33 +0,0 @@
|
|||
//
|
||||
// Created by Sam Gateau on 2016/07/21
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GLInputFormat.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
|
||||
GLInputFormat::GLInputFormat() {
|
||||
}
|
||||
|
||||
GLInputFormat:: ~GLInputFormat() {
|
||||
|
||||
}
|
||||
|
||||
GLInputFormat* GLInputFormat::sync(const Stream::Format& inputFormat) {
|
||||
GLInputFormat* object = Backend::getGPUObject<GLInputFormat>(inputFormat);
|
||||
|
||||
if (!object) {
|
||||
object = new GLInputFormat();
|
||||
object->key = inputFormat.getKey();
|
||||
Backend::setGPUObject(inputFormat, object);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// Created by Sam Gateau on 2016/07/21
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLInputFormat_h
|
||||
#define hifi_gpu_gl_GLInputFormat_h
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
namespace gpu {
|
||||
namespace gl {
|
||||
|
||||
class GLInputFormat : public GPUObject {
|
||||
public:
|
||||
static GLInputFormat* sync(const Stream::Format& inputFormat);
|
||||
|
||||
GLInputFormat();
|
||||
~GLInputFormat();
|
||||
|
||||
std::string key;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,59 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GLPipeline.h"
|
||||
|
||||
#include "GLShader.h"
|
||||
#include "GLState.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) {
|
||||
GLPipeline* object = Backend::getGPUObject<GLPipeline>(pipeline);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
// No object allocated yet, let's see if it's worth it...
|
||||
ShaderPointer shader = pipeline.getProgram();
|
||||
|
||||
// If this pipeline's shader has already failed to compile, don't try again
|
||||
if (shader->compilationHasFailed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLShader* programObject = GLShader::sync(backend, *shader);
|
||||
if (programObject == nullptr) {
|
||||
shader->setCompilationHasFailed(true);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StatePointer state = pipeline.getState();
|
||||
GLState* stateObject = GLState::sync(*state);
|
||||
if (stateObject == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Program and state are valid, we can create the pipeline object
|
||||
if (!object) {
|
||||
object = new GLPipeline();
|
||||
Backend::setGPUObject(pipeline, object);
|
||||
}
|
||||
|
||||
// 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->_program = programObject;
|
||||
object->_state = stateObject;
|
||||
|
||||
return object;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLPipeline_h
|
||||
#define hifi_gpu_gl_GLPipeline_h
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLPipeline : public GPUObject {
|
||||
public:
|
||||
static GLPipeline* sync(GLBackend& backend, const Pipeline& pipeline);
|
||||
|
||||
GLShader* _program { nullptr };
|
||||
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 };
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
#endif
|
|
@ -1,67 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLQuery_h
|
||||
#define hifi_gpu_gl_GLQuery_h
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLBackend.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLQuery : public GLObject<Query> {
|
||||
using Parent = gpu::gl::GLObject<Query>;
|
||||
public:
|
||||
template <typename GLQueryType>
|
||||
static GLQueryType* sync(GLBackend& backend, const Query& query) {
|
||||
GLQueryType* object = Backend::getGPUObject<GLQueryType>(query);
|
||||
|
||||
// need to have a gpu object?
|
||||
if (!object) {
|
||||
// All is green, assign the gpuobject to the Query
|
||||
object = new GLQueryType(backend.shared_from_this(), query);
|
||||
(void)CHECK_GL_ERROR();
|
||||
Backend::setGPUObject(query, object);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
template <typename GLQueryType>
|
||||
static GLuint getId(GLBackend& backend, const QueryPointer& query) {
|
||||
if (!query) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLQuery* object = sync<GLQueryType>(backend, *query);
|
||||
if (!object) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return object->_endqo;
|
||||
}
|
||||
|
||||
const GLuint& _endqo = { _id };
|
||||
const GLuint _beginqo = { 0 };
|
||||
GLuint64 _result { (GLuint64)-1 };
|
||||
GLuint64 _batchElapsedTime { (GLuint64) 0 };
|
||||
uint64_t _profileRangeId { 0 };
|
||||
uint32_t _rangeQueryDepth { 0 };
|
||||
|
||||
protected:
|
||||
GLQuery(const std::weak_ptr<GLBackend>& backend, const Query& query, GLuint endId, GLuint beginId) : Parent(backend, query, endId), _beginqo(beginId) {}
|
||||
~GLQuery() {
|
||||
if (_id) {
|
||||
GLuint ids[2] = { _endqo, _beginqo };
|
||||
glDeleteQueries(2, ids);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
|
@ -1,106 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLShader.h"
|
||||
#include <gl/GLShaders.h>
|
||||
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
GLShader::GLShader(const std::weak_ptr<GLBackend>& backend) : _backend(backend) {
|
||||
}
|
||||
|
||||
GLShader::~GLShader() {
|
||||
for (auto& so : _shaderObjects) {
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
if (so.glshader != 0) {
|
||||
backend->releaseShader(so.glshader);
|
||||
}
|
||||
if (so.glprogram != 0) {
|
||||
backend->releaseProgram(so.glprogram);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLShader* GLShader::sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler) {
|
||||
GLShader* object = Backend::getGPUObject<GLShader>(shader);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
// need to have a gpu object?
|
||||
if (shader.isProgram()) {
|
||||
GLShader* tempObject = backend.compileBackendProgram(shader, handler);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
} else if (shader.isDomain()) {
|
||||
GLShader* tempObject = backend.compileBackendShader(shader, handler);
|
||||
if (tempObject) {
|
||||
object = tempObject;
|
||||
Backend::setGPUObject(shader, object);
|
||||
}
|
||||
}
|
||||
|
||||
glFinish();
|
||||
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) {
|
||||
Shader::SlotSet buffers;
|
||||
backend.makeUniformBlockSlots(shaderObject.glprogram, slotBindings, buffers);
|
||||
|
||||
Shader::SlotSet uniforms;
|
||||
Shader::SlotSet textures;
|
||||
Shader::SlotSet samplers;
|
||||
backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers);
|
||||
|
||||
Shader::SlotSet resourceBuffers;
|
||||
backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers);
|
||||
|
||||
Shader::SlotSet inputs;
|
||||
backend.makeInputSlots(shaderObject.glprogram, slotBindings, inputs);
|
||||
|
||||
Shader::SlotSet outputs;
|
||||
backend.makeOutputSlots(shaderObject.glprogram, 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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLShader_h
|
||||
#define hifi_gpu_gl_GLShader_h
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
struct ShaderObject {
|
||||
GLuint glshader { 0 };
|
||||
GLuint glprogram { 0 };
|
||||
GLint transformCameraSlot { -1 };
|
||||
GLint transformObjectSlot { -1 };
|
||||
};
|
||||
|
||||
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 = nullptr);
|
||||
|
||||
enum Version {
|
||||
Mono = 0,
|
||||
Stereo,
|
||||
|
||||
NumVersions
|
||||
};
|
||||
|
||||
using ShaderObject = gpu::gl::ShaderObject;
|
||||
using ShaderObjects = std::array< ShaderObject, NumVersions >;
|
||||
|
||||
using UniformMapping = std::map<GLint, GLint>;
|
||||
using UniformMappingVersions = std::vector<UniformMapping>;
|
||||
|
||||
GLShader(const std::weak_ptr<GLBackend>& backend);
|
||||
~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;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
#endif
|
|
@ -1,335 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/14
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLShared.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <GPUIdent.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <fstream>
|
||||
|
||||
Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl")
|
||||
Q_LOGGING_CATEGORY(trace_render_gpu_gl, "trace.render.gpu.gl")
|
||||
Q_LOGGING_CATEGORY(trace_render_gpu_gl_detail, "trace.render.gpu.gl.detail")
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
bool checkGLError(const char* name) {
|
||||
GLenum error = glGetError();
|
||||
if (!error) {
|
||||
return false;
|
||||
} else {
|
||||
switch (error) {
|
||||
case GL_INVALID_ENUM:
|
||||
qCWarning(gpugllogging) << "GLBackend::" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag.";
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
qCWarning(gpugllogging) << "GLBackend" << name << ": A numeric argument is out of range.The offending command is ignored and has no other side effect than to set the error flag";
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
qCWarning(gpugllogging) << "GLBackend" << name << ": The specified operation is not allowed in the current state.The offending command is ignored and has no other side effect than to set the error flag..";
|
||||
break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
qCWarning(gpugllogging) << "GLBackend" << name << ": The framebuffer object is not complete.The offending command is ignored and has no other side effect than to set the error flag.";
|
||||
break;
|
||||
case GL_OUT_OF_MEMORY:
|
||||
qCWarning(gpugllogging) << "GLBackend" << name << ": There is not enough memory left to execute the command.The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
|
||||
break;
|
||||
case GL_STACK_UNDERFLOW:
|
||||
qCWarning(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to underflow.";
|
||||
break;
|
||||
case GL_STACK_OVERFLOW:
|
||||
qCWarning(gpugllogging) << "GLBackend" << name << ": An attempt has been made to perform an operation that would cause an internal stack to overflow.";
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool checkGLErrorDebug(const char* name) {
|
||||
// FIXME, disable in debug mode when near release
|
||||
return checkGLError(name);
|
||||
}
|
||||
|
||||
gpu::Size getFreeDedicatedMemory() {
|
||||
Size result { 0 };
|
||||
static bool nvidiaMemorySupported { false };
|
||||
static bool atiMemorySupported { false };
|
||||
if (nvidiaMemorySupported) {
|
||||
|
||||
GLint nvGpuMemory { 0 };
|
||||
qDebug() << "TODO: GLShared.cpp getFreeDedicatedMemory GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX";
|
||||
//glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &nvGpuMemory);
|
||||
if (GL_NO_ERROR == glGetError()) {
|
||||
result = KB_TO_BYTES(nvGpuMemory);
|
||||
} else {
|
||||
nvidiaMemorySupported = false;
|
||||
}
|
||||
} else if (atiMemorySupported) {
|
||||
GLint atiGpuMemory[4];
|
||||
qDebug() << "TODO: GLShared.cpp getFreeDedicatedMemory GL_TEXTURE_FREE_MEMORY_ATI";
|
||||
// not really total memory, but close enough if called early enough in the application lifecycle
|
||||
//glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory);
|
||||
if (GL_NO_ERROR == glGetError()) {
|
||||
result = KB_TO_BYTES(atiGpuMemory[0]);
|
||||
} else {
|
||||
atiMemorySupported = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ComparisonFunction comparisonFuncFromGL(GLenum func) {
|
||||
if (func == GL_NEVER) {
|
||||
return NEVER;
|
||||
} else if (func == GL_LESS) {
|
||||
return LESS;
|
||||
} else if (func == GL_EQUAL) {
|
||||
return EQUAL;
|
||||
} else if (func == GL_LEQUAL) {
|
||||
return LESS_EQUAL;
|
||||
} else if (func == GL_GREATER) {
|
||||
return GREATER;
|
||||
} else if (func == GL_NOTEQUAL) {
|
||||
return NOT_EQUAL;
|
||||
} else if (func == GL_GEQUAL) {
|
||||
return GREATER_EQUAL;
|
||||
} else if (func == GL_ALWAYS) {
|
||||
return ALWAYS;
|
||||
}
|
||||
|
||||
return ALWAYS;
|
||||
}
|
||||
|
||||
State::StencilOp stencilOpFromGL(GLenum stencilOp) {
|
||||
if (stencilOp == GL_KEEP) {
|
||||
return State::STENCIL_OP_KEEP;
|
||||
} else if (stencilOp == GL_ZERO) {
|
||||
return State::STENCIL_OP_ZERO;
|
||||
} else if (stencilOp == GL_REPLACE) {
|
||||
return State::STENCIL_OP_REPLACE;
|
||||
} else if (stencilOp == GL_INCR_WRAP) {
|
||||
return State::STENCIL_OP_INCR_SAT;
|
||||
} else if (stencilOp == GL_DECR_WRAP) {
|
||||
return State::STENCIL_OP_DECR_SAT;
|
||||
} else if (stencilOp == GL_INVERT) {
|
||||
return State::STENCIL_OP_INVERT;
|
||||
} else if (stencilOp == GL_INCR) {
|
||||
return State::STENCIL_OP_INCR;
|
||||
} else if (stencilOp == GL_DECR) {
|
||||
return State::STENCIL_OP_DECR;
|
||||
}
|
||||
|
||||
return State::STENCIL_OP_KEEP;
|
||||
}
|
||||
|
||||
State::BlendOp blendOpFromGL(GLenum blendOp) {
|
||||
if (blendOp == GL_FUNC_ADD) {
|
||||
return State::BLEND_OP_ADD;
|
||||
} else if (blendOp == GL_FUNC_SUBTRACT) {
|
||||
return State::BLEND_OP_SUBTRACT;
|
||||
} else if (blendOp == GL_FUNC_REVERSE_SUBTRACT) {
|
||||
return State::BLEND_OP_REV_SUBTRACT;
|
||||
} else if (blendOp == GL_MIN) {
|
||||
return State::BLEND_OP_MIN;
|
||||
} else if (blendOp == GL_MAX) {
|
||||
return State::BLEND_OP_MAX;
|
||||
}
|
||||
|
||||
return State::BLEND_OP_ADD;
|
||||
}
|
||||
|
||||
State::BlendArg blendArgFromGL(GLenum blendArg) {
|
||||
if (blendArg == GL_ZERO) {
|
||||
return State::ZERO;
|
||||
} else if (blendArg == GL_ONE) {
|
||||
return State::ONE;
|
||||
} else if (blendArg == GL_SRC_COLOR) {
|
||||
return State::SRC_COLOR;
|
||||
} else if (blendArg == GL_ONE_MINUS_SRC_COLOR) {
|
||||
return State::INV_SRC_COLOR;
|
||||
} else if (blendArg == GL_DST_COLOR) {
|
||||
return State::DEST_COLOR;
|
||||
} else if (blendArg == GL_ONE_MINUS_DST_COLOR) {
|
||||
return State::INV_DEST_COLOR;
|
||||
} else if (blendArg == GL_SRC_ALPHA) {
|
||||
return State::SRC_ALPHA;
|
||||
} else if (blendArg == GL_ONE_MINUS_SRC_ALPHA) {
|
||||
return State::INV_SRC_ALPHA;
|
||||
} else if (blendArg == GL_DST_ALPHA) {
|
||||
return State::DEST_ALPHA;
|
||||
} else if (blendArg == GL_ONE_MINUS_DST_ALPHA) {
|
||||
return State::INV_DEST_ALPHA;
|
||||
} else if (blendArg == GL_CONSTANT_COLOR) {
|
||||
return State::FACTOR_COLOR;
|
||||
} else if (blendArg == GL_ONE_MINUS_CONSTANT_COLOR) {
|
||||
return State::INV_FACTOR_COLOR;
|
||||
} else if (blendArg == GL_CONSTANT_ALPHA) {
|
||||
return State::FACTOR_ALPHA;
|
||||
} else if (blendArg == GL_ONE_MINUS_CONSTANT_ALPHA) {
|
||||
return State::INV_FACTOR_ALPHA;
|
||||
}
|
||||
|
||||
return State::ONE;
|
||||
}
|
||||
|
||||
void getCurrentGLState(State::Data& state) {
|
||||
{
|
||||
//GLint modes[2];
|
||||
//glGetIntegerv(GL_POLYGON_MODE, modes);
|
||||
//if (modes[0] == GL_FILL) {
|
||||
// state.fillMode = State::FILL_FACE;
|
||||
//} else {
|
||||
// if (modes[0] == GL_LINE) {
|
||||
// state.fillMode = State::FILL_LINE;
|
||||
// } else {
|
||||
// state.fillMode = State::FILL_POINT;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
{
|
||||
if (glIsEnabled(GL_CULL_FACE)) {
|
||||
GLint mode;
|
||||
glGetIntegerv(GL_CULL_FACE_MODE, &mode);
|
||||
state.cullMode = (mode == GL_FRONT ? State::CULL_FRONT : State::CULL_BACK);
|
||||
} else {
|
||||
state.cullMode = State::CULL_NONE;
|
||||
}
|
||||
}
|
||||
{
|
||||
GLint winding;
|
||||
glGetIntegerv(GL_FRONT_FACE, &winding);
|
||||
state.frontFaceClockwise = (winding == GL_CW);
|
||||
state.depthClampEnable = false; //glIsEnabled(GL_DEPTH_CLAMP_EXT);
|
||||
state.scissorEnable = glIsEnabled(GL_SCISSOR_TEST);
|
||||
state.multisampleEnable = false; //glIsEnabled(GL_MULTISAMPLE_EXT);
|
||||
state.antialisedLineEnable = false; //glIsEnabled(GL_LINE_SMOOTH);
|
||||
}
|
||||
{
|
||||
if (glIsEnabled(GL_POLYGON_OFFSET_FILL)) {
|
||||
glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &state.depthBiasSlopeScale);
|
||||
glGetFloatv(GL_POLYGON_OFFSET_UNITS, &state.depthBias);
|
||||
}
|
||||
}
|
||||
{
|
||||
GLboolean isEnabled = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean writeMask;
|
||||
glGetBooleanv(GL_DEPTH_WRITEMASK, &writeMask);
|
||||
GLint func;
|
||||
glGetIntegerv(GL_DEPTH_FUNC, &func);
|
||||
|
||||
state.depthTest = State::DepthTest(isEnabled, writeMask, comparisonFuncFromGL(func));
|
||||
}
|
||||
{
|
||||
GLboolean isEnabled = glIsEnabled(GL_STENCIL_TEST);
|
||||
|
||||
GLint frontWriteMask;
|
||||
GLint frontReadMask;
|
||||
GLint frontRef;
|
||||
GLint frontFail;
|
||||
GLint frontDepthFail;
|
||||
GLint frontPass;
|
||||
GLint frontFunc;
|
||||
glGetIntegerv(GL_STENCIL_WRITEMASK, &frontWriteMask);
|
||||
glGetIntegerv(GL_STENCIL_VALUE_MASK, &frontReadMask);
|
||||
glGetIntegerv(GL_STENCIL_REF, &frontRef);
|
||||
glGetIntegerv(GL_STENCIL_FAIL, &frontFail);
|
||||
glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &frontDepthFail);
|
||||
glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &frontPass);
|
||||
glGetIntegerv(GL_STENCIL_FUNC, &frontFunc);
|
||||
|
||||
GLint backWriteMask;
|
||||
GLint backReadMask;
|
||||
GLint backRef;
|
||||
GLint backFail;
|
||||
GLint backDepthFail;
|
||||
GLint backPass;
|
||||
GLint backFunc;
|
||||
glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &backWriteMask);
|
||||
glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &backReadMask);
|
||||
glGetIntegerv(GL_STENCIL_BACK_REF, &backRef);
|
||||
glGetIntegerv(GL_STENCIL_BACK_FAIL, &backFail);
|
||||
glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &backDepthFail);
|
||||
glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &backPass);
|
||||
glGetIntegerv(GL_STENCIL_BACK_FUNC, &backFunc);
|
||||
|
||||
state.stencilActivation = State::StencilActivation(isEnabled, frontWriteMask, backWriteMask);
|
||||
state.stencilTestFront = State::StencilTest(frontRef, frontReadMask, comparisonFuncFromGL(frontFunc), stencilOpFromGL(frontFail), stencilOpFromGL(frontDepthFail), stencilOpFromGL(frontPass));
|
||||
state.stencilTestBack = State::StencilTest(backRef, backReadMask, comparisonFuncFromGL(backFunc), stencilOpFromGL(backFail), stencilOpFromGL(backDepthFail), stencilOpFromGL(backPass));
|
||||
}
|
||||
{
|
||||
GLint mask = 0xFFFFFFFF;
|
||||
if (glIsEnabled(GL_SAMPLE_MASK)) {
|
||||
glGetIntegerv(GL_SAMPLE_MASK, &mask);
|
||||
state.sampleMask = mask;
|
||||
}
|
||||
state.sampleMask = mask;
|
||||
}
|
||||
{
|
||||
state.alphaToCoverageEnable = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
}
|
||||
{
|
||||
GLboolean isEnabled = glIsEnabled(GL_BLEND);
|
||||
GLint srcRGB;
|
||||
GLint srcA;
|
||||
GLint dstRGB;
|
||||
GLint dstA;
|
||||
glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB);
|
||||
glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcA);
|
||||
glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB);
|
||||
glGetIntegerv(GL_BLEND_DST_ALPHA, &dstA);
|
||||
|
||||
GLint opRGB;
|
||||
GLint opA;
|
||||
glGetIntegerv(GL_BLEND_EQUATION_RGB, &opRGB);
|
||||
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &opA);
|
||||
|
||||
state.blendFunction = State::BlendFunction(isEnabled,
|
||||
blendArgFromGL(srcRGB), blendOpFromGL(opRGB), blendArgFromGL(dstRGB),
|
||||
blendArgFromGL(srcA), blendOpFromGL(opA), blendArgFromGL(dstA));
|
||||
}
|
||||
{
|
||||
GLboolean mask[4];
|
||||
glGetBooleanv(GL_COLOR_WRITEMASK, mask);
|
||||
state.colorWriteMask = (mask[0] ? State::WRITE_RED : 0)
|
||||
| (mask[1] ? State::WRITE_GREEN : 0)
|
||||
| (mask[2] ? State::WRITE_BLUE : 0)
|
||||
| (mask[3] ? State::WRITE_ALPHA : 0);
|
||||
}
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void serverWait() {
|
||||
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
assert(fence);
|
||||
glWaitSync(fence, 0, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fence);
|
||||
}
|
||||
|
||||
void clientWait() {
|
||||
auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
assert(fence);
|
||||
auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
|
||||
while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) {
|
||||
// Minimum sleep
|
||||
QThread::usleep(1);
|
||||
result = glClientWaitSync(fence, 0, 0);
|
||||
}
|
||||
glDeleteSync(fence);
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
|
||||
using namespace gpu;
|
||||
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_GLShared_h
|
||||
#define hifi_gpu_GLShared_h
|
||||
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
|
||||
#include <gpu/Forward.h>
|
||||
#include <gpu/Format.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
|
||||
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl)
|
||||
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl_detail)
|
||||
|
||||
#define BUFFER_OFFSET(bytes) ((GLubyte*) nullptr + (bytes))
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
// Create a fence and inject a GPU wait on the fence
|
||||
void serverWait();
|
||||
|
||||
// Create a fence and synchronously wait on the fence
|
||||
void clientWait();
|
||||
|
||||
gpu::Size getFreeDedicatedMemory();
|
||||
ComparisonFunction comparisonFuncFromGL(GLenum func);
|
||||
State::StencilOp stencilOpFromGL(GLenum stencilOp);
|
||||
State::BlendOp blendOpFromGL(GLenum blendOp);
|
||||
State::BlendArg blendArgFromGL(GLenum blendArg);
|
||||
void getCurrentGLState(State::Data& state);
|
||||
|
||||
enum GLSyncState {
|
||||
// The object is currently undergoing no processing, although it's content
|
||||
// may be out of date, or it's storage may be invalid relative to the
|
||||
// owning GPU object
|
||||
Idle,
|
||||
// The object has been queued for transfer to the GPU
|
||||
Pending,
|
||||
// The object has been transferred to the GPU, but is awaiting
|
||||
// any post transfer operations that may need to occur on the
|
||||
// primary rendering thread
|
||||
Transferred,
|
||||
};
|
||||
|
||||
static const GLenum BLEND_OPS_TO_GL[State::NUM_BLEND_OPS] = {
|
||||
GL_FUNC_ADD,
|
||||
GL_FUNC_SUBTRACT,
|
||||
GL_FUNC_REVERSE_SUBTRACT,
|
||||
GL_MIN,
|
||||
GL_MAX
|
||||
};
|
||||
|
||||
static const GLenum BLEND_ARGS_TO_GL[State::NUM_BLEND_ARGS] = {
|
||||
GL_ZERO,
|
||||
GL_ONE,
|
||||
GL_SRC_COLOR,
|
||||
GL_ONE_MINUS_SRC_COLOR,
|
||||
GL_SRC_ALPHA,
|
||||
GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL_DST_ALPHA,
|
||||
GL_ONE_MINUS_DST_ALPHA,
|
||||
GL_DST_COLOR,
|
||||
GL_ONE_MINUS_DST_COLOR,
|
||||
GL_SRC_ALPHA_SATURATE,
|
||||
GL_CONSTANT_COLOR,
|
||||
GL_ONE_MINUS_CONSTANT_COLOR,
|
||||
GL_CONSTANT_ALPHA,
|
||||
GL_ONE_MINUS_CONSTANT_ALPHA,
|
||||
};
|
||||
|
||||
static const GLenum COMPARISON_TO_GL[gpu::NUM_COMPARISON_FUNCS] = {
|
||||
GL_NEVER,
|
||||
GL_LESS,
|
||||
GL_EQUAL,
|
||||
GL_LEQUAL,
|
||||
GL_GREATER,
|
||||
GL_NOTEQUAL,
|
||||
GL_GEQUAL,
|
||||
GL_ALWAYS
|
||||
};
|
||||
|
||||
static const GLenum PRIMITIVE_TO_GL[gpu::NUM_PRIMITIVES] = {
|
||||
GL_POINTS,
|
||||
GL_LINES,
|
||||
GL_LINE_STRIP,
|
||||
GL_TRIANGLES,
|
||||
GL_TRIANGLE_STRIP,
|
||||
GL_TRIANGLE_FAN,
|
||||
};
|
||||
|
||||
static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = {
|
||||
GL_FLOAT,
|
||||
GL_INT,
|
||||
GL_UNSIGNED_INT,
|
||||
GL_HALF_FLOAT,
|
||||
GL_SHORT,
|
||||
GL_UNSIGNED_SHORT,
|
||||
GL_BYTE,
|
||||
GL_UNSIGNED_BYTE,
|
||||
// Normalized values
|
||||
GL_INT,
|
||||
GL_UNSIGNED_INT,
|
||||
GL_SHORT,
|
||||
GL_UNSIGNED_SHORT,
|
||||
GL_BYTE,
|
||||
GL_UNSIGNED_BYTE,
|
||||
GL_UNSIGNED_BYTE,
|
||||
GL_INT_2_10_10_10_REV,
|
||||
};
|
||||
|
||||
bool checkGLError(const char* name = nullptr);
|
||||
bool checkGLErrorDebug(const char* name = nullptr);
|
||||
|
||||
class GLBackend;
|
||||
|
||||
template <typename GPUType>
|
||||
struct GLObject : public GPUObject {
|
||||
public:
|
||||
GLObject(const std::weak_ptr<GLBackend>& backend, const GPUType& gpuObject, GLuint id) : _gpuObject(gpuObject), _id(id), _backend(backend) {}
|
||||
|
||||
virtual ~GLObject() { }
|
||||
|
||||
const GPUType& _gpuObject;
|
||||
const GLuint _id;
|
||||
protected:
|
||||
const std::weak_ptr<GLBackend> _backend;
|
||||
};
|
||||
|
||||
class GlBuffer;
|
||||
class GLFramebuffer;
|
||||
class GLPipeline;
|
||||
class GLQuery;
|
||||
class GLState;
|
||||
class GLShader;
|
||||
class GLTexture;
|
||||
struct ShaderObject;
|
||||
|
||||
} } // namespace gpu::gl
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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 defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-override"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include "GLState.h"
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
typedef GLState::Command Command;
|
||||
typedef GLState::CommandPointer CommandPointer;
|
||||
typedef GLState::Command1<uint32> Command1U;
|
||||
typedef GLState::Command1<int32> Command1I;
|
||||
typedef GLState::Command1<bool> Command1B;
|
||||
typedef GLState::Command1<Vec2> CommandDepthBias;
|
||||
typedef GLState::Command1<State::DepthTest> CommandDepthTest;
|
||||
typedef GLState::Command3<State::StencilActivation, State::StencilTest, State::StencilTest> CommandStencil;
|
||||
typedef GLState::Command1<State::BlendFunction> CommandBlend;
|
||||
|
||||
const GLState::Commands makeResetStateCommands();
|
||||
|
||||
// NOTE: This must stay in sync with the ordering of the State::Field enum
|
||||
const GLState::Commands makeResetStateCommands() {
|
||||
// Since State::DEFAULT is a static defined in another .cpp the initialisation order is random
|
||||
// and we have a 50/50 chance that State::DEFAULT is not yet initialized.
|
||||
// Since State::DEFAULT = State::Data() it is much easier to not use the actual State::DEFAULT
|
||||
// but another State::Data object with a default initialization.
|
||||
const State::Data DEFAULT = State::Data();
|
||||
|
||||
auto depthBiasCommand = std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias,
|
||||
Vec2(DEFAULT.depthBias, DEFAULT.depthBiasSlopeScale));
|
||||
auto stencilCommand = std::make_shared<CommandStencil>(&GLBackend::do_setStateStencil, DEFAULT.stencilActivation,
|
||||
DEFAULT.stencilTestFront, DEFAULT.stencilTestBack);
|
||||
|
||||
// The state commands to reset to default,
|
||||
// WARNING depending on the order of the State::Field enum
|
||||
return {
|
||||
std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, DEFAULT.fillMode),
|
||||
std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, DEFAULT.cullMode),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, DEFAULT.depthClampEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable),
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable),
|
||||
|
||||
// Depth bias has 2 fields in State but really one call in GLBackend
|
||||
CommandPointer(depthBiasCommand),
|
||||
CommandPointer(depthBiasCommand),
|
||||
|
||||
std::make_shared<CommandDepthTest>(&GLBackend::do_setStateDepthTest, DEFAULT.depthTest),
|
||||
|
||||
// Depth bias has 3 fields in State but really one call in GLBackend
|
||||
CommandPointer(stencilCommand),
|
||||
CommandPointer(stencilCommand),
|
||||
CommandPointer(stencilCommand),
|
||||
|
||||
std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask),
|
||||
|
||||
std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable),
|
||||
|
||||
std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, DEFAULT.blendFunction),
|
||||
|
||||
std::make_shared<Command1U>(&GLBackend::do_setStateColorWriteMask, DEFAULT.colorWriteMask)
|
||||
};
|
||||
}
|
||||
|
||||
const GLState::Commands GLState::_resetStateCommands = makeResetStateCommands();
|
||||
|
||||
|
||||
void generateFillMode(GLState::Commands& commands, State::FillMode fillMode) {
|
||||
commands.push_back(std::make_shared<Command1I>(&GLBackend::do_setStateFillMode, int32(fillMode)));
|
||||
}
|
||||
|
||||
void generateCullMode(GLState::Commands& commands, State::CullMode cullMode) {
|
||||
commands.push_back(std::make_shared<Command1I>(&GLBackend::do_setStateCullMode, int32(cullMode)));
|
||||
}
|
||||
|
||||
void generateFrontFaceClockwise(GLState::Commands& commands, bool isClockwise) {
|
||||
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateFrontFaceClockwise, isClockwise));
|
||||
}
|
||||
|
||||
void generateDepthClampEnable(GLState::Commands& commands, bool enable) {
|
||||
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateDepthClampEnable, enable));
|
||||
}
|
||||
|
||||
void generateScissorEnable(GLState::Commands& commands, bool enable) {
|
||||
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateScissorEnable, enable));
|
||||
}
|
||||
|
||||
void generateMultisampleEnable(GLState::Commands& commands, bool enable) {
|
||||
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateMultisampleEnable, enable));
|
||||
}
|
||||
|
||||
void generateAntialiasedLineEnable(GLState::Commands& commands, bool enable) {
|
||||
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateAntialiasedLineEnable, enable));
|
||||
}
|
||||
|
||||
void generateDepthBias(GLState::Commands& commands, const State& state) {
|
||||
commands.push_back(std::make_shared<CommandDepthBias>(&GLBackend::do_setStateDepthBias, Vec2(state.getDepthBias(), state.getDepthBiasSlopeScale())));
|
||||
}
|
||||
|
||||
void generateDepthTest(GLState::Commands& commands, const State::DepthTest& test) {
|
||||
commands.push_back(std::make_shared<CommandDepthTest>(&GLBackend::do_setStateDepthTest, int32(test.getRaw())));
|
||||
}
|
||||
|
||||
void generateStencil(GLState::Commands& commands, const State& state) {
|
||||
commands.push_back(std::make_shared<CommandStencil>(&GLBackend::do_setStateStencil, state.getStencilActivation(), state.getStencilTestFront(), state.getStencilTestBack()));
|
||||
}
|
||||
|
||||
void generateAlphaToCoverageEnable(GLState::Commands& commands, bool enable) {
|
||||
commands.push_back(std::make_shared<Command1B>(&GLBackend::do_setStateAlphaToCoverageEnable, enable));
|
||||
}
|
||||
|
||||
void generateSampleMask(GLState::Commands& commands, uint32 mask) {
|
||||
commands.push_back(std::make_shared<Command1U>(&GLBackend::do_setStateSampleMask, mask));
|
||||
}
|
||||
|
||||
void generateBlend(GLState::Commands& commands, const State& state) {
|
||||
commands.push_back(std::make_shared<CommandBlend>(&GLBackend::do_setStateBlend, state.getBlendFunction()));
|
||||
}
|
||||
|
||||
void generateColorWriteMask(GLState::Commands& commands, uint32 mask) {
|
||||
commands.push_back(std::make_shared<Command1U>(&GLBackend::do_setStateColorWriteMask, mask));
|
||||
}
|
||||
|
||||
GLState* GLState::sync(const State& state) {
|
||||
GLState* object = Backend::getGPUObject<GLState>(state);
|
||||
|
||||
// If GPU object already created then good
|
||||
if (object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
// Else allocate and create the GLState
|
||||
if (!object) {
|
||||
object = new GLState();
|
||||
Backend::setGPUObject(state, object);
|
||||
}
|
||||
|
||||
// here, we need to regenerate something so let's do it all
|
||||
object->_commands.clear();
|
||||
object->_stamp = state.getStamp();
|
||||
object->_signature = state.getSignature();
|
||||
|
||||
bool depthBias = false;
|
||||
bool stencilState = false;
|
||||
|
||||
// go thorugh the list of state fields in the State and record the corresponding gl command
|
||||
for (int i = 0; i < State::NUM_FIELDS; i++) {
|
||||
if (state.getSignature()[i]) {
|
||||
switch (i) {
|
||||
case State::FILL_MODE: {
|
||||
generateFillMode(object->_commands, state.getFillMode());
|
||||
break;
|
||||
}
|
||||
case State::CULL_MODE: {
|
||||
generateCullMode(object->_commands, state.getCullMode());
|
||||
break;
|
||||
}
|
||||
case State::DEPTH_BIAS:
|
||||
case State::DEPTH_BIAS_SLOPE_SCALE: {
|
||||
depthBias = true;
|
||||
break;
|
||||
}
|
||||
case State::FRONT_FACE_CLOCKWISE: {
|
||||
generateFrontFaceClockwise(object->_commands, state.isFrontFaceClockwise());
|
||||
break;
|
||||
}
|
||||
case State::DEPTH_CLAMP_ENABLE: {
|
||||
generateDepthClampEnable(object->_commands, state.isDepthClampEnable());
|
||||
break;
|
||||
}
|
||||
case State::SCISSOR_ENABLE: {
|
||||
generateScissorEnable(object->_commands, state.isScissorEnable());
|
||||
break;
|
||||
}
|
||||
case State::MULTISAMPLE_ENABLE: {
|
||||
generateMultisampleEnable(object->_commands, state.isMultisampleEnable());
|
||||
break;
|
||||
}
|
||||
case State::ANTIALISED_LINE_ENABLE: {
|
||||
generateAntialiasedLineEnable(object->_commands, state.isAntialiasedLineEnable());
|
||||
break;
|
||||
}
|
||||
case State::DEPTH_TEST: {
|
||||
generateDepthTest(object->_commands, state.getDepthTest());
|
||||
break;
|
||||
}
|
||||
|
||||
case State::STENCIL_ACTIVATION:
|
||||
case State::STENCIL_TEST_FRONT:
|
||||
case State::STENCIL_TEST_BACK: {
|
||||
stencilState = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case State::SAMPLE_MASK: {
|
||||
generateSampleMask(object->_commands, state.getSampleMask());
|
||||
break;
|
||||
}
|
||||
case State::ALPHA_TO_COVERAGE_ENABLE: {
|
||||
generateAlphaToCoverageEnable(object->_commands, state.isAlphaToCoverageEnabled());
|
||||
break;
|
||||
}
|
||||
|
||||
case State::BLEND_FUNCTION: {
|
||||
generateBlend(object->_commands, state);
|
||||
break;
|
||||
}
|
||||
|
||||
case State::COLOR_WRITE_MASK: {
|
||||
generateColorWriteMask(object->_commands, state.getColorWriteMask());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (depthBias) {
|
||||
generateDepthBias(object->_commands, state);
|
||||
}
|
||||
|
||||
if (stencilState) {
|
||||
generateStencil(object->_commands, state);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLState_h
|
||||
#define hifi_gpu_gl_GLState_h
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
#include <gpu/State.h>
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLBackend;
|
||||
class GLState : public GPUObject {
|
||||
public:
|
||||
static GLState* sync(const State& state);
|
||||
|
||||
class Command {
|
||||
public:
|
||||
virtual void run(GLBackend* backend) = 0;
|
||||
Command() {}
|
||||
virtual ~Command() {};
|
||||
};
|
||||
|
||||
template <class T> class Command1 : public Command {
|
||||
public:
|
||||
typedef void (GLBackend::*GLFunction)(T);
|
||||
void run(GLBackend* backend) { (backend->*(_func))(_param); }
|
||||
Command1(GLFunction func, T param) : _func(func), _param(param) {};
|
||||
GLFunction _func;
|
||||
T _param;
|
||||
};
|
||||
template <class T, class U> class Command2 : public Command {
|
||||
public:
|
||||
typedef void (GLBackend::*GLFunction)(T, U);
|
||||
void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1); }
|
||||
Command2(GLFunction func, T param0, U param1) : _func(func), _param0(param0), _param1(param1) {};
|
||||
GLFunction _func;
|
||||
T _param0;
|
||||
U _param1;
|
||||
};
|
||||
|
||||
template <class T, class U, class V> class Command3 : public Command {
|
||||
public:
|
||||
typedef void (GLBackend::*GLFunction)(T, U, V);
|
||||
void run(GLBackend* backend) { (backend->*(_func))(_param0, _param1, _param2); }
|
||||
Command3(GLFunction func, T param0, U param1, V param2) : _func(func), _param0(param0), _param1(param1), _param2(param2) {};
|
||||
GLFunction _func;
|
||||
T _param0;
|
||||
U _param1;
|
||||
V _param2;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr< Command > CommandPointer;
|
||||
typedef std::vector< CommandPointer > Commands;
|
||||
|
||||
Commands _commands;
|
||||
Stamp _stamp;
|
||||
State::Signature _signature;
|
||||
|
||||
// The state commands to reset to default,
|
||||
static const Commands _resetStateCommands;
|
||||
|
||||
friend class GLBackend;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
|
@ -1,733 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GLTexelFormat.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
bool GLTexelFormat::isCompressed() const {
|
||||
switch (internalFormat) {
|
||||
case GL_COMPRESSED_R11_EAC:
|
||||
case GL_COMPRESSED_SIGNED_R11_EAC:
|
||||
case GL_COMPRESSED_RG11_EAC:
|
||||
case GL_COMPRESSED_SIGNED_RG11_EAC:
|
||||
case GL_COMPRESSED_RGB8_ETC2:
|
||||
case GL_COMPRESSED_SRGB8_ETC2:
|
||||
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||
case GL_COMPRESSED_RGBA8_ETC2_EAC:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
|
||||
case GL_COMPRESSED_RGBA_ASTC_4x4:
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x4:
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x6:
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x6:
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x8:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x5:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x6:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x8:
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x10:
|
||||
case GL_COMPRESSED_RGBA_ASTC_12x10:
|
||||
case GL_COMPRESSED_RGBA_ASTC_12x12:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10:
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||
GLenum result = GL_RGBA8;
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RED:
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
result = GL_R32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
result = GL_R32I;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
result = GL_R8;
|
||||
break;
|
||||
case gpu::NINT32:
|
||||
result = GL_R8_SNORM;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
result = GL_R32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
result = GL_R16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
result = GL_R16I;
|
||||
break;
|
||||
case gpu::NUINT16:
|
||||
//result = GL_R16_EXT;
|
||||
break;
|
||||
case gpu::NINT16:
|
||||
//result = GL_R16_SNORM_EXT;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
result = GL_R16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
result = GL_R8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
result = GL_R8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||
result = GL_SLUMINANCE8_NV;
|
||||
} else {
|
||||
result = GL_R8;
|
||||
}
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
result = GL_R8_SNORM;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case gpu::R11G11B10:
|
||||
// the type should be float
|
||||
result = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
case gpu::RGB9E5:
|
||||
// the type should be float
|
||||
result = GL_RGB9_E5;
|
||||
break;
|
||||
case gpu::DEPTH:
|
||||
result = GL_DEPTH_COMPONENT16;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
case gpu::INT32:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
result = GL_DEPTH_COMPONENT32_OES;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
result = GL_DEPTH_COMPONENT32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
case gpu::INT16:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::HALF:
|
||||
result = GL_DEPTH_COMPONENT16;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
case gpu::INT8:
|
||||
case gpu::NUINT8:
|
||||
case gpu::NINT8:
|
||||
result = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case gpu::DEPTH_STENCIL:
|
||||
result = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::XY:
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
result = GL_RG32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
result = GL_RG32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
result = GL_RG32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
result = GL_RG16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
result = GL_RG16I;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
result = GL_RG16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
result = GL_RG8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
result = GL_RG8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
result = GL_RG8;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
result = GL_RG8_SNORM;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NINT2_10_10_10:
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
result = GL_RGB8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
result = GL_SRGB8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
result = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
result = GL_RGBA32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
result = GL_RGBA32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
result = GL_RGBA32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
result = GL_RGBA16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
result = GL_RGBA16I;
|
||||
break;
|
||||
case gpu::NUINT16:
|
||||
//result = GL_RGBA16_EXT;
|
||||
break;
|
||||
case gpu::NINT16:
|
||||
//result = GL_RGBA16_SNORM_EXT;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
result = GL_RGBA16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
result = GL_RGBA8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
result = GL_RGBA8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
result = GL_RGBA8;
|
||||
break;
|
||||
case gpu::NUINT2:
|
||||
//result = GL_RGBA2;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
result = GL_RGBA8_SNORM;
|
||||
break;
|
||||
case gpu::NINT2_10_10_10:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
result = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
result = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
//qDebug() << "GLTexelFormat::evalGLTexelFormatInternal result " << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) {
|
||||
|
||||
if (dstFormat != srcFormat) {
|
||||
GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
texel.format = GL_RED;
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RED:
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_R8;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
texel.format = GL_DEPTH_COMPONENT;
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.type = GL_UNSIGNED_INT_24_8;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
texel.format = GL_RG;
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::XY:
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
texel.internalFormat = GL_RG32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
texel.internalFormat = GL_RG32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
texel.internalFormat = GL_RG32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
texel.internalFormat = GL_RG16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
texel.internalFormat = GL_RG16I;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
texel.type = GL_FLOAT;
|
||||
texel.internalFormat = GL_RG16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
texel.internalFormat = GL_RG8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
texel.internalFormat = GL_RG8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
texel.internalFormat = GL_RG8;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
texel.internalFormat = GL_RG8_SNORM;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NINT2_10_10_10:
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
texel.format = GL_RGB;
|
||||
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
texel.format = GL_RGBA;
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (srcFormat.getSemantic()) {
|
||||
case gpu::BGRA:
|
||||
case gpu::SBGRA:
|
||||
texel.format = GL_RGBA; // GL_BGRA_EXT;
|
||||
break;
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.internalFormat = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8_ALPHA8;
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
return texel;
|
||||
} else {
|
||||
GLTexelFormat texel = { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
|
||||
switch (dstFormat.getDimension()) {
|
||||
case gpu::SCALAR: {
|
||||
texel.format = GL_RED;
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
|
||||
case gpu::RED:
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_RED;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32: {
|
||||
texel.internalFormat = GL_R32UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT32: {
|
||||
texel.internalFormat = GL_R32I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT32: {
|
||||
texel.internalFormat = GL_R8;
|
||||
break;
|
||||
}
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_R32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16: {
|
||||
texel.internalFormat = GL_R16UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT16: {
|
||||
texel.internalFormat = GL_R16I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT16: {
|
||||
texel.internalFormat = GL_R16_EXT;
|
||||
break;
|
||||
}
|
||||
case gpu::NINT16: {
|
||||
texel.internalFormat = GL_R16_SNORM_EXT;
|
||||
break;
|
||||
}
|
||||
case gpu::HALF: {
|
||||
texel.internalFormat = GL_R16F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8: {
|
||||
texel.internalFormat = GL_R8UI;
|
||||
break;
|
||||
}
|
||||
case gpu::INT8: {
|
||||
texel.internalFormat = GL_R8I;
|
||||
break;
|
||||
}
|
||||
case gpu::NUINT8: {
|
||||
if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) {
|
||||
texel.internalFormat = GL_SLUMINANCE8_NV;
|
||||
} else {
|
||||
texel.internalFormat = GL_R8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_R8_SNORM;
|
||||
break;
|
||||
}
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case gpu::R11G11B10:
|
||||
texel.format = GL_RGB;
|
||||
texel.type = GL_UNSIGNED_INT_10F_11F_11F_REV;
|
||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
|
||||
case gpu::RGB9E5:
|
||||
texel.format = GL_RGB;
|
||||
texel.type = GL_UNSIGNED_INT_5_9_9_9_REV;
|
||||
texel.internalFormat = GL_RGB9_E5;
|
||||
break;
|
||||
|
||||
case gpu::DEPTH:
|
||||
texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32_OES;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
case gpu::INT32:
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32_OES;
|
||||
break;
|
||||
}
|
||||
case gpu::FLOAT: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT32F;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT16:
|
||||
case gpu::INT16:
|
||||
case gpu::NUINT16:
|
||||
case gpu::NINT16:
|
||||
case gpu::HALF: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT16;
|
||||
break;
|
||||
}
|
||||
case gpu::UINT8:
|
||||
case gpu::INT8:
|
||||
case gpu::NUINT8:
|
||||
case gpu::NINT8: {
|
||||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||
break;
|
||||
}
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUINT2:
|
||||
case gpu::NINT2_10_10_10:
|
||||
case gpu::NUM_TYPES: { // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.type = GL_UNSIGNED_INT_24_8;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC2: {
|
||||
texel.format = GL_RG;
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
case gpu::XY:
|
||||
texel.internalFormat = GL_RG8;
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC3: {
|
||||
texel.format = GL_RGB;
|
||||
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case gpu::VEC4: {
|
||||
texel.format = GL_RGBA;
|
||||
texel.type = ELEMENT_TYPE_TO_GL[dstFormat.getType()];
|
||||
|
||||
switch (dstFormat.getSemantic()) {
|
||||
case gpu::RGB:
|
||||
texel.internalFormat = GL_RGB8;
|
||||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
texel.internalFormat = GL_RGBA32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16I;
|
||||
break;
|
||||
case gpu::NUINT16:
|
||||
texel.format = GL_RGBA;
|
||||
//texel.internalFormat = GL_RGBA16_EXT;
|
||||
break;
|
||||
case gpu::NINT16:
|
||||
texel.format = GL_RGBA;
|
||||
//texel.internalFormat = GL_RGBA16_SNORM_EXT;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8_SNORM;
|
||||
break;
|
||||
case gpu::NUINT2:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NINT2_10_10_10:
|
||||
case gpu::COMPRESSED:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.internalFormat = GL_SRGB8;
|
||||
break;
|
||||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color
|
||||
break;
|
||||
default:
|
||||
qCWarning(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCDebug(gpugllogging) << "Unknown combination of texel format";
|
||||
}
|
||||
return texel;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLTexelFormat_h
|
||||
#define hifi_gpu_gl_GLTexelFormat_h
|
||||
|
||||
#include "GLShared.h"
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
class GLTexelFormat {
|
||||
public:
|
||||
GLenum internalFormat;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
|
||||
GLTexelFormat(GLenum glinternalFormat, GLenum glformat, GLenum gltype) : internalFormat(glinternalFormat), format(glformat), type(gltype) {}
|
||||
GLTexelFormat(GLenum glinternalFormat) : internalFormat(glinternalFormat) {}
|
||||
|
||||
bool isCompressed() const;
|
||||
|
||||
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) {
|
||||
return evalGLTexelFormat(dstFormat, dstFormat);
|
||||
}
|
||||
static GLenum evalGLTexelFormatInternal(const Element& dstFormat);
|
||||
|
||||
static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat);
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
#endif
|
|
@ -1,701 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "GLTexture.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "GLBackend.h"
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
||||
|
||||
const GLenum GLTexture::CUBE_FACE_LAYOUT[GLTexture::TEXTURE_CUBE_NUM_FACES] = {
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||
};
|
||||
|
||||
|
||||
const GLenum GLTexture::WRAP_MODES[Sampler::NUM_WRAP_MODES] = {
|
||||
GL_REPEAT, // WRAP_REPEAT,
|
||||
GL_MIRRORED_REPEAT, // WRAP_MIRROR,
|
||||
GL_CLAMP_TO_EDGE, // WRAP_CLAMP,
|
||||
GL_CLAMP_TO_BORDER, // WRAP_BORDER,
|
||||
GL_MIRRORED_REPEAT //GL_MIRROR_CLAMP_TO_EDGE_EXT // WRAP_MIRROR_ONCE,
|
||||
};
|
||||
|
||||
const GLFilterMode GLTexture::FILTER_MODES[Sampler::NUM_FILTERS] = {
|
||||
{ GL_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_POINT,
|
||||
{ GL_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR,
|
||||
{ GL_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT,
|
||||
{ GL_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR,
|
||||
|
||||
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_MAG_MIP_POINT,
|
||||
{ GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
||||
{ GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
||||
{ GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
||||
{ GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
||||
{ GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST }, //FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
||||
{ GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR }, //FILTER_MIN_MAG_LINEAR_MIP_POINT,
|
||||
{ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR }, //FILTER_MIN_MAG_MIP_LINEAR,
|
||||
{ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR } //FILTER_ANISOTROPIC,
|
||||
};
|
||||
|
||||
GLenum GLTexture::getGLTextureType(const Texture& texture) {
|
||||
switch (texture.getType()) {
|
||||
case Texture::TEX_2D:
|
||||
return GL_TEXTURE_2D;
|
||||
break;
|
||||
|
||||
case Texture::TEX_CUBE:
|
||||
return GL_TEXTURE_CUBE_MAP;
|
||||
break;
|
||||
|
||||
default:
|
||||
qFatal("Unsupported texture type");
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return GL_TEXTURE_2D;
|
||||
}
|
||||
|
||||
uint8_t GLTexture::getFaceCount(GLenum target) {
|
||||
switch (target) {
|
||||
case GL_TEXTURE_2D:
|
||||
return TEXTURE_2D_NUM_FACES;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
return TEXTURE_CUBE_NUM_FACES;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<GLenum>& GLTexture::getFaceTargets(GLenum target) {
|
||||
static std::vector<GLenum> cubeFaceTargets {
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||
};
|
||||
static std::vector<GLenum> faceTargets {
|
||||
GL_TEXTURE_2D
|
||||
};
|
||||
switch (target) {
|
||||
case GL_TEXTURE_2D:
|
||||
return faceTargets;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
return cubeFaceTargets;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return faceTargets;
|
||||
}
|
||||
|
||||
GLTexture::GLTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id) :
|
||||
GLObject(backend, texture, id),
|
||||
_source(texture.source()),
|
||||
_target(getGLTextureType(texture)),
|
||||
_texelFormat(GLTexelFormat::evalGLTexelFormatInternal(texture.getTexelFormat()))
|
||||
{
|
||||
Backend::setGPUObject(texture, this);
|
||||
}
|
||||
|
||||
GLTexture::~GLTexture() {
|
||||
auto backend = _backend.lock();
|
||||
if (backend && _id) {
|
||||
backend->releaseTexture(_id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Size GLTexture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const {
|
||||
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip)) {
|
||||
return 0;
|
||||
}
|
||||
auto dim = _gpuObject.evalMipDimensions(sourceMip);
|
||||
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
|
||||
auto mipSize = _gpuObject.getStoredMipFaceSize(sourceMip, face);
|
||||
if (mipData) {
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
|
||||
return copyMipFaceLinesFromTexture(targetMip, face, dim, 0, texelFormat.internalFormat, texelFormat.format, texelFormat.type, mipSize, mipData->readData());
|
||||
} else {
|
||||
qCDebug(gpugllogging) << "Missing mipData level=" << sourceMip << " face=" << (int)face << " for texture " << _gpuObject.source().c_str();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
GLExternalTexture::GLExternalTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint id)
|
||||
: Parent(backend, texture, id) {
|
||||
Backend::textureExternalCount.increment();
|
||||
}
|
||||
|
||||
GLExternalTexture::~GLExternalTexture() {
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
auto recycler = _gpuObject.getExternalRecycler();
|
||||
if (recycler) {
|
||||
backend->releaseExternalTexture(_id, recycler);
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "No recycler available for texture " << _id << " possible leak";
|
||||
}
|
||||
const_cast<GLuint&>(_id) = 0;
|
||||
}
|
||||
Backend::textureExternalCount.decrement();
|
||||
}
|
||||
|
||||
|
||||
// Variable sized textures
|
||||
using MemoryPressureState = GLVariableAllocationSupport::MemoryPressureState;
|
||||
using WorkQueue = GLVariableAllocationSupport::WorkQueue;
|
||||
using TransferJobPointer = GLVariableAllocationSupport::TransferJobPointer;
|
||||
|
||||
std::list<TextureWeakPointer> GLVariableAllocationSupport::_memoryManagedTextures;
|
||||
MemoryPressureState GLVariableAllocationSupport::_memoryPressureState { MemoryPressureState::Idle };
|
||||
std::atomic<bool> GLVariableAllocationSupport::_memoryPressureStateStale { false };
|
||||
const uvec3 GLVariableAllocationSupport::INITIAL_MIP_TRANSFER_DIMENSIONS { 64, 64, 1 };
|
||||
WorkQueue GLVariableAllocationSupport::_transferQueue;
|
||||
WorkQueue GLVariableAllocationSupport::_promoteQueue;
|
||||
WorkQueue GLVariableAllocationSupport::_demoteQueue;
|
||||
size_t GLVariableAllocationSupport::_frameTexturesCreated { 0 };
|
||||
|
||||
#define OVERSUBSCRIBED_PRESSURE_VALUE 0.95f
|
||||
#define UNDERSUBSCRIBED_PRESSURE_VALUE 0.85f
|
||||
#define DEFAULT_ALLOWED_TEXTURE_MEMORY_MB ((size_t)1024)
|
||||
|
||||
static const size_t DEFAULT_ALLOWED_TEXTURE_MEMORY = MB_TO_BYTES(DEFAULT_ALLOWED_TEXTURE_MEMORY_MB);
|
||||
|
||||
using TransferJob = GLVariableAllocationSupport::TransferJob;
|
||||
|
||||
const uvec3 GLVariableAllocationSupport::MAX_TRANSFER_DIMENSIONS { 1024, 1024, 1 };
|
||||
const size_t GLVariableAllocationSupport::MAX_TRANSFER_SIZE = GLVariableAllocationSupport::MAX_TRANSFER_DIMENSIONS.x * GLVariableAllocationSupport::MAX_TRANSFER_DIMENSIONS.y * 4;
|
||||
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
|
||||
TexturePointer GLVariableAllocationSupport::_currentTransferTexture;
|
||||
TransferJobPointer GLVariableAllocationSupport::_currentTransferJob;
|
||||
QThreadPool* TransferJob::_bufferThreadPool { nullptr };
|
||||
|
||||
void TransferJob::startBufferingThread() {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
_bufferThreadPool = new QThreadPool(qApp);
|
||||
_bufferThreadPool->setMaxThreadCount(1);
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TransferJob::TransferJob(const GLTexture& parent, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines, uint32_t lineOffset)
|
||||
: _parent(parent) {
|
||||
|
||||
auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
|
||||
GLenum format;
|
||||
GLenum internalFormat;
|
||||
GLenum type;
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat());
|
||||
format = texelFormat.format;
|
||||
internalFormat = texelFormat.internalFormat;
|
||||
type = texelFormat.type;
|
||||
_transferSize = _parent._gpuObject.getStoredMipFaceSize(sourceMip, face);
|
||||
|
||||
// If we're copying a subsection of the mip, do additional calculations to find the size and offset of the segment
|
||||
if (0 != lines) {
|
||||
transferDimensions.y = lines;
|
||||
auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
|
||||
auto bytesPerLine = (uint32_t)_transferSize / dimensions.y;
|
||||
_transferOffset = bytesPerLine * lineOffset;
|
||||
_transferSize = bytesPerLine * lines;
|
||||
}
|
||||
|
||||
Backend::texturePendingGPUTransferMemSize.update(0, _transferSize);
|
||||
|
||||
if (_transferSize > GLVariableAllocationSupport::MAX_TRANSFER_SIZE) {
|
||||
qCWarning(gpugllogging) << "Transfer size of " << _transferSize << " exceeds theoretical maximum transfer size";
|
||||
}
|
||||
|
||||
// Buffering can invoke disk IO, so it should be off of the main and render threads
|
||||
_bufferingLambda = [=] {
|
||||
auto mipStorage = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
|
||||
if (mipStorage) {
|
||||
_mipData = mipStorage->createView(_transferSize, _transferOffset);
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "Buffering failed because mip could not be retrieved from texture " << _parent._source.c_str() ;
|
||||
}
|
||||
};
|
||||
|
||||
_transferLambda = [=] {
|
||||
if (_mipData) {
|
||||
_parent.copyMipFaceLinesFromTexture(targetMip, face, transferDimensions, lineOffset, internalFormat, format, type, _mipData->size(), _mipData->readData());
|
||||
_mipData.reset();
|
||||
} else {
|
||||
qCWarning(gpugllogging) << "Transfer failed because mip could not be retrieved from texture " << _parent._source.c_str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TransferJob::TransferJob(const GLTexture& parent, std::function<void()> transferLambda)
|
||||
: _parent(parent), _bufferingRequired(false), _transferLambda(transferLambda) {
|
||||
}
|
||||
|
||||
TransferJob::~TransferJob() {
|
||||
Backend::texturePendingGPUTransferMemSize.update(_transferSize, 0);
|
||||
}
|
||||
|
||||
bool TransferJob::tryTransfer() {
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// Are we ready to transfer
|
||||
if (!bufferingCompleted()) {
|
||||
startBuffering();
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (_bufferingRequired) {
|
||||
_bufferingLambda();
|
||||
}
|
||||
#endif
|
||||
_transferLambda();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
bool TransferJob::bufferingRequired() const {
|
||||
if (!_bufferingRequired) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The default state of a QFuture is with status Canceled | Started | Finished,
|
||||
// so we have to check isCancelled before we check the actual state
|
||||
if (_bufferingStatus.isCanceled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !_bufferingStatus.isStarted();
|
||||
}
|
||||
|
||||
bool TransferJob::bufferingCompleted() const {
|
||||
if (!_bufferingRequired) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The default state of a QFuture is with status Canceled | Started | Finished,
|
||||
// so we have to check isCancelled before we check the actual state
|
||||
if (_bufferingStatus.isCanceled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _bufferingStatus.isFinished();
|
||||
}
|
||||
|
||||
void TransferJob::startBuffering() {
|
||||
if (bufferingRequired()) {
|
||||
assert(_bufferingStatus.isCanceled());
|
||||
_bufferingStatus = QtConcurrent::run(_bufferThreadPool, [=] {
|
||||
_bufferingLambda();
|
||||
});
|
||||
assert(!_bufferingStatus.isCanceled());
|
||||
assert(_bufferingStatus.isStarted());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GLVariableAllocationSupport::GLVariableAllocationSupport() {
|
||||
_memoryPressureStateStale = true;
|
||||
}
|
||||
|
||||
GLVariableAllocationSupport::~GLVariableAllocationSupport() {
|
||||
_memoryPressureStateStale = true;
|
||||
}
|
||||
|
||||
void GLVariableAllocationSupport::addMemoryManagedTexture(const TexturePointer& texturePointer) {
|
||||
_memoryManagedTextures.push_back(texturePointer);
|
||||
if (MemoryPressureState::Idle != _memoryPressureState) {
|
||||
addToWorkQueue(texturePointer);
|
||||
}
|
||||
}
|
||||
|
||||
void GLVariableAllocationSupport::addToWorkQueue(const TexturePointer& texturePointer) {
|
||||
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texturePointer);
|
||||
GLVariableAllocationSupport* vargltexture = dynamic_cast<GLVariableAllocationSupport*>(gltexture);
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
if (vargltexture->canDemote()) {
|
||||
// Demote largest first
|
||||
_demoteQueue.push({ texturePointer, (float)gltexture->size() });
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
if (vargltexture->canPromote()) {
|
||||
// Promote smallest first
|
||||
_promoteQueue.push({ texturePointer, 1.0f / (float)gltexture->size() });
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
if (vargltexture->hasPendingTransfers()) {
|
||||
// Transfer priority given to smaller mips first
|
||||
_transferQueue.push({ texturePointer, 1.0f / (float)gltexture->_gpuObject.evalMipSize(vargltexture->_populatedMip) });
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Idle:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WorkQueue& GLVariableAllocationSupport::getActiveWorkQueue() {
|
||||
static WorkQueue empty;
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
return _demoteQueue;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
return _promoteQueue;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
return _transferQueue;
|
||||
|
||||
case MemoryPressureState::Idle:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
// FIXME hack for stats display
|
||||
QString getTextureMemoryPressureModeString() {
|
||||
switch (GLVariableAllocationSupport::_memoryPressureState) {
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
return "Oversubscribed";
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
return "Undersubscribed";
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
return "Transfer";
|
||||
|
||||
case MemoryPressureState::Idle:
|
||||
return "Idle";
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void GLVariableAllocationSupport::updateMemoryPressure() {
|
||||
static size_t lastAllowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage();
|
||||
|
||||
size_t allowedMemoryAllocation = gpu::Texture::getAllowedGPUMemoryUsage();
|
||||
if (0 == allowedMemoryAllocation) {
|
||||
allowedMemoryAllocation = DEFAULT_ALLOWED_TEXTURE_MEMORY;
|
||||
}
|
||||
|
||||
// If the user explicitly changed the allowed memory usage, we need to mark ourselves stale
|
||||
// so that we react
|
||||
if (allowedMemoryAllocation != lastAllowedMemoryAllocation) {
|
||||
_memoryPressureStateStale = true;
|
||||
lastAllowedMemoryAllocation = allowedMemoryAllocation;
|
||||
}
|
||||
|
||||
if (!_memoryPressureStateStale.exchange(false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
|
||||
|
||||
// Clear any defunct textures (weak pointers that no longer have a valid texture)
|
||||
_memoryManagedTextures.remove_if([&](const TextureWeakPointer& weakPointer) {
|
||||
return weakPointer.expired();
|
||||
});
|
||||
|
||||
// Convert weak pointers to strong. This new list may still contain nulls if a texture was
|
||||
// deleted on another thread between the previous line and this one
|
||||
std::vector<TexturePointer> strongTextures; {
|
||||
strongTextures.reserve(_memoryManagedTextures.size());
|
||||
std::transform(
|
||||
_memoryManagedTextures.begin(), _memoryManagedTextures.end(),
|
||||
std::back_inserter(strongTextures),
|
||||
[](const TextureWeakPointer& p) { return p.lock(); });
|
||||
}
|
||||
|
||||
size_t totalVariableMemoryAllocation = 0;
|
||||
size_t idealMemoryAllocation = 0;
|
||||
bool canDemote = false;
|
||||
bool canPromote = false;
|
||||
bool hasTransfers = false;
|
||||
for (const auto& texture : strongTextures) {
|
||||
// Race conditions can still leave nulls in the list, so we need to check
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texture);
|
||||
GLVariableAllocationSupport* vartexture = dynamic_cast<GLVariableAllocationSupport*>(gltexture);
|
||||
// Track how much the texture thinks it should be using
|
||||
idealMemoryAllocation += texture->evalTotalSize();
|
||||
// Track how much we're actually using
|
||||
totalVariableMemoryAllocation += gltexture->size();
|
||||
canDemote |= vartexture->canDemote();
|
||||
canPromote |= vartexture->canPromote();
|
||||
hasTransfers |= vartexture->hasPendingTransfers();
|
||||
}
|
||||
|
||||
size_t unallocated = idealMemoryAllocation - totalVariableMemoryAllocation;
|
||||
float pressure = (float)totalVariableMemoryAllocation / (float)allowedMemoryAllocation;
|
||||
|
||||
auto newState = MemoryPressureState::Idle;
|
||||
if (pressure < UNDERSUBSCRIBED_PRESSURE_VALUE && (unallocated != 0 && canPromote)) {
|
||||
newState = MemoryPressureState::Undersubscribed;
|
||||
} else if (pressure > OVERSUBSCRIBED_PRESSURE_VALUE && canDemote) {
|
||||
newState = MemoryPressureState::Oversubscribed;
|
||||
} else if (hasTransfers) {
|
||||
newState = MemoryPressureState::Transfer;
|
||||
}
|
||||
|
||||
if (newState != _memoryPressureState) {
|
||||
_memoryPressureState = newState;
|
||||
// Clear the existing queue
|
||||
_transferQueue = WorkQueue();
|
||||
_promoteQueue = WorkQueue();
|
||||
_demoteQueue = WorkQueue();
|
||||
|
||||
// Populate the existing textures into the queue
|
||||
if (_memoryPressureState != MemoryPressureState::Idle) {
|
||||
for (const auto& texture : strongTextures) {
|
||||
// Race conditions can still leave nulls in the list, so we need to check
|
||||
if (!texture) {
|
||||
continue;
|
||||
}
|
||||
addToWorkQueue(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TexturePointer GLVariableAllocationSupport::getNextWorkQueueItem(WorkQueue& workQueue) {
|
||||
while (!workQueue.empty()) {
|
||||
auto workTarget = workQueue.top();
|
||||
|
||||
auto texture = workTarget.first.lock();
|
||||
if (!texture) {
|
||||
workQueue.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether the resulting texture can actually have work performed
|
||||
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texture);
|
||||
GLVariableAllocationSupport* vartexture = dynamic_cast<GLVariableAllocationSupport*>(gltexture);
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
if (vartexture->canDemote()) {
|
||||
return texture;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
if (vartexture->canPromote()) {
|
||||
return texture;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
if (vartexture->hasPendingTransfers()) {
|
||||
return texture;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Idle:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
// If we got here, then the texture has no work to do in the current state,
|
||||
// so pop it off the queue and continue
|
||||
workQueue.pop();
|
||||
}
|
||||
|
||||
return TexturePointer();
|
||||
}
|
||||
|
||||
void GLVariableAllocationSupport::processWorkQueue(WorkQueue& workQueue) {
|
||||
if (workQueue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the front of the work queue to perform work
|
||||
auto texture = getNextWorkQueueItem(workQueue);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the first item off the demote queue
|
||||
PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
|
||||
|
||||
GLTexture* gltexture = Backend::getGPUObject<GLTexture>(*texture);
|
||||
GLVariableAllocationSupport* vartexture = dynamic_cast<GLVariableAllocationSupport*>(gltexture);
|
||||
switch (_memoryPressureState) {
|
||||
case MemoryPressureState::Oversubscribed:
|
||||
vartexture->demote();
|
||||
workQueue.pop();
|
||||
addToWorkQueue(texture);
|
||||
_memoryPressureStateStale = true;
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Undersubscribed:
|
||||
vartexture->promote();
|
||||
workQueue.pop();
|
||||
addToWorkQueue(texture);
|
||||
_memoryPressureStateStale = true;
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Transfer:
|
||||
if (vartexture->executeNextTransfer(texture)) {
|
||||
workQueue.pop();
|
||||
addToWorkQueue(texture);
|
||||
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// Eagerly start the next buffering job if possible
|
||||
texture = getNextWorkQueueItem(workQueue);
|
||||
if (texture) {
|
||||
gltexture = Backend::getGPUObject<GLTexture>(*texture);
|
||||
vartexture = dynamic_cast<GLVariableAllocationSupport*>(gltexture);
|
||||
vartexture->executeNextBuffer(texture);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryPressureState::Idle:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLVariableAllocationSupport::processWorkQueues() {
|
||||
if (MemoryPressureState::Idle == _memoryPressureState) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& workQueue = getActiveWorkQueue();
|
||||
// Do work on the front of the queue
|
||||
processWorkQueue(workQueue);
|
||||
|
||||
if (workQueue.empty()) {
|
||||
_memoryPressureState = MemoryPressureState::Idle;
|
||||
_memoryPressureStateStale = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GLVariableAllocationSupport::manageMemory() {
|
||||
PROFILE_RANGE(render_gpu_gl, __FUNCTION__);
|
||||
updateMemoryPressure();
|
||||
processWorkQueues();
|
||||
}
|
||||
|
||||
bool GLVariableAllocationSupport::executeNextTransfer(const TexturePointer& currentTexture) {
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// If a transfer job is active on the buffering thread, but has not completed it's buffering lambda,
|
||||
// then we need to exit early, since we don't want to have the transfer job leave scope while it's
|
||||
// being used in another thread -- See https://highfidelity.fogbugz.com/f/cases/4626
|
||||
if (_currentTransferJob && !_currentTransferJob->bufferingCompleted()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_populatedMip <= _allocatedMip) {
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
_currentTransferJob.reset();
|
||||
_currentTransferTexture.reset();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the transfer queue is empty, rebuild it
|
||||
if (_pendingTransfers.empty()) {
|
||||
populateTransferQueue();
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (!_pendingTransfers.empty()) {
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// If there is a current transfer, but it's not the top of the pending transfer queue, then it's an orphan, so we want to abandon it.
|
||||
if (_currentTransferJob && _currentTransferJob != _pendingTransfers.front()) {
|
||||
_currentTransferJob.reset();
|
||||
}
|
||||
|
||||
if (!_currentTransferJob) {
|
||||
// Keeping hold of a strong pointer to the transfer job ensures that if the pending transfer queue is rebuilt, the transfer job
|
||||
// doesn't leave scope, causing a crash in the buffering thread
|
||||
_currentTransferJob = _pendingTransfers.front();
|
||||
|
||||
// Keeping hold of a strong pointer during the transfer ensures that the transfer thread cannot try to access a destroyed texture
|
||||
_currentTransferTexture = currentTexture;
|
||||
}
|
||||
|
||||
// transfer jobs use asynchronous buffering of the texture data because it may involve disk IO, so we execute a try here to determine if the buffering
|
||||
// is complete
|
||||
if (_currentTransferJob->tryTransfer()) {
|
||||
_pendingTransfers.pop();
|
||||
// Once a given job is finished, release the shared pointers keeping them alive
|
||||
_currentTransferTexture.reset();
|
||||
_currentTransferJob.reset();
|
||||
result = true;
|
||||
}
|
||||
#else
|
||||
if (_pendingTransfers.front()->tryTransfer()) {
|
||||
_pendingTransfers.pop();
|
||||
result = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
void GLVariableAllocationSupport::executeNextBuffer(const TexturePointer& currentTexture) {
|
||||
if (_currentTransferJob && !_currentTransferJob->bufferingCompleted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the transfer queue is empty, rebuild it
|
||||
if (_pendingTransfers.empty()) {
|
||||
populateTransferQueue();
|
||||
}
|
||||
|
||||
if (!_pendingTransfers.empty()) {
|
||||
if (!_currentTransferJob) {
|
||||
_currentTransferJob = _pendingTransfers.front();
|
||||
_currentTransferTexture = currentTexture;
|
||||
}
|
||||
|
||||
_currentTransferJob->startBuffering();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void GLVariableAllocationSupport::incrementPopulatedSize(Size delta) const {
|
||||
_populatedSize += delta;
|
||||
// Keep the 2 code paths to be able to debug
|
||||
if (_size < _populatedSize) {
|
||||
Backend::textureResourcePopulatedGPUMemSize.update(0, delta);
|
||||
} else {
|
||||
Backend::textureResourcePopulatedGPUMemSize.update(0, delta);
|
||||
}
|
||||
}
|
||||
void GLVariableAllocationSupport::decrementPopulatedSize(Size delta) const {
|
||||
_populatedSize -= delta;
|
||||
// Keep the 2 code paths to be able to debug
|
||||
if (_size < _populatedSize) {
|
||||
Backend::textureResourcePopulatedGPUMemSize.update(delta, 0);
|
||||
} else {
|
||||
Backend::textureResourcePopulatedGPUMemSize.update(delta, 0);
|
||||
}
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2016/05/15
|
||||
// Copyright 2013-2016 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
|
||||
//
|
||||
#ifndef hifi_gpu_gl_GLTexture_h
|
||||
#define hifi_gpu_gl_GLTexture_h
|
||||
|
||||
#include <QtCore/QThreadPool>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "GLShared.h"
|
||||
#include "GLBackend.h"
|
||||
#include "GLTexelFormat.h"
|
||||
#include <thread>
|
||||
|
||||
#define THREADED_TEXTURE_BUFFERING 1
|
||||
|
||||
namespace gpu { namespace gl {
|
||||
|
||||
struct GLFilterMode {
|
||||
GLint minFilter;
|
||||
GLint magFilter;
|
||||
};
|
||||
|
||||
class GLVariableAllocationSupport {
|
||||
friend class GLBackend;
|
||||
|
||||
public:
|
||||
GLVariableAllocationSupport();
|
||||
virtual ~GLVariableAllocationSupport();
|
||||
|
||||
enum class MemoryPressureState {
|
||||
Idle,
|
||||
Transfer,
|
||||
Oversubscribed,
|
||||
Undersubscribed,
|
||||
};
|
||||
|
||||
using QueuePair = std::pair<TextureWeakPointer, float>;
|
||||
struct QueuePairLess {
|
||||
bool operator()(const QueuePair& a, const QueuePair& b) {
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
using WorkQueue = std::priority_queue<QueuePair, std::vector<QueuePair>, QueuePairLess>;
|
||||
|
||||
class TransferJob {
|
||||
using VoidLambda = std::function<void()>;
|
||||
using VoidLambdaQueue = std::queue<VoidLambda>;
|
||||
const GLTexture& _parent;
|
||||
Texture::PixelsPointer _mipData;
|
||||
size_t _transferOffset { 0 };
|
||||
size_t _transferSize { 0 };
|
||||
|
||||
bool _bufferingRequired { true };
|
||||
VoidLambda _transferLambda;
|
||||
VoidLambda _bufferingLambda;
|
||||
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
// Indicates if a transfer from backing storage to interal storage has started
|
||||
QFuture<void> _bufferingStatus;
|
||||
static QThreadPool* _bufferThreadPool;
|
||||
#endif
|
||||
|
||||
public:
|
||||
TransferJob(const TransferJob& other) = delete;
|
||||
TransferJob(const GLTexture& parent, std::function<void()> transferLambda);
|
||||
TransferJob(const GLTexture& parent, uint16_t sourceMip, uint16_t targetMip, uint8_t face, uint32_t lines = 0, uint32_t lineOffset = 0);
|
||||
~TransferJob();
|
||||
bool tryTransfer();
|
||||
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
void startBuffering();
|
||||
bool bufferingRequired() const;
|
||||
bool bufferingCompleted() const;
|
||||
static void startBufferingThread();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void transfer();
|
||||
};
|
||||
|
||||
using TransferJobPointer = std::shared_ptr<TransferJob>;
|
||||
using TransferQueue = std::queue<TransferJobPointer>;
|
||||
static MemoryPressureState _memoryPressureState;
|
||||
|
||||
public:
|
||||
static void addMemoryManagedTexture(const TexturePointer& texturePointer);
|
||||
|
||||
protected:
|
||||
static size_t _frameTexturesCreated;
|
||||
static std::atomic<bool> _memoryPressureStateStale;
|
||||
static std::list<TextureWeakPointer> _memoryManagedTextures;
|
||||
static WorkQueue _transferQueue;
|
||||
static WorkQueue _promoteQueue;
|
||||
static WorkQueue _demoteQueue;
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
static TexturePointer _currentTransferTexture;
|
||||
static TransferJobPointer _currentTransferJob;
|
||||
#endif
|
||||
static const uvec3 INITIAL_MIP_TRANSFER_DIMENSIONS;
|
||||
static const uvec3 MAX_TRANSFER_DIMENSIONS;
|
||||
static const size_t MAX_TRANSFER_SIZE;
|
||||
|
||||
|
||||
static void updateMemoryPressure();
|
||||
static void processWorkQueues();
|
||||
static void processWorkQueue(WorkQueue& workQueue);
|
||||
static TexturePointer getNextWorkQueueItem(WorkQueue& workQueue);
|
||||
static void addToWorkQueue(const TexturePointer& texture);
|
||||
static WorkQueue& getActiveWorkQueue();
|
||||
|
||||
static void manageMemory();
|
||||
|
||||
//bool canPromoteNoAllocate() const { return _allocatedMip < _populatedMip; }
|
||||
bool canPromote() const { return _allocatedMip > _minAllocatedMip; }
|
||||
bool canDemote() const { return _allocatedMip < _maxAllocatedMip; }
|
||||
bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; }
|
||||
#if THREADED_TEXTURE_BUFFERING
|
||||
void executeNextBuffer(const TexturePointer& currentTexture);
|
||||
#endif
|
||||
bool executeNextTransfer(const TexturePointer& currentTexture);
|
||||
virtual void populateTransferQueue() = 0;
|
||||
virtual void promote() = 0;
|
||||
virtual void demote() = 0;
|
||||
|
||||
// THe amount of memory currently allocated
|
||||
Size _size { 0 };
|
||||
|
||||
// The amount of memory currnently populated
|
||||
void incrementPopulatedSize(Size delta) const;
|
||||
void decrementPopulatedSize(Size delta) const;
|
||||
mutable Size _populatedSize { 0 };
|
||||
|
||||
// The allocated mip level, relative to the number of mips in the gpu::Texture object
|
||||
// The relationship between a given glMip to the original gpu::Texture mip is always
|
||||
// glMip + _allocatedMip
|
||||
uint16 _allocatedMip { 0 };
|
||||
// The populated mip level, relative to the number of mips in the gpu::Texture object
|
||||
// This must always be >= the allocated mip
|
||||
uint16 _populatedMip { 0 };
|
||||
// The highest (lowest resolution) mip that we will support, relative to the number
|
||||
// of mips in the gpu::Texture object
|
||||
uint16 _maxAllocatedMip { 0 };
|
||||
// The lowest (highest resolution) mip that we will support, relative to the number
|
||||
// of mips in the gpu::Texture object
|
||||
uint16 _minAllocatedMip { 0 };
|
||||
// Contains a series of lambdas that when executed will transfer data to the GPU, modify
|
||||
// the _populatedMip and update the sampler in order to fully populate the allocated texture
|
||||
// until _populatedMip == _allocatedMip
|
||||
TransferQueue _pendingTransfers;
|
||||
};
|
||||
|
||||
class GLTexture : public GLObject<Texture> {
|
||||
using Parent = GLObject<Texture>;
|
||||
friend class GLBackend;
|
||||
friend class GLVariableAllocationSupport;
|
||||
public:
|
||||
static const uint16_t INVALID_MIP { (uint16_t)-1 };
|
||||
static const uint8_t INVALID_FACE { (uint8_t)-1 };
|
||||
|
||||
~GLTexture();
|
||||
|
||||
const GLuint& _texture { _id };
|
||||
const std::string _source;
|
||||
const GLenum _target;
|
||||
GLTexelFormat _texelFormat;
|
||||
|
||||
static const std::vector<GLenum>& getFaceTargets(GLenum textureType);
|
||||
static uint8_t getFaceCount(GLenum textureType);
|
||||
static GLenum getGLTextureType(const Texture& texture);
|
||||
|
||||
static const uint8_t TEXTURE_2D_NUM_FACES = 1;
|
||||
static const uint8_t TEXTURE_CUBE_NUM_FACES = 6;
|
||||
static const GLenum CUBE_FACE_LAYOUT[TEXTURE_CUBE_NUM_FACES];
|
||||
static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS];
|
||||
static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES];
|
||||
|
||||
protected:
|
||||
virtual Size size() const = 0;
|
||||
virtual void generateMips() const = 0;
|
||||
virtual void syncSampler() const = 0;
|
||||
|
||||
virtual Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const = 0;
|
||||
virtual Size copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip, uint8_t face) const final;
|
||||
virtual void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) {} // Only relevant for Variable Allocation textures
|
||||
|
||||
GLTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
|
||||
};
|
||||
|
||||
class GLExternalTexture : public GLTexture {
|
||||
using Parent = GLTexture;
|
||||
friend class GLBackend;
|
||||
public:
|
||||
~GLExternalTexture();
|
||||
protected:
|
||||
GLExternalTexture(const std::weak_ptr<gl::GLBackend>& backend, const Texture& texture, GLuint id);
|
||||
void generateMips() const override {}
|
||||
void syncSampler() const override {}
|
||||
Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override { return 0;}
|
||||
|
||||
Size size() const override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include "../gl/GLBackend.h"
|
||||
#include "../gl/GLTexture.h"
|
||||
#include <gpu/gl/GLBackend.h>
|
||||
#include <gpu/gl/GLTexture.h>
|
||||
|
||||
|
||||
namespace gpu { namespace gles {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLESBackend.h"
|
||||
#include "../gl/GLBuffer.h"
|
||||
#include <gpu/gl/GLBuffer.h>
|
||||
|
||||
namespace gpu {
|
||||
namespace gles {
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include "../gl/GLFramebuffer.h"
|
||||
#include "../gl/GLTexture.h"
|
||||
#include <gpu/gl/GLFramebuffer.h>
|
||||
#include <gpu/gl/GLTexture.h>
|
||||
|
||||
namespace gpu { namespace gles {
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
#include "GLESBackend.h"
|
||||
|
||||
#include "../gl/GLQuery.h"
|
||||
#include <gpu/gl/GLQuery.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "GLESBackend.h"
|
||||
#include "../gl/GLShader.h"
|
||||
#include <gpu/gl/GLShader.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../gl/GLTexelFormat.h"
|
||||
#include <gpu/gl/GLTexelFormat.h>
|
||||
|
||||
using namespace gpu;
|
||||
using namespace gpu::gl;
|
||||
|
@ -251,9 +251,6 @@ void GLESFixedAllocationTexture::allocateStorage() const {
|
|||
void GLESFixedAllocationTexture::syncSampler() const {
|
||||
Parent::syncSampler();
|
||||
const Sampler& sampler = _gpuObject.getSampler();
|
||||
auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), sampler.getMinMip());
|
||||
|
||||
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip);
|
||||
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
|
||||
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip()));
|
||||
}
|
||||
|
@ -459,7 +456,6 @@ void copyCompressedTexGPUMem(const gpu::Texture& texture, GLenum texTarget, GLui
|
|||
sourceMip._size = (GLint)faceTargets.size() * sourceMip._faceSize;
|
||||
sourceMip._offset = bufferOffset;
|
||||
bufferOffset += sourceMip._size;
|
||||
gpu::gl::checkGLError();
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
|
@ -505,7 +501,6 @@ void copyCompressedTexGPUMem(const gpu::Texture& texture, GLenum texTarget, GLui
|
|||
#endif
|
||||
glCompressedTexSubImage2D(faceTargets[f], destLevel, 0, 0, sourceMip._width, sourceMip._height, internalFormat,
|
||||
sourceMip._faceSize, BUFFER_OFFSET(sourceMip._offset + f * sourceMip._faceSize));
|
||||
gpu::gl::checkGLError();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "AnimDebugDraw.h"
|
||||
|
||||
#include <qmath.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
|
@ -21,7 +22,6 @@
|
|||
|
||||
#include "animdebugdraw_vert.h"
|
||||
#include "animdebugdraw_frag.h"
|
||||
|
||||
class AnimDebugDrawData {
|
||||
public:
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ static const int VERTICES_PER_TRIANGLE = 3;
|
|||
|
||||
static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element TEXCOORD0_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV };
|
||||
static const gpu::Element TANGENT_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
|
||||
static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
|
||||
static const gpu::Element TEXCOORD4_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::XYZW };
|
||||
|
||||
|
@ -107,8 +109,10 @@ static gpu::Stream::FormatPointer SOLID_STREAM_FORMAT;
|
|||
static gpu::Stream::FormatPointer INSTANCED_SOLID_STREAM_FORMAT;
|
||||
static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
|
||||
|
||||
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
|
||||
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
|
||||
static const uint SHAPE_VERTEX_STRIDE = sizeof(GeometryCache::ShapeVertex); // position, normal, texcoords, tangent
|
||||
static const uint SHAPE_NORMALS_OFFSET = offsetof(GeometryCache::ShapeVertex, normal);
|
||||
static const uint SHAPE_TEXCOORD0_OFFSET = offsetof(GeometryCache::ShapeVertex, uv);
|
||||
static const uint SHAPE_TANGENT_OFFSET = offsetof(GeometryCache::ShapeVertex, tangent);
|
||||
|
||||
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
|
||||
|
||||
|
@ -167,16 +171,20 @@ std::vector<vec3> polygon() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices) {
|
||||
void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices) {
|
||||
gpu::Buffer::Size offset = vertexBuffer->getSize();
|
||||
vertexBuffer->append(vertices);
|
||||
|
||||
gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3);
|
||||
gpu::Buffer::Size viewSize = vertices.size() * sizeof(ShapeVertex);
|
||||
|
||||
_positionView = gpu::BufferView(vertexBuffer, offset,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
|
||||
_normalView = gpu::BufferView(vertexBuffer, offset + SHAPE_NORMALS_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, NORMAL_ELEMENT);
|
||||
_texCoordView = gpu::BufferView(vertexBuffer, offset + SHAPE_TEXCOORD0_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, TEXCOORD0_ELEMENT);
|
||||
_tangentView = gpu::BufferView(vertexBuffer, offset + SHAPE_TANGENT_OFFSET,
|
||||
viewSize, SHAPE_VERTEX_STRIDE, TANGENT_ELEMENT);
|
||||
}
|
||||
|
||||
void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices) {
|
||||
|
@ -202,6 +210,8 @@ void GeometryCache::ShapeData::setupIndices(gpu::BufferPointer& indexBuffer, con
|
|||
void GeometryCache::ShapeData::setupBatch(gpu::Batch& batch) const {
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, _positionView);
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL, _normalView);
|
||||
batch.setInputBuffer(gpu::Stream::TEXCOORD, _texCoordView);
|
||||
batch.setInputBuffer(gpu::Stream::TANGENT, _tangentView);
|
||||
batch.setIndexBuffer(_indicesView);
|
||||
}
|
||||
|
||||
|
@ -268,14 +278,14 @@ static IndexPair indexToken(geometry::Index a, geometry::Index b) {
|
|||
template <size_t N>
|
||||
void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
using namespace geometry;
|
||||
VertexVector vertices;
|
||||
std::vector<GeometryCache::ShapeVertex> vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
IndexPairs wireSeenIndices;
|
||||
|
||||
size_t faceCount = shape.faces.size();
|
||||
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
|
||||
|
||||
vertices.reserve(N * faceCount * 2);
|
||||
vertices.reserve(N * faceCount);
|
||||
solidIndices.reserve(faceIndexCount * faceCount);
|
||||
|
||||
Index baseVertex = 0;
|
||||
|
@ -284,11 +294,35 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
|
|||
// Compute the face normal
|
||||
vec3 faceNormal = shape.getFaceNormal(f);
|
||||
|
||||
// Find two points on this face with the same Y tex coords, and find the vector going from the one with the smaller X tex coord to the one with the larger X tex coord
|
||||
vec3 faceTangent = vec3(0.0f);
|
||||
Index i1 = 0;
|
||||
Index i2 = i1 + 1;
|
||||
while (i1 < N) {
|
||||
if (shape.texCoords[f * N + i1].y == shape.texCoords[f * N + i2].y) {
|
||||
break;
|
||||
}
|
||||
if (i2 == N - 1) {
|
||||
i1++;
|
||||
i2 = i1 + 1;
|
||||
} else {
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i1 < N && i2 < N) {
|
||||
vec3 p1 = shape.vertices[face[i1]];
|
||||
vec3 p2 = shape.vertices[face[i2]];
|
||||
faceTangent = glm::normalize(p1 - p2);
|
||||
if (shape.texCoords[f * N + i1].x < shape.texCoords[f * N + i2].x) {
|
||||
faceTangent *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the vertices for the face
|
||||
for (Index i = 0; i < N; i++) {
|
||||
Index originalIndex = face[i];
|
||||
vertices.push_back(shape.vertices[originalIndex]);
|
||||
vertices.push_back(faceNormal);
|
||||
vertices.emplace_back(shape.vertices[originalIndex], faceNormal, shape.texCoords[f * N + i], faceTangent);
|
||||
}
|
||||
|
||||
// Create the wire indices for unseen edges
|
||||
|
@ -316,21 +350,95 @@ void setupFlatShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N
|
|||
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
|
||||
}
|
||||
|
||||
vec2 calculateSphereTexCoord(const vec3& vertex) {
|
||||
float u = 1.0f - (std::atan2(-vertex.z, -vertex.x) / ((float)M_PI) + 1.0f) * 0.5f;
|
||||
if (vertex.y == 1.0f || vertex.y == -1.0f) {
|
||||
// Remember points at the top so we don't treat them as being along the seam
|
||||
u = NAN;
|
||||
}
|
||||
float v = 0.5f - std::asin(vertex.y) / (float)M_PI;
|
||||
return vec2(u, v);
|
||||
}
|
||||
|
||||
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
|
||||
|
||||
vec3 calculateSphereTangent(float u) {
|
||||
float phi = u * M_PI_TIMES_2;
|
||||
return -glm::normalize(glm::vec3(glm::sin(phi), 0.0f, glm::cos(phi)));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid<N>& shape, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
using namespace geometry;
|
||||
|
||||
VertexVector vertices;
|
||||
vertices.reserve(shape.vertices.size() * 2);
|
||||
std::vector<GeometryCache::ShapeVertex> vertices;
|
||||
vertices.reserve(shape.vertices.size());
|
||||
for (const auto& vertex : shape.vertices) {
|
||||
vertices.push_back(vertex);
|
||||
vertices.push_back(vertex);
|
||||
// We'll fill in the correct tangents later, once we correct the UVs
|
||||
vertices.emplace_back(vertex, vertex, calculateSphereTexCoord(vertex), vec3(0.0f));
|
||||
}
|
||||
|
||||
// We need to fix up the sphere's UVs because it's actually a tesselated icosahedron. See http://mft-dev.dk/uv-mapping-sphere/
|
||||
size_t faceCount = shape.faces.size();
|
||||
for (size_t f = 0; f < faceCount; f++) {
|
||||
// Fix zipper
|
||||
{
|
||||
float& u1 = vertices[shape.faces[f][0]].uv.x;
|
||||
float& u2 = vertices[shape.faces[f][1]].uv.x;
|
||||
float& u3 = vertices[shape.faces[f][2]].uv.x;
|
||||
|
||||
if (glm::isnan(u1)) {
|
||||
u1 = (u2 + u3) / 2.0f;
|
||||
}
|
||||
if (glm::isnan(u2)) {
|
||||
u2 = (u1 + u3) / 2.0f;
|
||||
}
|
||||
if (glm::isnan(u3)) {
|
||||
u3 = (u1 + u2) / 2.0f;
|
||||
}
|
||||
|
||||
const float U_THRESHOLD = 0.25f;
|
||||
float max = glm::max(u1, glm::max(u2, u3));
|
||||
float min = glm::min(u1, glm::min(u2, u3));
|
||||
|
||||
if (max - min > U_THRESHOLD) {
|
||||
if (u1 < U_THRESHOLD) {
|
||||
u1 += 1.0f;
|
||||
}
|
||||
if (u2 < U_THRESHOLD) {
|
||||
u2 += 1.0f;
|
||||
}
|
||||
if (u3 < U_THRESHOLD) {
|
||||
u3 += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix swirling at poles
|
||||
for (Index i = 0; i < N; i++) {
|
||||
Index originalIndex = shape.faces[f][i];
|
||||
if (shape.vertices[originalIndex].y == 1.0f || shape.vertices[originalIndex].y == -1.0f) {
|
||||
float uSum = 0.0f;
|
||||
for (Index i2 = 1; i2 <= N - 1; i2++) {
|
||||
float u = vertices[shape.faces[f][(i + i2) % N]].uv.x;
|
||||
uSum += u;
|
||||
}
|
||||
uSum /= (float)(N - 1);
|
||||
vertices[originalIndex].uv.x = uSum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in tangents
|
||||
for (Index i = 0; i < N; i++) {
|
||||
vec3 tangent = calculateSphereTangent(vertices[shape.faces[f][i]].uv.x);
|
||||
vertices[shape.faces[f][i]].tangent = tangent;
|
||||
}
|
||||
}
|
||||
|
||||
IndexVector solidIndices, wireIndices;
|
||||
IndexPairs wireSeenIndices;
|
||||
|
||||
size_t faceCount = shape.faces.size();
|
||||
size_t faceIndexCount = triangulatedFaceIndexCount<N>();
|
||||
|
||||
solidIndices.reserve(faceIndexCount * faceCount);
|
||||
|
@ -365,25 +473,22 @@ void setupSmoothShape(GeometryCache::ShapeData& shapeData, const geometry::Solid
|
|||
template <uint32_t N>
|
||||
void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer, bool isConical = false) {
|
||||
using namespace geometry;
|
||||
VertexVector vertices;
|
||||
std::vector<GeometryCache::ShapeVertex> vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
|
||||
// Top (if not conical) and bottom faces
|
||||
std::vector<vec3> shape = polygon<N>();
|
||||
if (isConical) {
|
||||
for (uint32_t i = 0; i < N; i++) {
|
||||
vertices.push_back(vec3(0.0f, 0.5f, 0.0f));
|
||||
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
|
||||
vertices.emplace_back(vec3(0.0f, 0.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec2((float)i / (float)N, 1.0f), vec3(0.0f));
|
||||
}
|
||||
} else {
|
||||
for (const vec3& v : shape) {
|
||||
vertices.push_back(vec3(v.x, 0.5f, v.z));
|
||||
vertices.push_back(vec3(0.0f, 1.0f, 0.0f));
|
||||
vertices.emplace_back(vec3(v.x, 0.5f, v.z), vec3(0.0f, 1.0f, 0.0f), vec2(v.x, v.z) + vec2(0.5f), vec3(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
for (const vec3& v : shape) {
|
||||
vertices.push_back(vec3(v.x, -0.5f, v.z));
|
||||
vertices.push_back(vec3(0.0f, -1.0f, 0.0f));
|
||||
vertices.emplace_back(vec3(v.x, -0.5f, v.z), vec3(0.0f, -1.0f, 0.0f), vec2(-v.x, v.z) + vec2(0.5f), vec3(-1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
Index baseVertex = 0;
|
||||
for (uint32_t i = 2; i < N; i++) {
|
||||
|
@ -412,15 +517,16 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
|
|||
vec3 topRight = (isConical ? vec3(0.0f, 0.5f, 0.0f) : vec3(right.x, 0.5f, right.z));
|
||||
vec3 bottomLeft = vec3(left.x, -0.5f, left.z);
|
||||
vec3 bottomRight = vec3(right.x, -0.5f, right.z);
|
||||
vec3 tangent = glm::normalize(bottomLeft - bottomRight);
|
||||
|
||||
vertices.push_back(topLeft);
|
||||
vertices.push_back(normal);
|
||||
vertices.push_back(bottomLeft);
|
||||
vertices.push_back(normal);
|
||||
vertices.push_back(topRight);
|
||||
vertices.push_back(normal);
|
||||
vertices.push_back(bottomRight);
|
||||
vertices.push_back(normal);
|
||||
// Our tex coords go in the opposite direction as our vertices
|
||||
float u = 1.0f - (float)i / (float)N;
|
||||
float u2 = 1.0f - (float)(i + 1) / (float)N;
|
||||
|
||||
vertices.emplace_back(topLeft, normal, vec2(u, 0.0f), tangent);
|
||||
vertices.emplace_back(bottomLeft, normal, vec2(u, 1.0f), tangent);
|
||||
vertices.emplace_back(topRight, normal, vec2(u2, 0.0f), tangent);
|
||||
vertices.emplace_back(bottomRight, normal, vec2(u2, 1.0f), tangent);
|
||||
|
||||
solidIndices.push_back(baseVertex + 0);
|
||||
solidIndices.push_back(baseVertex + 2);
|
||||
|
@ -439,41 +545,6 @@ void extrudePolygon(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& ver
|
|||
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
|
||||
}
|
||||
|
||||
void drawCircle(GeometryCache::ShapeData& shapeData, gpu::BufferPointer& vertexBuffer, gpu::BufferPointer& indexBuffer) {
|
||||
// Draw a circle with radius 1/4th the size of the bounding box
|
||||
using namespace geometry;
|
||||
|
||||
VertexVector vertices;
|
||||
IndexVector solidIndices, wireIndices;
|
||||
const int NUM_CIRCLE_VERTICES = 64;
|
||||
|
||||
std::vector<vec3> shape = polygon<NUM_CIRCLE_VERTICES>();
|
||||
for (const vec3& v : shape) {
|
||||
vertices.push_back(vec3(v.x, 0.0f, v.z));
|
||||
vertices.push_back(vec3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
Index baseVertex = 0;
|
||||
for (uint32_t i = 2; i < NUM_CIRCLE_VERTICES; i++) {
|
||||
solidIndices.push_back(baseVertex + 0);
|
||||
solidIndices.push_back(baseVertex + i);
|
||||
solidIndices.push_back(baseVertex + i - 1);
|
||||
solidIndices.push_back(baseVertex + NUM_CIRCLE_VERTICES);
|
||||
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES - 1);
|
||||
solidIndices.push_back(baseVertex + i + NUM_CIRCLE_VERTICES);
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i <= NUM_CIRCLE_VERTICES; i++) {
|
||||
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES));
|
||||
wireIndices.push_back(baseVertex + i - 1);
|
||||
wireIndices.push_back(baseVertex + (i % NUM_CIRCLE_VERTICES) + NUM_CIRCLE_VERTICES);
|
||||
wireIndices.push_back(baseVertex + (i - 1) + NUM_CIRCLE_VERTICES);
|
||||
}
|
||||
|
||||
shapeData.setupVertices(vertexBuffer, vertices);
|
||||
shapeData.setupIndices(indexBuffer, solidIndices, wireIndices);
|
||||
}
|
||||
|
||||
// FIXME solids need per-face vertices, but smooth shaded
|
||||
// components do not. Find a way to support using draw elements
|
||||
// or draw arrays as appropriate
|
||||
|
@ -506,9 +577,9 @@ void GeometryCache::buildShapes() {
|
|||
// Line
|
||||
{
|
||||
ShapeData& shapeData = _shapes[Line];
|
||||
shapeData.setupVertices(_shapeVertices, VertexVector {
|
||||
vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f),
|
||||
vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f)
|
||||
shapeData.setupVertices(_shapeVertices, std::vector<ShapeVertex> {
|
||||
ShapeVertex(vec3(-0.5f, 0.0f, 0.0f), vec3(-0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f)),
|
||||
ShapeVertex(vec3(0.5f, 0.0f, 0.0f), vec3(0.5f, 0.0f, 0.0f), vec2(0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f))
|
||||
});
|
||||
IndexVector wireIndices;
|
||||
// Only two indices
|
||||
|
@ -572,6 +643,8 @@ gpu::Stream::FormatPointer& getSolidStreamFormat() {
|
|||
SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
|
||||
SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
|
||||
}
|
||||
return SOLID_STREAM_FORMAT;
|
||||
}
|
||||
|
@ -581,6 +654,8 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() {
|
|||
INSTANCED_SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
|
||||
INSTANCED_SOLID_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
}
|
||||
return INSTANCED_SOLID_STREAM_FORMAT;
|
||||
|
@ -591,6 +666,8 @@ gpu::Stream::FormatPointer& getInstancedSolidFadeStreamFormat() {
|
|||
INSTANCED_SOLID_FADE_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, POSITION_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::NORMAL, gpu::Stream::NORMAL, NORMAL_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD0, gpu::Stream::TEXCOORD0, TEXCOORD0_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TANGENT, gpu::Stream::TANGENT, TANGENT_ELEMENT);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::COLOR, gpu::Stream::COLOR, COLOR_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD2, gpu::Stream::TEXCOORD2, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
INSTANCED_SOLID_FADE_STREAM_FORMAT->setAttribute(gpu::Stream::TEXCOORD3, gpu::Stream::TEXCOORD3, TEXCOORD4_ELEMENT, 0, gpu::Stream::PER_INSTANCE);
|
||||
|
@ -893,6 +970,7 @@ void GeometryCache::updateVertices(int id, const QVector<glm::vec2>& points, con
|
|||
|
||||
details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0);
|
||||
details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET);
|
||||
// TODO: circle3D overlays use this to define their vertices, so they need tex coords
|
||||
details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
|
||||
|
||||
details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride);
|
||||
|
|
|
@ -354,13 +354,24 @@ public:
|
|||
/// Set a batch to the simple pipeline, returning the previous pipeline
|
||||
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
|
||||
|
||||
struct ShapeVertex {
|
||||
ShapeVertex(const vec3& pos, const vec3& normal, const vec2& uv, const vec3& tangent) : pos(pos), normal(normal), uv(uv), tangent(tangent) {}
|
||||
|
||||
vec3 pos;
|
||||
vec3 normal;
|
||||
vec2 uv;
|
||||
vec3 tangent;
|
||||
};
|
||||
|
||||
struct ShapeData {
|
||||
gpu::BufferView _positionView;
|
||||
gpu::BufferView _normalView;
|
||||
gpu::BufferView _texCoordView;
|
||||
gpu::BufferView _tangentView;
|
||||
gpu::BufferView _indicesView;
|
||||
gpu::BufferView _wireIndicesView;
|
||||
|
||||
void setupVertices(gpu::BufferPointer& vertexBuffer, const geometry::VertexVector& vertices);
|
||||
void setupVertices(gpu::BufferPointer& vertexBuffer, const std::vector<ShapeVertex>& vertices);
|
||||
void setupIndices(gpu::BufferPointer& indexBuffer, const geometry::IndexVector& indices, const geometry::IndexVector& wireIndices);
|
||||
void setupBatch(gpu::Batch& batch) const;
|
||||
void draw(gpu::Batch& batch) const;
|
||||
|
|
|
@ -148,25 +148,25 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
<@func evalMaterialNormal(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
{
|
||||
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
|
||||
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
|
||||
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
|
||||
vec3 localNormal = <$fetchedNormal$>;
|
||||
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
|
||||
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func tangentToViewSpaceLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
<@func evalMaterialNormalLOD(fragPos, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
|
||||
{
|
||||
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
|
||||
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
|
||||
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
|
||||
// attenuate the normal map divergence from the mesh normal based on distance
|
||||
// THe attenuation range [20,100] meters from the eye is arbitrary for now
|
||||
// The attenuation range [20,100] meters from the eye is arbitrary for now
|
||||
vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(20.0, 100.0, (-<$fragPos$>).z));
|
||||
<$normal$> = vec3(normalizedTangent * localNormal.x + normalizedNormal * localNormal.y + normalizedBitangent * localNormal.z);
|
||||
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ void main(void) {
|
|||
|
||||
vec3 fragPosition = _position.xyz;
|
||||
vec3 fragNormal;
|
||||
<$tangentToViewSpace(normalTex, _normal, _tangent, fragNormal)$>
|
||||
<$evalMaterialNormal(normalTex, _normal, _tangent, fragNormal)$>
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue