Merge branch 'master' of github.com:highfidelity/hifi into serverless-domains

This commit is contained in:
Seth Alves 2018-03-21 14:30:07 -07:00
commit bea7ee42e2
112 changed files with 1043 additions and 6878 deletions
CMakeLists.txt
assignment-client/src/scripts
cmake
interface
libraries
entities-renderer/src
gl/src/gl
gpu-gl-common
gpu-gl
gpu-gles
render-utils/src

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

@ -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, &currentFBO);
@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@
//
#include "GL41Backend.h"
#include "../gl/GLQuery.h"
#include <gpu/gl/GLQuery.h>
using namespace gpu;
using namespace gpu::gl;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@
//
#include "GL45Backend.h"
#include "../gl/GLQuery.h"
#include <gpu/gl/GLQuery.h>
namespace gpu { namespace gl45 {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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, &currentFBO);
_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();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,7 @@
//
#include "GLESBackend.h"
#include "../gl/GLQuery.h"
#include <gpu/gl/GLQuery.h>
using namespace gpu;
using namespace gpu::gl;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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