Compare commits
200 Commits
cycles-lig
...
vamr-openx
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7ec3023926 | ||
![]() |
37fc5bcd8c | ||
![]() |
88ef625c0b | ||
![]() |
34430ac5f5 | ||
![]() |
00842f9efd | ||
![]() |
04eada72fa | ||
![]() |
17dda0b3e6 | ||
![]() |
b0a333e755 | ||
![]() |
bc8186b5d1 | ||
![]() |
e0bb3f9286 | ||
![]() |
d0b4ec00f6 | ||
![]() |
7b6514c222 | ||
![]() |
c506acf2fc | ||
![]() |
31b8350b01 | ||
![]() |
d7a216704b | ||
![]() |
4b67477732 | ||
![]() |
4a039158e5 | ||
![]() |
61014e1dd9 | ||
![]() |
3441314e40 | ||
![]() |
f175dcc35f | ||
![]() |
756b676076 | ||
![]() |
7462fca737 | ||
![]() |
7c9e18c193 | ||
![]() |
6b69b5349b | ||
![]() |
daba8140c2 | ||
![]() |
599d0611b0 | ||
![]() |
e88970db82 | ||
![]() |
20b0b36479 | ||
![]() |
2c77f2deac | ||
![]() |
fec7ac7c51 | ||
![]() |
2a1ec8ec2a | ||
1548682cde | |||
![]() |
588dea6751 | ||
![]() |
ad4f9a4d98 | ||
![]() |
84466c7d71 | ||
![]() |
de037b031d | ||
![]() |
a21ae28f96 | ||
![]() |
b2424bd781 | ||
![]() |
d0177fc541 | ||
![]() |
4cf8740790 | ||
![]() |
a53b90329a | ||
![]() |
2c41ffa380 | ||
![]() |
cdc2768f65 | ||
![]() |
eb477c67a1 | ||
![]() |
0dd3f3925b | ||
![]() |
9e7c48575a | ||
![]() |
8138099fa9 | ||
![]() |
02de1b9860 | ||
![]() |
57712625f2 | ||
![]() |
96a34d7f50 | ||
![]() |
873223f38d | ||
![]() |
716c6b0c01 | ||
![]() |
62bbd2e37d | ||
![]() |
ba223dfac8 | ||
![]() |
8557997e81 | ||
![]() |
bcc8f7c6be | ||
![]() |
fe7b01a08f | ||
![]() |
5350015d51 | ||
![]() |
3483aa57b3 | ||
![]() |
44a220f721 | ||
![]() |
5274c5cce6 | ||
![]() |
0d70afed19 | ||
![]() |
03b09dbe32 | ||
![]() |
f04a5ad1e4 | ||
![]() |
ab1455e972 | ||
![]() |
b94af38c31 | ||
![]() |
40db778de3 | ||
![]() |
22966f4d35 | ||
![]() |
e8f66ff060 | ||
![]() |
9ac33e56a1 | ||
![]() |
091cc94379 | ||
![]() |
fc31be5ab0 | ||
![]() |
aff49f607a | ||
![]() |
57b77cd193 | ||
![]() |
d58eb8d29d | ||
![]() |
a4310ba85f | ||
![]() |
bd42740ef1 | ||
![]() |
679a4c34fc | ||
![]() |
55362436d9 | ||
![]() |
c1d164070b | ||
![]() |
3a4034a741 | ||
![]() |
a0be113d2e | ||
![]() |
151fb129e7 | ||
![]() |
165c5a5259 | ||
![]() |
74fc1db25b | ||
![]() |
03ff2a8dd5 | ||
d99d15f48d | |||
![]() |
6a998833cd | ||
![]() |
fca4826c7f | ||
![]() |
b0845fc133 | ||
![]() |
70cf8bd9c6 | ||
![]() |
3a2e459f58 | ||
![]() |
330f062099 | ||
![]() |
09872df1c7 | ||
![]() |
67d6399da6 | ||
![]() |
c29724912b | ||
![]() |
99560d9657 | ||
![]() |
b8a7b87873 | ||
![]() |
c9f6c1a054 | ||
![]() |
dd0fcb50b4 | ||
![]() |
c1e9cf00ac | ||
![]() |
84d609f67b | ||
![]() |
86178548d5 | ||
![]() |
d711540a85 | ||
![]() |
6e3158cb00 | ||
![]() |
b216690505 | ||
![]() |
b98896ddd9 | ||
![]() |
a05104d61f | ||
![]() |
7fe1cc8d24 | ||
![]() |
70e84a2c20 | ||
![]() |
084a33ca94 | ||
![]() |
37f619aea3 | ||
![]() |
6904ab10f4 | ||
![]() |
146ef0dd1e | ||
![]() |
5891e86420 | ||
![]() |
2cedad990a | ||
![]() |
109be29e42 | ||
![]() |
13442da69f | ||
![]() |
231dbd53bf | ||
![]() |
d3e48fb096 | ||
![]() |
d544a0b41c | ||
![]() |
cf4799e299 | ||
![]() |
57d9f004aa | ||
![]() |
62cde7a9ef | ||
![]() |
e4fcf25fc5 | ||
![]() |
215c919b33 | ||
![]() |
da44a02d00 | ||
![]() |
867007d9d7 | ||
![]() |
e9ea814233 | ||
![]() |
6b43c82cb5 | ||
![]() |
afbb62fecd | ||
![]() |
8a676e8fa9 | ||
![]() |
c52111e983 | ||
![]() |
d749e8a2c4 | ||
![]() |
8663aa80e6 | ||
![]() |
88b39444a0 | ||
![]() |
4cfc3caa09 | ||
![]() |
28428b3462 | ||
![]() |
24146563a0 | ||
![]() |
2ee9c60c20 | ||
![]() |
fb64675209 | ||
![]() |
76385139cf | ||
![]() |
b18f5a6a81 | ||
![]() |
9d29373b06 | ||
![]() |
f2f1e4dfed | ||
![]() |
0da0f29ade | ||
![]() |
a8519dbac2 | ||
![]() |
d15d07c4f6 | ||
![]() |
d356787a65 | ||
![]() |
a284fa3abb | ||
![]() |
4eeb7523e9 | ||
![]() |
f30fcd6c85 | ||
![]() |
47e8133520 | ||
![]() |
3fa7d59a04 | ||
![]() |
df8dc43946 | ||
![]() |
3b0a2fecfc | ||
![]() |
80af6d534d | ||
![]() |
71c7d61808 | ||
![]() |
637b803b97 | ||
![]() |
314eef0df8 | ||
![]() |
34fa0f8ac6 | ||
![]() |
16366724bd | ||
![]() |
fc8127d070 | ||
![]() |
3ac37fb552 | ||
![]() |
8e51a75772 | ||
![]() |
ba2dab402d | ||
![]() |
796994d222 | ||
![]() |
66e90e9179 | ||
![]() |
1404edbe3a | ||
![]() |
2f68a76409 | ||
![]() |
304d9a20fc | ||
![]() |
b169e327bf | ||
![]() |
7238bbecc4 | ||
![]() |
a49b4ca402 | ||
![]() |
eb0424c946 | ||
![]() |
5d6da57aa3 | ||
![]() |
e968bbc5d8 | ||
![]() |
b1b0e05c54 | ||
![]() |
e547026dfe | ||
![]() |
f816380af5 | ||
![]() |
5e642bfea1 | ||
![]() |
0d1a22f74f | ||
![]() |
20a1af936d | ||
![]() |
c9c1b90532 | ||
![]() |
4192281e14 | ||
![]() |
329deadc9e | ||
![]() |
53845c554d | ||
![]() |
35c9e3beed | ||
![]() |
60f66768cf | ||
![]() |
3e88974a80 | ||
![]() |
09e7d6cd26 | ||
![]() |
5d5ad5d6dd | ||
![]() |
e70894c360 | ||
![]() |
4c11886c4e | ||
![]() |
41e2f2e75f | ||
![]() |
864abbd425 | ||
![]() |
f333e7eb56 | ||
![]() |
a2ac2ec3c3 | ||
![]() |
06d52afcda | ||
![]() |
e65ba62c37 |
@@ -236,6 +236,7 @@ option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
|
||||
option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" )
|
||||
mark_as_advanced(WITH_SYSTEM_BULLET)
|
||||
option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO})
|
||||
option(WITH_OPENXR "Enable VR features through the OpenXR specification" ON)
|
||||
|
||||
# Compositor
|
||||
option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
|
||||
@@ -1762,6 +1763,7 @@ if(FIRST_RUN)
|
||||
info_cfg_option(WITH_CYCLES)
|
||||
info_cfg_option(WITH_FREESTYLE)
|
||||
info_cfg_option(WITH_OPENCOLORIO)
|
||||
info_cfg_option(WITH_OPENXR)
|
||||
info_cfg_option(WITH_OPENIMAGEDENOISE)
|
||||
info_cfg_option(WITH_OPENVDB)
|
||||
info_cfg_option(WITH_ALEMBIC)
|
||||
|
@@ -99,6 +99,7 @@ else()
|
||||
include(cmake/pugixml.cmake)
|
||||
endif()
|
||||
include(cmake/openimagedenoise.cmake)
|
||||
include(cmake/openxr.cmake)
|
||||
|
||||
if(WITH_WEBP)
|
||||
include(cmake/webp.cmake)
|
||||
|
@@ -174,6 +174,8 @@ harvest(opensubdiv/include opensubdiv/include "*.h")
|
||||
harvest(opensubdiv/lib opensubdiv/lib "*.a")
|
||||
harvest(openvdb/include/openvdb openvdb/include/openvdb "*.h")
|
||||
harvest(openvdb/lib openvdb/lib "*.a")
|
||||
harvest(openxr_sdk/include/openxr openxr_sdk/include/openxr "*.h")
|
||||
harvest(openxr_sdk/lib openxr_sdk/src/loader "*.a")
|
||||
harvest(osl/bin osl/bin "oslc")
|
||||
harvest(osl/include osl/include "*.h")
|
||||
harvest(osl/lib osl/lib "*.a")
|
||||
|
53
build_files/build_environment/cmake/openxr.cmake
Normal file
53
build_files/build_environment/cmake/openxr.cmake
Normal file
@@ -0,0 +1,53 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
|
||||
set(OPENXR_SDK_EXTRA_ARGS
|
||||
-DBUILD_API_LAYERS=ON
|
||||
-DBUILD_FORCE_GENERATION=ON
|
||||
-DBUILD_LOADER=ON
|
||||
-DBUILD_SPECIFICATION=OFF
|
||||
-DBUILD_TESTS=OFF
|
||||
-DDYNAMIC_LOADER=OFF
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_openxr_sdk
|
||||
URL ${OPENXR_SDK_URI}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
URL_HASH MD5=${OPENXR_SDK_HASH}
|
||||
PREFIX ${BUILD_DIR}/openxr_sdk
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openxr_sdk ${DEFAULT_CMAKE_FLAGS} ${OPENXR_SDK_EXTRA_ARGS}
|
||||
PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/openxr_sdk/src/external_openxr_sdk < ${PATCH_DIR}/openxr_sdk.diff
|
||||
INSTALL_DIR ${LIBDIR}/openxr_sdk
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
if(BUILD_MODE STREQUAL Release)
|
||||
ExternalProject_Add_Step(external_openxr_sdk after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openxr_sdk/include/openxr ${HARVEST_TARGET}/openxr_sdk/include/openxr
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/openxr_sdk/lib ${HARVEST_TARGET}/openxr_sdk/lib
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
if(BUILD_MODE STREQUAL Debug)
|
||||
ExternalProject_Add_Step(external_openxr_sdk after_install
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/openxr_sdk/lib/openxr_loader-1_0.lib ${HARVEST_TARGET}/openxr_sdk/lib/openxr_loader-1_0_d.lib
|
||||
DEPENDEES install
|
||||
)
|
||||
endif()
|
||||
endif()
|
@@ -306,3 +306,7 @@ set(EMBREE_HASH 3d4a1147002ff43939d45140aa9d6fb8)
|
||||
set(OIDN_VERSION 1.0.0)
|
||||
set(OIDN_URI https://github.com/OpenImageDenoise/oidn/releases/download/v${OIDN_VERSION}/oidn-${OIDN_VERSION}.src.zip)
|
||||
set(OIDN_HASH 19fe67b0164e8f020ac8a4f520defe60)
|
||||
|
||||
set(OPENXR_SDK_VERSION 1.0.0)
|
||||
set(OPENXR_SDK_URI https://github.com/KhronosGroup/OpenXR-SDK-Source/archive/release-${OPENXR_SDK_VERSION}.tar.gz)
|
||||
set(OPENXR_SDK_HASH 260bdc87b5a9b7ef35a540e39f875d79)
|
||||
|
@@ -27,16 +27,16 @@ getopt \
|
||||
-o s:i:t:h \
|
||||
--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,\
|
||||
with-all,with-opencollada,with-jack,with-embree,with-oidn,\
|
||||
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
|
||||
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,ver-openxr\
|
||||
force-all,force-python,force-numpy,force-boost,\
|
||||
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
|
||||
force-ffmpeg,force-opencollada,force-alembic,force-embree,force-oidn,\
|
||||
force-ffmpeg,force-opencollada,force-alembic,force-embree,force-oidn,foce-openxr\
|
||||
build-all,build-python,build-numpy,build-boost,\
|
||||
build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
|
||||
build-ffmpeg,build-opencollada,build-alembic,build-embree,build-oidn,\
|
||||
build-ffmpeg,build-opencollada,build-alembic,build-embree,build-oidn,build-openxr\
|
||||
skip-python,skip-numpy,skip-boost,\
|
||||
skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
|
||||
skip-ffmpeg,skip-opencollada,skip-alembic,skip-embree,skip-oidn \
|
||||
skip-ffmpeg,skip-opencollada,skip-alembic,skip-embree,skip-oidn,skip-openxr \
|
||||
-- "$@" \
|
||||
)
|
||||
|
||||
@@ -144,6 +144,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--ver-openvdb=<ver>
|
||||
Force version of OpenVDB library.
|
||||
|
||||
--ver-openxr=<ver>
|
||||
Force version of OpenXR-SDK.
|
||||
|
||||
Note about the --ver-foo options:
|
||||
It may not always work as expected (some libs are actually checked out from a git rev...), yet it might help
|
||||
to fix some build issues (like LLVM mismatch with the version used by your graphic system).
|
||||
@@ -196,6 +199,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--build-ffmpeg
|
||||
Force the build of FFMpeg.
|
||||
|
||||
--build-openxr
|
||||
Force the build of OpenXR-SDK.
|
||||
|
||||
Note about the --build-foo options:
|
||||
* They force the script to prefer building dependencies rather than using available packages.
|
||||
This may make things simpler and allow working around some distribution bugs, but on the other hand it will
|
||||
@@ -254,6 +260,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--force-ffmpeg
|
||||
Force the rebuild of FFMpeg.
|
||||
|
||||
--force-openxr
|
||||
Force the rebuild of OpenXR-SDK.
|
||||
|
||||
Note about the --force-foo options:
|
||||
* They obviously only have an effect if those libraries are built by this script
|
||||
(i.e. if there is no available and satisfactory package)!
|
||||
@@ -303,7 +312,10 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
Unconditionally skip OpenImageDenoise installation/building.
|
||||
|
||||
--skip-ffmpeg
|
||||
Unconditionally skip FFMpeg installation/building.\""
|
||||
Unconditionally skip FFMpeg installation/building.
|
||||
|
||||
--skip-openxr
|
||||
Unconditionally skip OpenXR-SDK installation/building.\""
|
||||
|
||||
##### Main Vars #####
|
||||
|
||||
@@ -416,6 +428,11 @@ FFMPEG_FORCE_REBUILD=false
|
||||
FFMPEG_SKIP=false
|
||||
_ffmpeg_list_sep=";"
|
||||
|
||||
OPENXR_VERSION="1.0.0"
|
||||
OPENXR_FORCE_BUILD=false
|
||||
OPENXR_FORCE_REBUILD=false
|
||||
OPENXR_SKIP=false
|
||||
|
||||
# FFMPEG optional libs.
|
||||
VORBIS_USE=false
|
||||
VORBIS_DEV=""
|
||||
@@ -581,6 +598,11 @@ while true; do
|
||||
OPENVDB_VERSION_MIN=$OPENVDB_VERSION
|
||||
shift; shift; continue
|
||||
;;
|
||||
--ver-openxr)
|
||||
OPENXR_VERSION="$2"
|
||||
OPENXR_VERSION_MIN=$OPENXR_VERSION
|
||||
shift; shift; continue
|
||||
;;
|
||||
--build-all)
|
||||
PYTHON_FORCE_BUILD=true
|
||||
NUMPY_FORCE_BUILD=true
|
||||
@@ -597,6 +619,7 @@ while true; do
|
||||
OIDN_FORCE_BUILD=true
|
||||
FFMPEG_FORCE_BUILD=true
|
||||
ALEMBIC_FORCE_BUILD=true
|
||||
OPENXR_FORCE_BUILD=true
|
||||
shift; continue
|
||||
;;
|
||||
--build-python)
|
||||
@@ -648,6 +671,9 @@ while true; do
|
||||
--build-alembic)
|
||||
ALEMBIC_FORCE_BUILD=true; shift; continue
|
||||
;;
|
||||
--build-openxr)
|
||||
OPENXR_FORCE_BUILD=true; shift; continue
|
||||
;;
|
||||
--force-all)
|
||||
PYTHON_FORCE_REBUILD=true
|
||||
NUMPY_FORCE_REBUILD=true
|
||||
@@ -664,6 +690,7 @@ while true; do
|
||||
OIDN_FORCE_REBUILD=true
|
||||
FFMPEG_FORCE_REBUILD=true
|
||||
ALEMBIC_FORCE_REBUILD=true
|
||||
OPENXR_FORCE_REBUILD=true
|
||||
shift; continue
|
||||
;;
|
||||
--force-python)
|
||||
@@ -713,6 +740,9 @@ while true; do
|
||||
--force-alembic)
|
||||
ALEMBIC_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--force-openxr)
|
||||
OPENXR_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--skip-python)
|
||||
PYTHON_SKIP=true; shift; continue
|
||||
;;
|
||||
@@ -758,6 +788,9 @@ while true; do
|
||||
--skip-alembic)
|
||||
ALEMBIC_SKIP=true; shift; continue
|
||||
;;
|
||||
--skip-openxr)
|
||||
OPENXR_SKIP=true; shift; continue
|
||||
;;
|
||||
--)
|
||||
# no more arguments to parse
|
||||
break
|
||||
@@ -884,6 +917,12 @@ OIDN_SOURCE=( "https://github.com/OpenImageDenoise/oidn/releases/download/v${OID
|
||||
|
||||
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
|
||||
|
||||
OPENXR_USE_REPO=false
|
||||
OPENXR_SOURCE=("https://github.com/KhronosGroup/OpenXR-SDK-Source/archive/release-$OPENXR_VERSION.tar.gz")
|
||||
#~ OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK-Source.git")
|
||||
#~ OPENXR_REPO_UID="348912bf9bfaf445ac2974bda19fd0d50496460b"
|
||||
#~ OPENXR_REPO_BRANCH="master"
|
||||
|
||||
# C++11 is required now
|
||||
CXXFLAGS_BACK=$CXXFLAGS
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
@@ -2799,6 +2838,103 @@ compile_FFmpeg() {
|
||||
}
|
||||
|
||||
|
||||
#### Build OpenXR SDK ####
|
||||
_init_openxr_sdk() {
|
||||
_src=$SRC/OpenXR-SDK-$OPENXR_VERSION
|
||||
_git=true
|
||||
_inst=$INST/openxr-sdk-$OPENXR_VERSION
|
||||
_inst_shortcut=$INST/openxr-sdk
|
||||
}
|
||||
|
||||
clean_OpenXR_SDK() {
|
||||
_init_openxr_sdk
|
||||
_clean
|
||||
}
|
||||
|
||||
compile_OpenXR_SDK() {
|
||||
if [ "$NO_BUILD" = true ]; then
|
||||
WARNING "--no-build enabled, OpenXR will not be compiled!"
|
||||
return
|
||||
fi
|
||||
|
||||
# To be changed each time we make edits that would modify the compiled result!
|
||||
openxr_magic=0
|
||||
_init_openxr_sdk
|
||||
|
||||
# Clean install if needed!
|
||||
magic_compile_check openxr-$OPENXR_VERSION $openxr_magic
|
||||
if [ $? -eq 1 -o "$OPENXR_FORCE_REBUILD" = true ]; then
|
||||
clean_OpenXR_SDK
|
||||
fi
|
||||
|
||||
if [ ! -d $_inst ]; then
|
||||
INFO "Building OpenXR-SDK-$OPENXR_VERSION"
|
||||
|
||||
prepare_opt
|
||||
|
||||
if [ ! -d $_src ]; then
|
||||
mkdir -p $SRC
|
||||
|
||||
if [ "$OPENXR_USE_REPO" = true ]; then
|
||||
git clone $OPENXR_SOURCE_REPO $_src
|
||||
else
|
||||
download OPENXR_SOURCE[@] "$_src.tar.gz"
|
||||
INFO "Unpacking OpenXR-SDK-$OPENXR_VERSION"
|
||||
tar -C $SRC --transform "s,(.*/?)OpenXR-SDK-[^/]*(.*),\1OpenXR-SDK-$OPENXR_VERSION\2,x" \
|
||||
-xf $_src.tar.gz
|
||||
fi
|
||||
fi
|
||||
|
||||
cd $_src
|
||||
|
||||
if [ "$OPENXR_USE_REPO" = true ]; then
|
||||
git pull origin $OPENXR_REPO_BRANCH
|
||||
|
||||
# Stick to same rev as windows' libs...
|
||||
git checkout $OPENXR_REPO_UID
|
||||
git reset --hard
|
||||
fi
|
||||
|
||||
# Always refresh the whole build!
|
||||
if [ -d build ]; then
|
||||
rm -rf build
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake_d="-D CMAKE_BUILD_TYPE=Release"
|
||||
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
|
||||
cmake_d="$cmake_d -D BUILD_API_LAYERS=ON"
|
||||
cmake_d="$cmake_d -D BUILD_FORCE_GENERATION=ON"
|
||||
cmake_d="$cmake_d -D BUILD_LOADER=ON"
|
||||
cmake_d="$cmake_d -D BUILD_SPECIFICATION=OFF"
|
||||
cmake_d="$cmake_d -D BUILD_TESTS=OFF"
|
||||
|
||||
cmake $cmake_d ..
|
||||
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
ERROR "OpenXR-SDK-$OPENXR_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
magic_compile_set openxr-$OPENXR_VERSION $openxr_magic
|
||||
|
||||
cd $CWD
|
||||
INFO "Done compiling OpenXR-SDK-$OPENXR_VERSION!"
|
||||
else
|
||||
INFO "Own OpenXR-SDK-$OPENXR_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-openxr option."
|
||||
fi
|
||||
|
||||
run_ldconfig "openxr"
|
||||
}
|
||||
|
||||
|
||||
#### Install on DEB-like ####
|
||||
get_package_version_DEB() {
|
||||
dpkg-query -W -f '${Version}' $1 | sed -r 's/([0-9]+:)?(([0-9]+\.?)+([0-9]+)).*/\2/'
|
||||
@@ -3323,6 +3459,18 @@ install_DEB() {
|
||||
compile_FFmpeg
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$OPENXR_SKIP" = true ]; then
|
||||
WARNING "Skipping OpenXR-SDK installation, as requested..."
|
||||
elif [ "$OPENXR_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced OpenXR-SDK building, as requested..."
|
||||
compile_OpenXR_SDK
|
||||
else
|
||||
# No package currently!
|
||||
PRINT ""
|
||||
compile_OpenXR_SDK
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -3909,6 +4057,17 @@ install_RPM() {
|
||||
compile_FFmpeg
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$OPENXR_SKIP" = true ]; then
|
||||
WARNING "Skipping OpenXR-SDK installation, as requested..."
|
||||
elif [ "$OPENXR_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced OpenXR-SDK building, as requested..."
|
||||
compile_OpenXR_SDK
|
||||
else
|
||||
# No package currently!
|
||||
compile_OpenXR_SDK
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -4391,6 +4550,17 @@ install_ARCH() {
|
||||
compile_FFmpeg
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$OPENXR_SKIP" = true ]; then
|
||||
WARNING "Skipping OpenXR-SDK installation, as requested..."
|
||||
elif [ "$OPENXR_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced OpenXR-SDK building, as requested..."
|
||||
compile_OpenXR_SDK
|
||||
else
|
||||
# No package currently!
|
||||
compile_OpenXR_SDK
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -4587,6 +4757,17 @@ install_OTHER() {
|
||||
INFO "Forced FFMpeg building, as requested..."
|
||||
compile_FFmpeg
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$OPENXR_SKIP" = true ]; then
|
||||
WARNING "Skipping OpenXR-SDK installation, as requested..."
|
||||
elif [ "$OPENXR_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced OpenXR-SDK building, as requested..."
|
||||
compile_OpenXR_SDK
|
||||
else
|
||||
# No package currently!
|
||||
compile_OpenXR_SDK
|
||||
fi
|
||||
}
|
||||
|
||||
#### Printing User Info ####
|
||||
@@ -4844,6 +5025,17 @@ print_info() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$OPENXR_SKIP" = false ]; then
|
||||
_1="-D WITH_OPENXR=ON"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
if [ -d $INST/openxr-sdk ]; then
|
||||
_1="-D OPENXR_ROOT_DIR=$INST/openxr-sdk"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
PRINT "Or even simpler, just run (in your blender-source dir):"
|
||||
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
|
||||
|
28
build_files/build_environment/patches/openxr_sdk.diff
Normal file
28
build_files/build_environment/patches/openxr_sdk.diff
Normal file
@@ -0,0 +1,28 @@
|
||||
diff -Naur orig/src/loader/CMakeLists.txt external_openxr_sdk/src/loader/CMakeLists.txt
|
||||
--- orig/src/loader/CMakeLists.txt 2019-07-29 07:06:59 -0600
|
||||
+++ external_openxr_sdk/src/loader/CMakeLists.txt 2019-08-20 07:56:51 -0600
|
||||
@@ -128,24 +128,6 @@
|
||||
configure_file("openxr.pc.in" "openxr.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/openxr.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
- foreach(configuration in CMAKE_C_FLAGS_DEBUG
|
||||
- CMAKE_C_FLAGS_RELEASE
|
||||
- CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
- CMAKE_CXX_FLAGS_DEBUG
|
||||
- CMAKE_CXX_FLAGS_RELEASE
|
||||
- CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
- # If building DLLs, force static CRT linkage
|
||||
- if(DYNAMIC_LOADER)
|
||||
- if (${configuration} MATCHES "/MD")
|
||||
- string(REGEX REPLACE "/MD" "/MT" ${configuration} "${${configuration}}")
|
||||
- endif()
|
||||
- else() # Otherwise for static libs, link the CRT dynamically
|
||||
- if (${configuration} MATCHES "/MT")
|
||||
- string(REGEX REPLACE "/MT" "/MD" ${configuration} "${${configuration}}")
|
||||
- endif()
|
||||
- endif()
|
||||
- endforeach()
|
||||
-
|
||||
target_link_libraries(${LOADER_NAME} shlwapi)
|
||||
target_compile_options(${LOADER_NAME} PRIVATE)
|
||||
generate_export_header(${LOADER_NAME})
|
68
build_files/cmake/Modules/FindOpenXR-SDK.cmake
Normal file
68
build_files/cmake/Modules/FindOpenXR-SDK.cmake
Normal file
@@ -0,0 +1,68 @@
|
||||
# - Find OpenXR-SDK library
|
||||
# Find the native OpenXR-SDK includes and library
|
||||
# This module defines
|
||||
# OPENXR_SDK_INCLUDE_DIRS, where to find OpenXR-SDK headers, Set when
|
||||
# OPENXR_SDK_INCLUDE_DIR is found.
|
||||
# OPENXR_SDK_LIBRARIES, libraries to link against to use OpenXR-SDK.
|
||||
# OPENXR_SDK_ROOT_DIR, the base directory to search for OpenXR-SDK.
|
||||
# This can also be an environment variable.
|
||||
# OPENXR_SDK_FOUND, if false, do not try to use OpenXR-SDK.
|
||||
#
|
||||
# also defined, but not for general use are
|
||||
# OPENXR_LOADER_LIBRARY, where to find the OpenXR-SDK library.
|
||||
|
||||
#=============================================================================
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If OPENXR_SDK_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT OPENXR_SDK_ROOT_DIR AND NOT $ENV{OPENXR_SDK_ROOT_DIR} STREQUAL "")
|
||||
SET(OPENXR_SDK_ROOT_DIR $ENV{OPENXR_SDK_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_openxr_sdk_SEARCH_DIRS
|
||||
${OPENXR_SDK_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/lib/openxr-sdk
|
||||
)
|
||||
|
||||
FIND_PATH(OPENXR_SDK_INCLUDE_DIR
|
||||
NAMES
|
||||
openxr/openxr.h
|
||||
HINTS
|
||||
${_openxr_sdk_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(OPENXR_LOADER_LIBRARY
|
||||
NAMES
|
||||
openxr_loader
|
||||
HINTS
|
||||
${_openxr_sdk_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set OPENXR_SDK_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENXR_SDK DEFAULT_MSG
|
||||
OPENXR_LOADER_LIBRARY OPENXR_SDK_INCLUDE_DIR)
|
||||
|
||||
IF(OPENXR_SDK_FOUND)
|
||||
SET(OPENXR_SDK_LIBRARIES ${OPENXR_LOADER_LIBRARY})
|
||||
SET(OPENXR_SDK_INCLUDE_DIRS ${OPENXR_SDK_INCLUDE_DIR})
|
||||
ENDIF(OPENXR_SDK_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
OPENXR_SDK_INCLUDE_DIR
|
||||
OPENXR_LOADER_LIBRARY
|
||||
)
|
115
build_files/cmake/Modules/presentation.cmake
Normal file
115
build_files/cmake/Modules/presentation.cmake
Normal file
@@ -0,0 +1,115 @@
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Copied right from the OpenXR-SDK (src/cmake/presentation.cmake).
|
||||
# Don't forget to add the license header above.
|
||||
|
||||
set(PRESENTATION_BACKENDS xlib xcb wayland)
|
||||
set(PRESENTATION_BACKEND xlib CACHE STRING
|
||||
"Presentation backend chosen at configure time")
|
||||
set_property(CACHE PRESENTATION_BACKEND PROPERTY STRINGS
|
||||
${PRESENTATION_BACKENDS})
|
||||
|
||||
list(FIND PRESENTATION_BACKENDS ${PRESENTATION_BACKEND} index)
|
||||
if(index EQUAL -1)
|
||||
message(FATAL_ERROR "Presentation backend must be one of
|
||||
${PRESENTATION_BACKENDS}")
|
||||
endif()
|
||||
|
||||
message(STATUS "Using presentation backend: ${PRESENTATION_BACKEND}")
|
||||
|
||||
|
||||
if( PRESENTATION_BACKEND MATCHES "xlib" )
|
||||
find_package(X11 REQUIRED)
|
||||
if ((NOT X11_Xxf86vm_LIB) OR (NOT X11_Xrandr_LIB))
|
||||
message(FATAL_ERROR "OpenXR xlib backend requires Xxf86vm and Xrandr")
|
||||
endif()
|
||||
|
||||
add_definitions( -DSUPPORT_X )
|
||||
add_definitions( -DOS_LINUX_XLIB )
|
||||
set( XLIB_LIBRARIES
|
||||
${X11_LIBRARIES}
|
||||
${X11_Xxf86vm_LIB}
|
||||
${X11_Xrandr_LIB} )
|
||||
|
||||
elseif( PRESENTATION_BACKEND MATCHES "xcb" )
|
||||
find_package(PkgConfig REQUIRED)
|
||||
# XCB + XCB GLX is limited to OpenGL 2.1
|
||||
# add_definitions( -DOS_LINUX_XCB )
|
||||
# XCB + Xlib GLX 1.3
|
||||
add_definitions( -DOS_LINUX_XCB_GLX )
|
||||
|
||||
pkg_search_module(X11 REQUIRED x11)
|
||||
pkg_search_module(XCB REQUIRED xcb)
|
||||
pkg_search_module(XCB_RANDR REQUIRED xcb-randr)
|
||||
pkg_search_module(XCB_KEYSYMS REQUIRED xcb-keysyms)
|
||||
pkg_search_module(XCB_GLX REQUIRED xcb-glx)
|
||||
pkg_search_module(XCB_DRI2 REQUIRED xcb-dri2)
|
||||
pkg_search_module(XCB_ICCCM REQUIRED xcb-icccm)
|
||||
|
||||
set( XCB_LIBRARIES
|
||||
${XCB_LIBRARIES}
|
||||
${XCB_KEYSYMS_LIBRARIES}
|
||||
${XCB_RANDR_LIBRARIES}
|
||||
${XCB_GLX_LIBRARIES}
|
||||
${XCB_DRI2_LIBRARIES}
|
||||
${X11_LIBRARIES} )
|
||||
|
||||
elseif( PRESENTATION_BACKEND MATCHES "wayland" )
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(WAYLAND_CLIENT REQUIRED wayland-client)
|
||||
pkg_search_module(WAYLAND_EGL REQUIRED wayland-egl)
|
||||
pkg_search_module(WAYLAND_SCANNER REQUIRED wayland-scanner)
|
||||
pkg_search_module(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.7)
|
||||
pkg_search_module(EGL REQUIRED egl)
|
||||
|
||||
add_definitions( -DOS_LINUX_WAYLAND )
|
||||
set( WAYLAND_LIBRARIES
|
||||
${EGL_LIBRARIES}
|
||||
${WAYLAND_CLIENT_LIBRARIES}
|
||||
${WAYLAND_EGL_LIBRARIES} )
|
||||
|
||||
# generate wayland protocols
|
||||
set(WAYLAND_PROTOCOLS_DIR ${CMAKE_SOURCE_DIR}/wayland-protocols/)
|
||||
file(MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR})
|
||||
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir)
|
||||
pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
|
||||
|
||||
set(PROTOCOL xdg-shell-unstable-v6)
|
||||
set(PROTOCOL_XML
|
||||
${WAYLAND_PROTOCOLS_DATADIR}/unstable/xdg-shell/${PROTOCOL}.xml)
|
||||
|
||||
if( EXISTS ${PROTOCOL_XML} )
|
||||
execute_process(COMMAND
|
||||
${WAYLAND_SCANNER}
|
||||
code
|
||||
${PROTOCOL_XML}
|
||||
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.c)
|
||||
execute_process(COMMAND
|
||||
${WAYLAND_SCANNER}
|
||||
client-header
|
||||
${PROTOCOL_XML}
|
||||
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.h)
|
||||
|
||||
set( WAYLAND_PROTOCOL_SRC
|
||||
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.c
|
||||
${WAYLAND_PROTOCOLS_DIR}/${PROTOCOL}.h )
|
||||
|
||||
include_directories(${WAYLAND_PROTOCOLS_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"xdg-shell-unstable-v6.xml not found in "
|
||||
${WAYLAND_PROTOCOLS_DATADIR}
|
||||
"\nYour wayland-protocols package does not "
|
||||
"contain xdg-shell-unstable-v6.")
|
||||
endif()
|
||||
endif()
|
50
build_files/cmake/Modules/xr_platform_defines.cmake
Normal file
50
build_files/cmake/Modules/xr_platform_defines.cmake
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2017 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# These defines are required as per the OpenXR specification. We can
|
||||
# just take them from the OpenXR-SDK's src/CMakeLists.txt. Not all of
|
||||
# them are needed (e.g. XCB and Wayland), but we just copy them anyway.
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DXR_OS_WINDOWS)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
add_definitions(-DXR_OS_LINUX)
|
||||
endif()
|
||||
|
||||
# Determine the presentation backend for Linux systems.
|
||||
# Use an include because the code is pretty big.
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
include(presentation)
|
||||
endif()
|
||||
|
||||
# Several files use these compile-time platform switches
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
add_definitions( -DXR_USE_PLATFORM_WIN32 )
|
||||
elseif( PRESENTATION_BACKEND MATCHES "xlib" )
|
||||
add_definitions( -DXR_USE_PLATFORM_XLIB )
|
||||
elseif( PRESENTATION_BACKEND MATCHES "xcb" )
|
||||
add_definitions( -DXR_USE_PLATFORM_XCB )
|
||||
elseif( PRESENTATION_BACKEND MATCHES "wayland" )
|
||||
add_definitions( -DXR_USE_PLATFORM_WAYLAND )
|
||||
endif()
|
||||
|
||||
add_definitions(-DXR_USE_GRAPHICS_API_OPENGL)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
add_definitions(-DXR_USE_GRAPHICS_API_D3D)
|
||||
add_definitions(-DXR_USE_GRAPHICS_API_D3D10)
|
||||
add_definitions(-DXR_USE_GRAPHICS_API_D3D11)
|
||||
add_definitions(-DXR_USE_GRAPHICS_API_D3D12)
|
||||
endif()
|
||||
|
@@ -41,6 +41,7 @@ set(WITH_OPENAL ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEDENOISE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENXR ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENMP ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
|
||||
|
@@ -46,6 +46,7 @@ set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEDENOISE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENXR OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
|
||||
|
@@ -42,6 +42,7 @@ set(WITH_OPENAL ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENIMAGEDENOISE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENXR ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENMP ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
|
||||
|
@@ -474,6 +474,9 @@ function(setup_liblinks
|
||||
if(WITH_OPENSUBDIV)
|
||||
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
|
||||
endif()
|
||||
if(WITH_OPENXR)
|
||||
target_link_libraries(${target} ${OPENXR_SDK_LIBRARIES})
|
||||
endif()
|
||||
if(WITH_CYCLES_EMBREE)
|
||||
target_link_libraries(${target} ${EMBREE_LIBRARIES})
|
||||
endif()
|
||||
|
@@ -416,6 +416,14 @@ if(WITH_OPENMP)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
find_package(OpenXR-SDK)
|
||||
if(NOT OPENXR_SDK_FOUND)
|
||||
message(WARNING "OpenXR-SDK was not found, disabling WITH_OPENXR")
|
||||
set(WITH_OPENXR OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(EXETYPE MACOSX_BUNDLE)
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
|
||||
|
@@ -416,6 +416,15 @@ if(WITH_OPENSUBDIV)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
find_package(OpenXR-SDK)
|
||||
if(NOT OPENXR_SDK_FOUND)
|
||||
message(WARNING "OpenXR-SDK was not found, disabling WITH_OPENXR")
|
||||
set(WITH_OPENXR OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
|
||||
if(HAIKU)
|
||||
list(APPEND PLATFORM_LINKLIBS -lnetwork)
|
||||
|
@@ -691,3 +691,15 @@ if(WINDOWS_PYTHON_DEBUG)
|
||||
</Project>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
if(EXISTS ${LIBDIR}/openxr_sdk)
|
||||
set(OPENXR_SDK ${LIBDIR}/openxr_sdk)
|
||||
set(OPENXR_SDK_LIBPATH ${LIBDIR}/openxr_sdk/lib)
|
||||
set(OPENXR_SDK_INCLUDE_DIR ${OPENXR_SDK}/include)
|
||||
set(OPENXR_SDK_LIBRARIES optimized ${OPENXR_SDK_LIBPATH}/openxr_loader-1_0.lib debug ${OPENXR_SDK_LIBPATH}/openxr_loader-1_0_d.lib)
|
||||
else()
|
||||
message(WARNING "OpenXR-SDK was not found, disabling WITH_OPENXR")
|
||||
set(WITH_OPENXR OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -76,3 +76,7 @@ endif()
|
||||
if(WITH_OPENVDB)
|
||||
add_subdirectory(openvdb)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
add_subdirectory(vamr)
|
||||
endif()
|
||||
|
@@ -270,11 +270,13 @@ elseif(WIN32)
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
intern/GHOST_ContextD3D.cpp
|
||||
intern/GHOST_DisplayManagerWin32.cpp
|
||||
intern/GHOST_DropTargetWin32.cpp
|
||||
intern/GHOST_SystemWin32.cpp
|
||||
intern/GHOST_WindowWin32.cpp
|
||||
|
||||
intern/GHOST_ContextD3D.h
|
||||
intern/GHOST_DisplayManagerWin32.h
|
||||
intern/GHOST_DropTargetWin32.h
|
||||
intern/GHOST_SystemWin32.h
|
||||
|
@@ -30,21 +30,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a "handle" for a C++ GHOST object.
|
||||
* A handle is just an opaque pointer to an empty struct.
|
||||
* In the API the pointer is cast to the actual C++ class.
|
||||
* The 'name' argument to the macro is the name of the handle to create.
|
||||
*/
|
||||
|
||||
GHOST_DECLARE_HANDLE(GHOST_SystemHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
|
||||
|
||||
/**
|
||||
* Definition of a callback routine that receives events.
|
||||
* \param event The event received.
|
||||
@@ -193,6 +178,25 @@ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemha
|
||||
extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle);
|
||||
|
||||
#ifdef WIN32
|
||||
/**
|
||||
* Create a new offscreen context.
|
||||
* Never explicitly delete the context, use disposeContext() instead.
|
||||
* \param systemhandle The handle to the system
|
||||
* \return A handle to the new context ( == NULL if creation failed).
|
||||
*/
|
||||
GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
* \param systemhandle The handle to the system
|
||||
* \param contexthandle Handle to the context to be disposed.
|
||||
* \return Indication of success.
|
||||
*/
|
||||
GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the window user data.
|
||||
* \param windowhandle The handle to the window
|
||||
@@ -207,6 +211,11 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl
|
||||
*/
|
||||
extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata);
|
||||
|
||||
/**
|
||||
* Returns whether a window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
extern int GHOST_isUpsideDownWindow(GHOST_WindowHandle windowhandle);
|
||||
|
||||
/**
|
||||
* Dispose a window.
|
||||
* \param systemhandle The handle to the system
|
||||
@@ -706,6 +715,16 @@ extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthan
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL framebuffer handle that serves as a default framebuffer.
|
||||
*/
|
||||
extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Returns whether a context is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
extern int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL framebuffer handle that serves as a default framebuffer.
|
||||
*/
|
||||
|
@@ -56,6 +56,15 @@ class GHOST_IContext {
|
||||
*/
|
||||
virtual GHOST_TSuccess releaseDrawingContext() = 0;
|
||||
|
||||
virtual unsigned int getDefaultFramebuffer() = 0;
|
||||
|
||||
virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
|
||||
/**
|
||||
* Returns if the window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
virtual bool isUpsideDown() const = 0;
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IContext")
|
||||
#endif
|
||||
|
@@ -264,6 +264,12 @@ class GHOST_ISystem {
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext() = 0;
|
||||
|
||||
/**
|
||||
* Overload to allow requesting a different context type. By default only OpenGL is supported.
|
||||
* However by explicitly overloading this a system may add support for others.
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type) = 0;
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
* \param context Pointer to the context to be disposed.
|
||||
|
@@ -241,6 +241,11 @@ class GHOST_IWindow {
|
||||
*/
|
||||
virtual void setUserData(const GHOST_TUserDataPtr userData) = 0;
|
||||
|
||||
/**
|
||||
* Returns if the window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
virtual bool isUpsideDown() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the tablet data (pressure etc).
|
||||
* \return The tablet data (pressure etc).
|
||||
|
@@ -41,6 +41,22 @@
|
||||
} * name
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a "handle" for a C++ GHOST object.
|
||||
* A handle is just an opaque pointer to an empty struct.
|
||||
* In the API the pointer is cast to the actual C++ class.
|
||||
* The 'name' argument to the macro is the name of the handle to create.
|
||||
*/
|
||||
|
||||
GHOST_DECLARE_HANDLE(GHOST_SystemHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_TimerTaskHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_WindowHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_RectangleHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
|
||||
GHOST_DECLARE_HANDLE(GHOST_XrContextHandle);
|
||||
|
||||
typedef char GHOST_TInt8;
|
||||
typedef unsigned char GHOST_TUns8;
|
||||
typedef short GHOST_TInt16;
|
||||
@@ -129,7 +145,10 @@ typedef enum { GHOST_kWindowOrderTop = 0, GHOST_kWindowOrderBottom } GHOST_TWind
|
||||
|
||||
typedef enum {
|
||||
GHOST_kDrawingContextTypeNone = 0,
|
||||
GHOST_kDrawingContextTypeOpenGL
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
#ifdef WIN32
|
||||
GHOST_kDrawingContextTypeD3D,
|
||||
#endif
|
||||
} GHOST_TDrawingContextType;
|
||||
|
||||
typedef enum {
|
||||
|
@@ -127,6 +127,25 @@ GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
return system->disposeContext(context);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
|
||||
return (GHOST_ContextHandle)system->createOffscreenContext(GHOST_kDrawingContextTypeD3D);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return system->disposeContext(context);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
||||
const char *title,
|
||||
GHOST_TInt32 left,
|
||||
@@ -156,6 +175,13 @@ void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr
|
||||
window->setUserData(userdata);
|
||||
}
|
||||
|
||||
int GHOST_isUpsideDownWindow(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||
|
||||
return window->isUpsideDown();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
|
||||
GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
@@ -621,6 +647,20 @@ GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
return context->releaseDrawingContext();
|
||||
}
|
||||
|
||||
unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->getDefaultFramebuffer();
|
||||
}
|
||||
|
||||
int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->isUpsideDown();
|
||||
}
|
||||
|
||||
unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||
|
@@ -149,3 +149,4 @@ void GHOST_Context::initClearGL()
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0.000, 0.000, 0.000, 0.000);
|
||||
}
|
||||
|
||||
|
@@ -38,7 +38,8 @@ class GHOST_Context : public GHOST_IContext {
|
||||
* Constructor.
|
||||
* \param stereoVisual Stereo visual for quad buffered stereo.
|
||||
*/
|
||||
GHOST_Context(bool stereoVisual) : m_stereoVisual(stereoVisual)
|
||||
GHOST_Context(bool stereoVisual)
|
||||
: m_stereoVisual(stereoVisual)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -119,6 +120,14 @@ class GHOST_Context : public GHOST_IContext {
|
||||
return m_stereoVisual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
inline bool isUpsideDown() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OpenGL framebuffer associated with the OpenGL context
|
||||
* \return The ID of an OpenGL framebuffer object.
|
||||
|
446
intern/ghost/intern/GHOST_ContextD3D.cpp
Normal file
446
intern/ghost/intern/GHOST_ContextD3D.cpp
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/wglew.h>
|
||||
|
||||
#include "GHOST_ContextWGL.h" /* For shared drawing */
|
||||
#include "GHOST_ContextD3D.h"
|
||||
|
||||
//#define USE_DRAW_D3D_TEST_TRIANGLE
|
||||
|
||||
HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
|
||||
PFN_D3D11_CREATE_DEVICE GHOST_ContextD3D::s_D3D11CreateDeviceFn = NULL;
|
||||
|
||||
#ifdef USE_DRAW_D3D_TEST_TRIANGLE
|
||||
static void drawTestTriangle(ID3D11Device *m_device,
|
||||
ID3D11DeviceContext *m_device_ctx,
|
||||
GHOST_TInt32 width,
|
||||
GHOST_TInt32 height);
|
||||
#endif
|
||||
|
||||
GHOST_ContextD3D::GHOST_ContextD3D(bool stereoVisual, HWND hWnd)
|
||||
: GHOST_Context(stereoVisual), m_hWnd(hWnd)
|
||||
{
|
||||
}
|
||||
|
||||
GHOST_ContextD3D::~GHOST_ContextD3D()
|
||||
{
|
||||
m_device->Release();
|
||||
m_device_ctx->ClearState();
|
||||
m_device_ctx->Release();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::swapBuffers()
|
||||
{
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::activateDrawingContext()
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::releaseDrawingContext()
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::setupD3DLib()
|
||||
{
|
||||
if (s_d3d_lib == NULL) {
|
||||
s_d3d_lib = LoadLibraryA("d3d11.dll");
|
||||
|
||||
WIN32_CHK(s_d3d_lib != NULL);
|
||||
|
||||
if (s_d3d_lib == NULL) {
|
||||
fprintf(stderr, "LoadLibrary(\"d3d11.dll\") failed!\n");
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_D3D11CreateDeviceFn == NULL) {
|
||||
s_D3D11CreateDeviceFn = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(s_d3d_lib,
|
||||
"D3D11CreateDevice");
|
||||
|
||||
WIN32_CHK(s_D3D11CreateDeviceFn != NULL);
|
||||
|
||||
if (s_D3D11CreateDeviceFn == NULL) {
|
||||
fprintf(stderr, "GetProcAddress(s_d3d_lib, \"D3D11CreateDevice\") failed!\n");
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::initializeDrawingContext()
|
||||
{
|
||||
if (setupD3DLib() == GHOST_kFailure) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
HRESULT hres = s_D3D11CreateDeviceFn(NULL,
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
NULL,
|
||||
// D3D11_CREATE_DEVICE_DEBUG,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
D3D11_SDK_VERSION,
|
||||
&m_device,
|
||||
NULL,
|
||||
&m_device_ctx);
|
||||
|
||||
WIN32_CHK(hres == S_OK);
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::releaseNativeHandles()
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
class GHOST_SharedOpenGLResource {
|
||||
struct SharedData {
|
||||
HANDLE device;
|
||||
GLuint fbo;
|
||||
HANDLE render_buf{nullptr};
|
||||
} m_shared;
|
||||
|
||||
public:
|
||||
GHOST_SharedOpenGLResource(ID3D11Device *device,
|
||||
ID3D11DeviceContext *device_ctx,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
ID3D11RenderTargetView *render_target = nullptr)
|
||||
: m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height)
|
||||
{
|
||||
ID3D11Resource *backbuffer_res;
|
||||
|
||||
if (!render_target) {
|
||||
D3D11_TEXTURE2D_DESC texDesc{};
|
||||
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{};
|
||||
ID3D11Texture2D *tex;
|
||||
|
||||
texDesc.Width = width;
|
||||
texDesc.Height = height;
|
||||
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
texDesc.SampleDesc.Count = 1;
|
||||
texDesc.ArraySize = 1;
|
||||
texDesc.MipLevels = 1;
|
||||
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
device->CreateTexture2D(&texDesc, NULL, &tex);
|
||||
|
||||
renderTargetViewDesc.Format = texDesc.Format;
|
||||
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
renderTargetViewDesc.Texture2D.MipSlice = 0;
|
||||
|
||||
device->CreateRenderTargetView(tex, &renderTargetViewDesc, &render_target);
|
||||
|
||||
tex->Release();
|
||||
}
|
||||
|
||||
m_render_target = render_target;
|
||||
m_render_target->GetResource(&backbuffer_res);
|
||||
backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex);
|
||||
backbuffer_res->Release();
|
||||
}
|
||||
|
||||
~GHOST_SharedOpenGLResource()
|
||||
{
|
||||
m_render_target_tex->Release();
|
||||
m_render_target->Release();
|
||||
|
||||
if (m_is_initialized) {
|
||||
if (m_shared.render_buf) {
|
||||
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
|
||||
}
|
||||
if (m_shared.device) {
|
||||
wglDXCloseDeviceNV(m_shared.device);
|
||||
}
|
||||
glDeleteFramebuffers(1, &m_shared.fbo);
|
||||
glDeleteRenderbuffers(1, &m_gl_render_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void reregisterSharedObject()
|
||||
{
|
||||
if (m_shared.render_buf) {
|
||||
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
|
||||
}
|
||||
|
||||
m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
|
||||
m_render_target_tex,
|
||||
m_gl_render_buf,
|
||||
GL_RENDERBUFFER,
|
||||
WGL_ACCESS_READ_WRITE_NV);
|
||||
if (!m_shared.render_buf) {
|
||||
fprintf(stderr, "Error registering shared object using wglDXRegisterObjectNV()\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess initialize()
|
||||
{
|
||||
m_shared.device = wglDXOpenDeviceNV(m_device);
|
||||
if (m_shared.device == NULL) {
|
||||
fprintf(stderr, "Error opening shared device using wglDXOpenDeviceNV()\n");
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/* Build the renderbuffer. */
|
||||
glGenRenderbuffers(1, &m_gl_render_buf);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_buf);
|
||||
|
||||
reregisterSharedObject();
|
||||
|
||||
/* Build the framebuffer */
|
||||
glGenFramebuffers(1, &m_shared.fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_shared.fbo);
|
||||
glFramebufferRenderbuffer(
|
||||
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_gl_render_buf);
|
||||
m_is_initialized = true;
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
void ensureUpdated(unsigned int width, unsigned int height)
|
||||
{
|
||||
if (m_is_initialized == false) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
if ((m_cur_width != width) || (m_cur_height != height)) {
|
||||
m_cur_width = width;
|
||||
m_cur_height = height;
|
||||
reregisterSharedObject();
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess blit(unsigned int width, unsigned int height)
|
||||
{
|
||||
GLint fbo;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fbo);
|
||||
|
||||
ensureUpdated(width, height);
|
||||
|
||||
const float clear_col[] = {0.8f, 0.5f, 1.0f, 1.0f};
|
||||
m_device_ctx->ClearRenderTargetView(m_render_target, clear_col);
|
||||
m_device_ctx->OMSetRenderTargets(1, &m_render_target, nullptr);
|
||||
|
||||
beginGLOnly();
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared.fbo);
|
||||
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (err != GL_FRAMEBUFFER_COMPLETE) {
|
||||
fprintf(stderr, "Error: Framebuffer incomplete %u\n", err);
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/* No glBlitNamedFramebuffer, gotta be 3.3 compatible. */
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
endGLOnly();
|
||||
|
||||
#ifdef USE_DRAW_D3D_TEST_TRIANGLE
|
||||
drawTestTriangle(m_device, m_device_ctx, m_cur_width, m_cur_height);
|
||||
#endif
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
ID3D11RenderTargetView *m_render_target;
|
||||
ID3D11Texture2D *m_render_target_tex;
|
||||
|
||||
private:
|
||||
void beginGLOnly()
|
||||
{
|
||||
wglDXLockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
|
||||
}
|
||||
void endGLOnly()
|
||||
{
|
||||
wglDXUnlockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
|
||||
}
|
||||
|
||||
ID3D11Device *m_device;
|
||||
ID3D11DeviceContext *m_device_ctx;
|
||||
GLuint m_gl_render_buf;
|
||||
unsigned int m_cur_width, m_cur_height;
|
||||
bool m_is_initialized{false};
|
||||
};
|
||||
|
||||
GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(
|
||||
unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target)
|
||||
{
|
||||
if (!(WGL_NV_DX_interop && WGL_NV_DX_interop2)) {
|
||||
fprintf(stderr,
|
||||
"Error: Can't render OpenGL framebuffer using Direct3D. NV_DX_interop extension not "
|
||||
"available.");
|
||||
return nullptr;
|
||||
}
|
||||
GHOST_SharedOpenGLResource *shared_res = new GHOST_SharedOpenGLResource(
|
||||
m_device, m_device_ctx, width, height, render_target);
|
||||
|
||||
return shared_res;
|
||||
}
|
||||
GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
return createSharedOpenGLResource(width, height, nullptr);
|
||||
}
|
||||
|
||||
void GHOST_ContextD3D::disposeSharedOpenGLResource(GHOST_SharedOpenGLResource *shared_res)
|
||||
{
|
||||
delete shared_res;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::blitFromOpenGLContext(GHOST_SharedOpenGLResource *shared_res,
|
||||
unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
return shared_res->blit(width, height);
|
||||
}
|
||||
|
||||
ID3D11Texture2D *GHOST_ContextD3D::getSharedTexture2D(GHOST_SharedOpenGLResource *shared_res)
|
||||
{
|
||||
return shared_res->m_render_target_tex;
|
||||
}
|
||||
|
||||
#ifdef USE_DRAW_D3D_TEST_TRIANGLE
|
||||
# pragma comment(lib, "D3DCompiler.lib")
|
||||
|
||||
const static std::string vertex_shader_str{
|
||||
"struct VSOut {"
|
||||
"float3 color : Color;"
|
||||
"float4 pos : SV_POSITION;"
|
||||
"};"
|
||||
|
||||
"VSOut main(float2 pos : Position, float3 color : Color)"
|
||||
"{"
|
||||
" VSOut vso;"
|
||||
" vso.pos = float4(pos.x, pos.y, 0.0f, 1.0f);"
|
||||
" vso.color = color;"
|
||||
" return vso;"
|
||||
"}"};
|
||||
const static std::string pixel_shader_str{
|
||||
" float4 main(float3 color : Color) : SV_TARGET"
|
||||
"{"
|
||||
" return float4(color, 1.0f);"
|
||||
"}"};
|
||||
|
||||
# include <wrl/module.h>
|
||||
# include <d3dcompiler.h>
|
||||
|
||||
static void drawTestTriangle(ID3D11Device *m_device,
|
||||
ID3D11DeviceContext *m_device_ctx,
|
||||
GHOST_TInt32 width,
|
||||
GHOST_TInt32 height)
|
||||
{
|
||||
struct Vertex {
|
||||
float x, y;
|
||||
unsigned char r, g, b, a;
|
||||
};
|
||||
Vertex vertices[] = {
|
||||
{0.0f, 0.5f, 255, 0, 0},
|
||||
{0.5f, -0.5f, 0, 255, 0},
|
||||
{-0.5f, -0.5f, 0, 0, 255},
|
||||
|
||||
};
|
||||
const unsigned int stride = sizeof(Vertex);
|
||||
const unsigned int offset = 0;
|
||||
ID3D11Buffer *vertex_buffer;
|
||||
|
||||
D3D11_BUFFER_DESC buffer_desc{};
|
||||
buffer_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
buffer_desc.ByteWidth = sizeof(vertices);
|
||||
buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA init_data{};
|
||||
init_data.pSysMem = vertices;
|
||||
|
||||
m_device->CreateBuffer(&buffer_desc, &init_data, &vertex_buffer);
|
||||
m_device_ctx->IASetVertexBuffers(0, 1, &vertex_buffer, &stride, &offset);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3DBlob> blob;
|
||||
D3DCompile(pixel_shader_str.c_str(),
|
||||
pixel_shader_str.length(),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"main",
|
||||
"ps_5_0",
|
||||
0,
|
||||
0,
|
||||
&blob,
|
||||
NULL);
|
||||
Microsoft::WRL::ComPtr<ID3D11PixelShader> pixel_shader;
|
||||
m_device->CreatePixelShader(
|
||||
blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &pixel_shader);
|
||||
|
||||
D3DCompile(vertex_shader_str.c_str(),
|
||||
vertex_shader_str.length(),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"main",
|
||||
"vs_5_0",
|
||||
0,
|
||||
0,
|
||||
&blob,
|
||||
NULL);
|
||||
Microsoft::WRL::ComPtr<ID3D11VertexShader> vertex_shader;
|
||||
m_device->CreateVertexShader(
|
||||
blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &vertex_shader);
|
||||
|
||||
m_device_ctx->PSSetShader(pixel_shader.Get(), NULL, 0);
|
||||
m_device_ctx->VSSetShader(vertex_shader.Get(), 0, 0);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11InputLayout> input_layout;
|
||||
const D3D11_INPUT_ELEMENT_DESC input_desc[] = {
|
||||
{"Position", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"Color", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
m_device->CreateInputLayout(input_desc,
|
||||
(unsigned int)std::size(input_desc),
|
||||
blob->GetBufferPointer(),
|
||||
blob->GetBufferSize(),
|
||||
&input_layout);
|
||||
m_device_ctx->IASetInputLayout(input_layout.Get());
|
||||
|
||||
m_device_ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
D3D11_VIEWPORT viewport = {};
|
||||
viewport.Width = width;
|
||||
viewport.Height = height;
|
||||
viewport.MaxDepth = 1;
|
||||
m_device_ctx->RSSetViewports(1, &viewport);
|
||||
|
||||
m_device_ctx->Draw(std::size(vertices), 0);
|
||||
}
|
||||
#endif
|
136
intern/ghost/intern/GHOST_ContextD3D.h
Normal file
136
intern/ghost/intern/GHOST_ContextD3D.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#ifndef __GHOST_CONTEXTD3D_H__
|
||||
#define __GHOST_CONTEXTD3D_H__
|
||||
|
||||
#ifndef WIN32
|
||||
# error WIN32 only!
|
||||
#endif // WIN32
|
||||
|
||||
#include <D3D11.h>
|
||||
|
||||
#include "GHOST_Context.h"
|
||||
|
||||
class GHOST_ContextD3D : public GHOST_Context {
|
||||
/* XR code needs low level graphics data to send to OpenXR. */
|
||||
friend class GHOST_XrGraphicsBindingD3D;
|
||||
|
||||
public:
|
||||
GHOST_ContextD3D(bool stereoVisual, HWND hWnd);
|
||||
~GHOST_ContextD3D();
|
||||
|
||||
/**
|
||||
* Swaps front and back buffers of a window.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
GHOST_TSuccess swapBuffers();
|
||||
|
||||
/**
|
||||
* Activates the drawing context of this window.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
GHOST_TSuccess activateDrawingContext();
|
||||
|
||||
/**
|
||||
* Release the drawing context of the calling thread.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
GHOST_TSuccess releaseDrawingContext();
|
||||
|
||||
/**
|
||||
* Call immediately after new to initialize. If this fails then immediately delete the object.
|
||||
* \return Indication as to whether initialization has succeeded.
|
||||
*/
|
||||
GHOST_TSuccess initializeDrawingContext();
|
||||
|
||||
/**
|
||||
* Updates the drawing context of this window. Needed
|
||||
* whenever the window is changed.
|
||||
* \return Indication of success.
|
||||
*/
|
||||
GHOST_TSuccess updateDrawingContext()
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it is OK for a remove the native display
|
||||
* \return Indication as to whether removal has succeeded.
|
||||
*/
|
||||
GHOST_TSuccess releaseNativeHandles();
|
||||
|
||||
/**
|
||||
* Sets the swap interval for swapBuffers.
|
||||
* \param interval The swap interval to use.
|
||||
* \return A boolean success indicator.
|
||||
*/
|
||||
GHOST_TSuccess setSwapInterval(int /*interval*/)
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current swap interval for swapBuffers.
|
||||
* \param intervalOut Variable to store the swap interval if it can be read.
|
||||
* \return Whether the swap interval can be read.
|
||||
*/
|
||||
GHOST_TSuccess getSwapInterval(int &)
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OpenGL framebuffer associated with the OpenGL context
|
||||
* \return The ID of an OpenGL framebuffer object.
|
||||
*/
|
||||
unsigned int getDefaultFramebuffer()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
class GHOST_SharedOpenGLResource *createSharedOpenGLResource(
|
||||
unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target);
|
||||
class GHOST_SharedOpenGLResource *createSharedOpenGLResource(unsigned int width,
|
||||
unsigned int height);
|
||||
void disposeSharedOpenGLResource(class GHOST_SharedOpenGLResource *shared_res);
|
||||
GHOST_TSuccess blitFromOpenGLContext(class GHOST_SharedOpenGLResource *shared_res,
|
||||
unsigned int width,
|
||||
unsigned int height);
|
||||
ID3D11Texture2D *getSharedTexture2D(class GHOST_SharedOpenGLResource *shared_res);
|
||||
|
||||
bool isUpsideDown() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
GHOST_TSuccess setupD3DLib();
|
||||
|
||||
static HMODULE s_d3d_lib;
|
||||
static PFN_D3D11_CREATE_DEVICE s_D3D11CreateDeviceFn;
|
||||
|
||||
HWND m_hWnd;
|
||||
|
||||
ID3D11Device *m_device;
|
||||
ID3D11DeviceContext *m_device_ctx;
|
||||
};
|
||||
|
||||
#endif /* __GHOST_CONTEXTD3D_H__ */
|
@@ -273,6 +273,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
|
||||
m_window = (Window)glXCreatePbuffer(m_display, framebuffer_config[0], pbuffer_attribs);
|
||||
}
|
||||
|
||||
m_fbconfig = framebuffer_config[0];
|
||||
XFree(framebuffer_config);
|
||||
}
|
||||
}
|
||||
|
@@ -38,6 +38,9 @@
|
||||
#endif
|
||||
|
||||
class GHOST_ContextGLX : public GHOST_Context {
|
||||
/* XR code needs low level graphics data to send to OpenXR. */
|
||||
friend class GHOST_XrGraphicsBindingOpenGL;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
|
@@ -30,7 +30,8 @@
|
||||
|
||||
class GHOST_ContextNone : public GHOST_Context {
|
||||
public:
|
||||
GHOST_ContextNone(bool stereoVisual) : GHOST_Context(stereoVisual), m_swapInterval(1)
|
||||
GHOST_ContextNone(bool stereoVisual)
|
||||
: GHOST_Context(stereoVisual), m_swapInterval(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,9 @@
|
||||
#endif
|
||||
|
||||
class GHOST_ContextWGL : public GHOST_Context {
|
||||
/* XR code needs low level graphics data to send to OpenXR. */
|
||||
friend class GHOST_XrGraphicsBindingOpenGL;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
|
@@ -121,6 +121,16 @@ GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow *window)
|
||||
return success;
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_System::createOffscreenContext(GHOST_TDrawingContextType type)
|
||||
{
|
||||
switch (type) {
|
||||
case GHOST_kDrawingContextTypeOpenGL:
|
||||
return createOffscreenContext();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_System::validWindow(GHOST_IWindow *window)
|
||||
{
|
||||
return m_windowManager->getWindowFound(window);
|
||||
|
@@ -119,6 +119,19 @@ class GHOST_System : public GHOST_ISystem {
|
||||
*/
|
||||
GHOST_TSuccess disposeWindow(GHOST_IWindow *window);
|
||||
|
||||
/**
|
||||
* Create a new offscreen context.
|
||||
* Never explicitly delete the context, use disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext() = 0;
|
||||
|
||||
/**
|
||||
* Overload to allow requesting a different context type. By default only OpenGL is supported.
|
||||
* However by explicitly overloading this a system may add support for others.
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type);
|
||||
|
||||
/**
|
||||
* Returns whether a window is valid.
|
||||
* \param window Pointer to the window to be checked.
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include "GHOST_ContextD3D.h"
|
||||
#include "GHOST_SystemWin32.h"
|
||||
#include "GHOST_EventDragnDrop.h"
|
||||
|
||||
@@ -406,6 +407,47 @@ GHOST_TSuccess GHOST_SystemWin32::disposeContext(GHOST_IContext *context)
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new offscreen DirectX 11 context.
|
||||
* Never explicitly delete the window, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *GHOST_SystemWin32::createOffscreenContextD3D()
|
||||
{
|
||||
GHOST_Context *context;
|
||||
|
||||
HWND wnd = CreateWindowA("STATIC",
|
||||
"BlenderD3D",
|
||||
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||
0,
|
||||
0,
|
||||
64,
|
||||
64,
|
||||
NULL,
|
||||
NULL,
|
||||
GetModuleHandle(NULL),
|
||||
NULL);
|
||||
|
||||
context = new GHOST_ContextD3D(false, wnd);
|
||||
if (context->initializeDrawingContext() == GHOST_kFailure) {
|
||||
delete context;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_TDrawingContextType type)
|
||||
{
|
||||
switch (type) {
|
||||
case GHOST_kDrawingContextTypeOpenGL:
|
||||
return createOffscreenContext();
|
||||
case GHOST_kDrawingContextTypeD3D:
|
||||
return createOffscreenContextD3D();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_SystemWin32::processEvents(bool waitForEvent)
|
||||
{
|
||||
MSG msg;
|
||||
|
@@ -133,6 +133,13 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext();
|
||||
|
||||
/**
|
||||
* Create a new offscreen context.
|
||||
* Never explicitly delete the window, use disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
* \param context Pointer to the context to be disposed.
|
||||
@@ -235,6 +242,13 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
*/
|
||||
GHOST_TSuccess exit();
|
||||
|
||||
/**
|
||||
* Create a new offscreen DirectX context.
|
||||
* Never explicitly delete the window, use disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContextD3D();
|
||||
|
||||
/**
|
||||
* Converts raw WIN32 key codes from the wndproc to GHOST keys.
|
||||
* \param vKey The virtual key from hardKey
|
||||
|
@@ -114,6 +114,11 @@ unsigned int GHOST_Window::getDefaultFramebuffer()
|
||||
return (m_context) ? m_context->getDefaultFramebuffer() : 0;
|
||||
}
|
||||
|
||||
bool GHOST_Window::isUpsideDown() const
|
||||
{
|
||||
return m_context->isUpsideDown();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_Window::activateDrawingContext()
|
||||
{
|
||||
return m_context->activateDrawingContext();
|
||||
|
@@ -279,6 +279,11 @@ class GHOST_Window : public GHOST_IWindow {
|
||||
m_userData = userData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the window is rendered upside down compared to OpenGL.
|
||||
*/
|
||||
bool isUpsideDown() const;
|
||||
|
||||
float getNativePixelSize(void)
|
||||
{
|
||||
if (m_nativePixelSize > 0.0f)
|
||||
|
@@ -23,6 +23,7 @@
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include "GHOST_ContextD3D.h"
|
||||
#include "GHOST_WindowWin32.h"
|
||||
#include "GHOST_SystemWin32.h"
|
||||
#include "GHOST_DropTargetWin32.h"
|
||||
@@ -724,6 +725,19 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
|
||||
# error // must specify either core or compat at build time
|
||||
#endif
|
||||
}
|
||||
else if (type == GHOST_kDrawingContextTypeD3D) {
|
||||
GHOST_Context *context;
|
||||
|
||||
context = new GHOST_ContextD3D(false, m_hWnd);
|
||||
if (context->initializeDrawingContext()) {
|
||||
return context;
|
||||
}
|
||||
else {
|
||||
delete context;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
59
intern/vamr/CMakeLists.txt
Normal file
59
intern/vamr/CMakeLists.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
set(INC
|
||||
.
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
${OPENXR_SDK_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(SRC
|
||||
intern/VAMR.cc
|
||||
intern/CAPI.cc
|
||||
intern/Context.cc
|
||||
intern/Event.cc
|
||||
intern/GraphicsBinding.cc
|
||||
intern/Session.cc
|
||||
|
||||
VAMR_capi.h
|
||||
VAMR_IContext.h
|
||||
VAMR_Types.h
|
||||
intern/Context.h
|
||||
intern/Exception.h
|
||||
intern/utils.h
|
||||
intern/IGraphicsBinding.h
|
||||
intern/openxr_includes.h
|
||||
intern/Session.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LIB
|
||||
shlwapi
|
||||
)
|
||||
elseif(WITH_X11)
|
||||
add_definitions(-DWITH_X11)
|
||||
endif()
|
||||
|
||||
|
||||
add_definitions(${GL_DEFINITIONS})
|
||||
|
||||
include(xr_platform_defines)
|
||||
|
||||
blender_add_lib(bf_intern_vamr "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
46
intern/vamr/VAMR_IContext.h
Normal file
46
intern/vamr/VAMR_IContext.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __VAMR_ICONTEXT_H__
|
||||
#define __VAMR_ICONTEXT_H__
|
||||
|
||||
#include "VAMR_Types.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
class IContext {
|
||||
public:
|
||||
virtual ~IContext() = default;
|
||||
|
||||
virtual void startSession(const VAMR_SessionBeginInfo *begin_info) = 0;
|
||||
virtual void endSession() = 0;
|
||||
virtual bool isSessionRunning() const = 0;
|
||||
virtual void drawSessionViews(void *draw_customdata) = 0;
|
||||
|
||||
virtual void dispatchErrorMessage(const class Exception *) const = 0;
|
||||
|
||||
virtual void setGraphicsContextBindFuncs(VAMR_GraphicsContextBindFn bind_fn,
|
||||
VAMR_GraphicsContextUnbindFn unbind_fn) = 0;
|
||||
virtual void setDrawViewFunc(VAMR_DrawViewFn draw_view_fn) = 0;
|
||||
};
|
||||
|
||||
} // namespace VAMR
|
||||
|
||||
#endif // __VAMR_ICONTEXT_H__
|
103
intern/vamr/VAMR_Types.h
Normal file
103
intern/vamr/VAMR_Types.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __VAMR_TYPES_H__
|
||||
#define __VAMR_TYPES_H__
|
||||
|
||||
typedef struct VAMR_Context__ {
|
||||
int dummy;
|
||||
} * VAMR_ContextHandle;
|
||||
|
||||
typedef enum { VAMR_Failure = 0, VAMR_Success } VAMR_TSuccess;
|
||||
|
||||
/**
|
||||
* The XR view (i.e. the OpenXR runtime) may require a different graphics library than OpenGL. An
|
||||
* offscreen texture of the viewport will then be drawn into using OpenGL, but the final texture
|
||||
* draw call will happen through another lib (say DirectX).
|
||||
*
|
||||
* This enum defines the possible graphics bindings to attempt to enable.
|
||||
*/
|
||||
typedef enum {
|
||||
VAMR_GraphicsBindingTypeUnknown = 0,
|
||||
VAMR_GraphicsBindingTypeOpenGL,
|
||||
#ifdef WIN32
|
||||
VAMR_GraphicsBindingTypeD3D11,
|
||||
#endif
|
||||
/* For later */
|
||||
// VAMR_GraphicsBindingVulkan,
|
||||
} VAMR_GraphicsBindingType;
|
||||
/* An array of VAMR_GraphicsBindingType items defining the candidate bindings to use. The first
|
||||
* available candidate will be chosen, so order defines priority. */
|
||||
typedef const VAMR_GraphicsBindingType *VAMR_GraphicsBindingCandidates;
|
||||
|
||||
typedef struct {
|
||||
float position[3];
|
||||
/* Blender convention (w, x, y, z) */
|
||||
float orientation_quat[4];
|
||||
} VAMR_Pose;
|
||||
|
||||
enum {
|
||||
VAMR_ContextDebug = (1 << 0),
|
||||
VAMR_ContextDebugTime = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const VAMR_GraphicsBindingCandidates gpu_binding_candidates;
|
||||
unsigned int gpu_binding_candidates_count;
|
||||
|
||||
unsigned int context_flag;
|
||||
} VAMR_ContextCreateInfo;
|
||||
|
||||
typedef struct {
|
||||
VAMR_Pose base_pose;
|
||||
} VAMR_SessionBeginInfo;
|
||||
|
||||
typedef struct {
|
||||
int ofsx, ofsy;
|
||||
int width, height;
|
||||
|
||||
VAMR_Pose pose;
|
||||
|
||||
struct {
|
||||
float angle_left, angle_right;
|
||||
float angle_up, angle_down;
|
||||
} fov;
|
||||
|
||||
/** Set if the buffer should be submitted with a srgb transfer applied. */
|
||||
char expects_srgb_buffer;
|
||||
} VAMR_DrawViewInfo;
|
||||
|
||||
typedef struct {
|
||||
const char *user_message;
|
||||
|
||||
/** File path and line number the error was found at. */
|
||||
const char *source_location;
|
||||
|
||||
void *customdata;
|
||||
} VAMR_Error;
|
||||
|
||||
typedef void (*VAMR_ErrorHandlerFn)(const VAMR_Error *);
|
||||
|
||||
typedef void *(*VAMR_GraphicsContextBindFn)(VAMR_GraphicsBindingType graphics_lib);
|
||||
typedef void (*VAMR_GraphicsContextUnbindFn)(VAMR_GraphicsBindingType graphics_lib,
|
||||
void *graphics_context);
|
||||
typedef void (*VAMR_DrawViewFn)(const VAMR_DrawViewInfo *draw_view, void *customdata);
|
||||
|
||||
#endif // __VAMR_TYPES_H__
|
60
intern/vamr/VAMR_capi.h
Normal file
60
intern/vamr/VAMR_capi.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __VAMR_CAPI_H__
|
||||
#define __VAMR_CAPI_H__
|
||||
|
||||
#include "VAMR_Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* xr-context */
|
||||
|
||||
/**
|
||||
* Set a custom callback to be executed whenever an error occurs. Should be set before calling
|
||||
* #VAMR_ContextCreate().
|
||||
*/
|
||||
void VAMR_ErrorHandler(VAMR_ErrorHandlerFn handler_fn, void *customdata);
|
||||
|
||||
VAMR_ContextHandle VAMR_ContextCreate(const VAMR_ContextCreateInfo *create_info);
|
||||
void VAMR_ContextDestroy(VAMR_ContextHandle xr_context);
|
||||
|
||||
void VAMR_GraphicsContextBindFuncs(VAMR_ContextHandle xr_context,
|
||||
VAMR_GraphicsContextBindFn bind_fn,
|
||||
VAMR_GraphicsContextUnbindFn unbind_fn);
|
||||
|
||||
void VAMR_DrawViewFunc(VAMR_ContextHandle xr_context, VAMR_DrawViewFn draw_view_fn);
|
||||
|
||||
/* sessions */
|
||||
int VAMR_SessionIsRunning(const VAMR_ContextHandle xr_context);
|
||||
void VAMR_SessionStart(VAMR_ContextHandle xr_context, const VAMR_SessionBeginInfo *begin_info);
|
||||
void VAMR_SessionEnd(VAMR_ContextHandle xr_context);
|
||||
void VAMR_SessionDrawViews(VAMR_ContextHandle xr_context, void *customdata);
|
||||
|
||||
/* events */
|
||||
VAMR_TSuccess VAMR_EventsHandle(VAMR_ContextHandle xr_context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __VAMR_CAPI_H__
|
81
intern/vamr/intern/CAPI.cc
Normal file
81
intern/vamr/intern/CAPI.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#include "VAMR_Types.h"
|
||||
#include "VAMR_capi.h"
|
||||
#include "VAMR_IContext.h"
|
||||
|
||||
#include "Exception.h"
|
||||
|
||||
#define VAMR_CAPI_CALL(call, ctx) \
|
||||
try { \
|
||||
call; \
|
||||
} \
|
||||
catch (VAMR::Exception & e) { \
|
||||
(ctx)->dispatchErrorMessage(&e); \
|
||||
}
|
||||
|
||||
#define VAMR_CAPI_CALL_RET(call, ctx) \
|
||||
try { \
|
||||
return call; \
|
||||
} \
|
||||
catch (VAMR::Exception & e) { \
|
||||
(ctx)->dispatchErrorMessage(&e); \
|
||||
}
|
||||
|
||||
void VAMR_SessionStart(VAMR_ContextHandle xr_contexthandle,
|
||||
const VAMR_SessionBeginInfo *begin_info)
|
||||
{
|
||||
VAMR::IContext *xr_context = (VAMR::IContext *)xr_contexthandle;
|
||||
VAMR_CAPI_CALL(xr_context->startSession(begin_info), xr_context);
|
||||
}
|
||||
|
||||
void VAMR_SessionEnd(VAMR_ContextHandle xr_contexthandle)
|
||||
{
|
||||
VAMR::IContext *xr_context = (VAMR::IContext *)xr_contexthandle;
|
||||
VAMR_CAPI_CALL(xr_context->endSession(), xr_context);
|
||||
}
|
||||
|
||||
int VAMR_SessionIsRunning(const VAMR_ContextHandle xr_contexthandle)
|
||||
{
|
||||
const VAMR::IContext *xr_context = (const VAMR::IContext *)xr_contexthandle;
|
||||
VAMR_CAPI_CALL_RET(xr_context->isSessionRunning(), xr_context);
|
||||
return 0; // Only reached if exception is thrown.
|
||||
}
|
||||
|
||||
void VAMR_SessionDrawViews(VAMR_ContextHandle xr_contexthandle, void *draw_customdata)
|
||||
{
|
||||
VAMR::IContext *xr_context = (VAMR::IContext *)xr_contexthandle;
|
||||
VAMR_CAPI_CALL(xr_context->drawSessionViews(draw_customdata), xr_context);
|
||||
}
|
||||
|
||||
void VAMR_GraphicsContextBindFuncs(VAMR_ContextHandle xr_contexthandle,
|
||||
VAMR_GraphicsContextBindFn bind_fn,
|
||||
VAMR_GraphicsContextUnbindFn unbind_fn)
|
||||
{
|
||||
VAMR::IContext *xr_context = (VAMR::IContext *)xr_contexthandle;
|
||||
VAMR_CAPI_CALL(xr_context->setGraphicsContextBindFuncs(bind_fn, unbind_fn), xr_context);
|
||||
}
|
||||
|
||||
void VAMR_DrawViewFunc(VAMR_ContextHandle xr_contexthandle, VAMR_DrawViewFn draw_view_fn)
|
||||
{
|
||||
VAMR::IContext *xr_context = (VAMR::IContext *)xr_contexthandle;
|
||||
VAMR_CAPI_CALL(xr_context->setDrawViewFunc(draw_view_fn), xr_context);
|
||||
}
|
555
intern/vamr/intern/Context.cc
Normal file
555
intern/vamr/intern/Context.cc
Normal file
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*
|
||||
* Abstraction for XR (VR, AR, MR, ..) access via OpenXR.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "VAMR_Types.h"
|
||||
|
||||
#include "openxr_includes.h"
|
||||
|
||||
#include "Context.h"
|
||||
#include "Exception.h"
|
||||
#include "Session.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
struct OpenXRInstanceData {
|
||||
XrInstance instance{XR_NULL_HANDLE};
|
||||
XrInstanceProperties instance_properties;
|
||||
|
||||
std::vector<XrExtensionProperties> extensions;
|
||||
std::vector<XrApiLayerProperties> layers;
|
||||
|
||||
static PFN_xrCreateDebugUtilsMessengerEXT s_xrCreateDebugUtilsMessengerEXT_fn;
|
||||
static PFN_xrDestroyDebugUtilsMessengerEXT s_xrDestroyDebugUtilsMessengerEXT_fn;
|
||||
|
||||
XrDebugUtilsMessengerEXT debug_messenger{XR_NULL_HANDLE};
|
||||
};
|
||||
|
||||
PFN_xrCreateDebugUtilsMessengerEXT OpenXRInstanceData::s_xrCreateDebugUtilsMessengerEXT_fn =
|
||||
nullptr;
|
||||
PFN_xrDestroyDebugUtilsMessengerEXT OpenXRInstanceData::s_xrDestroyDebugUtilsMessengerEXT_fn =
|
||||
nullptr;
|
||||
|
||||
VAMR_ErrorHandlerFn Context::s_error_handler = nullptr;
|
||||
void *Context::s_error_handler_customdata = nullptr;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Create, Initialize and Destruct
|
||||
*
|
||||
* \{ */
|
||||
|
||||
Context::Context(const VAMR_ContextCreateInfo *create_info)
|
||||
: m_oxr(new OpenXRInstanceData()),
|
||||
m_debug(create_info->context_flag & VAMR_ContextDebug),
|
||||
m_debug_time(create_info->context_flag & VAMR_ContextDebugTime)
|
||||
{
|
||||
}
|
||||
Context::~Context()
|
||||
{
|
||||
/* Destroy session data first. Otherwise xrDestroyInstance will implicitly do it, before the
|
||||
* session had a chance to do so explicitly. */
|
||||
m_session = nullptr;
|
||||
|
||||
if (m_oxr->debug_messenger != XR_NULL_HANDLE) {
|
||||
assert(m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn != nullptr);
|
||||
m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn(m_oxr->debug_messenger);
|
||||
}
|
||||
if (m_oxr->instance != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroyInstance(m_oxr->instance));
|
||||
m_oxr->instance = XR_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void Context::initialize(const VAMR_ContextCreateInfo *create_info)
|
||||
{
|
||||
enumerateApiLayers();
|
||||
enumerateExtensions();
|
||||
XR_DEBUG_ONLY_CALL(this, printAvailableAPILayersAndExtensionsInfo());
|
||||
|
||||
m_gpu_binding_type = determineGraphicsBindingTypeToEnable(create_info);
|
||||
|
||||
assert(m_oxr->instance == XR_NULL_HANDLE);
|
||||
createOpenXRInstance();
|
||||
storeInstanceProperties();
|
||||
printInstanceInfo();
|
||||
XR_DEBUG_ONLY_CALL(this, initDebugMessenger());
|
||||
}
|
||||
|
||||
void Context::createOpenXRInstance()
|
||||
{
|
||||
XrInstanceCreateInfo create_info{XR_TYPE_INSTANCE_CREATE_INFO};
|
||||
|
||||
std::string("Blender").copy(create_info.applicationInfo.applicationName,
|
||||
XR_MAX_APPLICATION_NAME_SIZE);
|
||||
create_info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
|
||||
|
||||
getAPILayersToEnable(m_enabled_layers);
|
||||
getExtensionsToEnable(m_enabled_extensions);
|
||||
create_info.enabledApiLayerCount = m_enabled_layers.size();
|
||||
create_info.enabledApiLayerNames = m_enabled_layers.data();
|
||||
create_info.enabledExtensionCount = m_enabled_extensions.size();
|
||||
create_info.enabledExtensionNames = m_enabled_extensions.data();
|
||||
XR_DEBUG_ONLY_CALL(this, printExtensionsAndAPILayersToEnable());
|
||||
|
||||
CHECK_XR(xrCreateInstance(&create_info, &m_oxr->instance),
|
||||
"Failed to connect to an OpenXR runtime.");
|
||||
}
|
||||
|
||||
void Context::storeInstanceProperties()
|
||||
{
|
||||
const std::map<std::string, OpenXRRuntimeID> runtime_map{
|
||||
{"Monado(XRT) by Collabora et al", OPENXR_RUNTIME_MONADO},
|
||||
{"Oculus", OPENXR_RUNTIME_OCULUS},
|
||||
{"Windows Mixed Reality Runtime", OPENXR_RUNTIME_WMR}};
|
||||
decltype(runtime_map)::const_iterator runtime_map_iter;
|
||||
|
||||
m_oxr->instance_properties.type = XR_TYPE_INSTANCE_PROPERTIES;
|
||||
CHECK_XR(xrGetInstanceProperties(m_oxr->instance, &m_oxr->instance_properties),
|
||||
"Failed to get OpenXR runtime information. Do you have an active runtime set up?");
|
||||
|
||||
runtime_map_iter = runtime_map.find(m_oxr->instance_properties.runtimeName);
|
||||
if (runtime_map_iter != runtime_map.end()) {
|
||||
m_runtime_id = runtime_map_iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* Create, Initialize and Destruct */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Debug Printing
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void Context::printInstanceInfo()
|
||||
{
|
||||
assert(m_oxr->instance != XR_NULL_HANDLE);
|
||||
|
||||
printf("Connected to OpenXR runtime: %s (Version %u.%u.%u)\n",
|
||||
m_oxr->instance_properties.runtimeName,
|
||||
XR_VERSION_MAJOR(m_oxr->instance_properties.runtimeVersion),
|
||||
XR_VERSION_MINOR(m_oxr->instance_properties.runtimeVersion),
|
||||
XR_VERSION_PATCH(m_oxr->instance_properties.runtimeVersion));
|
||||
}
|
||||
|
||||
void Context::printAvailableAPILayersAndExtensionsInfo()
|
||||
{
|
||||
puts("Available OpenXR API-layers/extensions:");
|
||||
for (XrApiLayerProperties &layer_info : m_oxr->layers) {
|
||||
printf("Layer: %s\n", layer_info.layerName);
|
||||
}
|
||||
for (XrExtensionProperties &ext_info : m_oxr->extensions) {
|
||||
printf("Extension: %s\n", ext_info.extensionName);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::printExtensionsAndAPILayersToEnable()
|
||||
{
|
||||
for (const char *layer_name : m_enabled_layers) {
|
||||
printf("Enabling OpenXR API-Layer: %s\n", layer_name);
|
||||
}
|
||||
for (const char *ext_name : m_enabled_extensions) {
|
||||
printf("Enabling OpenXR Extension: %s\n", ext_name);
|
||||
}
|
||||
}
|
||||
|
||||
static XrBool32 debug_messenger_func(XrDebugUtilsMessageSeverityFlagsEXT /*messageSeverity*/,
|
||||
XrDebugUtilsMessageTypeFlagsEXT /*messageTypes*/,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT *callbackData,
|
||||
void * /*userData*/)
|
||||
{
|
||||
puts("OpenXR Debug Message:");
|
||||
puts(callbackData->message);
|
||||
return XR_FALSE; // OpenXR spec suggests always returning false.
|
||||
}
|
||||
|
||||
void Context::initDebugMessenger()
|
||||
{
|
||||
XrDebugUtilsMessengerCreateInfoEXT create_info{XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};
|
||||
|
||||
/* Extension functions need to be obtained through xrGetInstanceProcAddr */
|
||||
if (XR_FAILED(xrGetInstanceProcAddr(
|
||||
m_oxr->instance,
|
||||
"xrCreateDebugUtilsMessengerEXT",
|
||||
(PFN_xrVoidFunction *)&m_oxr->s_xrCreateDebugUtilsMessengerEXT_fn)) ||
|
||||
XR_FAILED(xrGetInstanceProcAddr(
|
||||
m_oxr->instance,
|
||||
"xrDestroyDebugUtilsMessengerEXT",
|
||||
(PFN_xrVoidFunction *)&m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn))) {
|
||||
m_oxr->s_xrCreateDebugUtilsMessengerEXT_fn = nullptr;
|
||||
m_oxr->s_xrDestroyDebugUtilsMessengerEXT_fn = nullptr;
|
||||
|
||||
fprintf(stderr,
|
||||
"Could not use XR_EXT_debug_utils to enable debug prints. Not a fatal error, "
|
||||
"continuing without the messenger.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
create_info.messageSeverities = XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
create_info.messageTypes = XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||
XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
create_info.userCallback = debug_messenger_func;
|
||||
|
||||
if (XR_FAILED(m_oxr->s_xrCreateDebugUtilsMessengerEXT_fn(
|
||||
m_oxr->instance, &create_info, &m_oxr->debug_messenger))) {
|
||||
fprintf(stderr,
|
||||
"Failed to create OpenXR debug messenger. Not a fatal error, continuing without the "
|
||||
"messenger.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* Debug Printing */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Error handling
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void Context::dispatchErrorMessage(const Exception *exception) const
|
||||
{
|
||||
std::ostringstream stream_err_location;
|
||||
std::string str_err_location;
|
||||
VAMR_Error error;
|
||||
|
||||
stream_err_location << exception->m_file << ":" << exception->m_line;
|
||||
str_err_location = stream_err_location.str();
|
||||
|
||||
error.user_message = exception->m_msg;
|
||||
error.source_location = str_err_location.c_str();
|
||||
error.customdata = s_error_handler_customdata;
|
||||
|
||||
XR_DEBUG_ONLY_CALL(this,
|
||||
fprintf(stderr,
|
||||
"Error: \t%s\n\tOpenXR error value: %i\n\tSource: (%s)\n",
|
||||
error.user_message,
|
||||
exception->m_res,
|
||||
error.source_location));
|
||||
|
||||
/* Potentially destroys VAMR-context */
|
||||
s_error_handler(&error);
|
||||
}
|
||||
|
||||
void Context::setErrorHandler(VAMR_ErrorHandlerFn handler_fn, void *customdata)
|
||||
{
|
||||
s_error_handler = handler_fn;
|
||||
s_error_handler_customdata = customdata;
|
||||
}
|
||||
|
||||
/** \} */ /* Error handling */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name OpenXR API-Layers and Extensions
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \param layer_name May be NULL for extensions not belonging to a specific layer.
|
||||
*/
|
||||
void Context::enumerateExtensionsEx(std::vector<XrExtensionProperties> &extensions,
|
||||
const char *layer_name)
|
||||
{
|
||||
uint32_t extension_count = 0;
|
||||
|
||||
/* Get count for array creation/init first. */
|
||||
CHECK_XR(xrEnumerateInstanceExtensionProperties(layer_name, 0, &extension_count, nullptr),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
|
||||
if (extension_count == 0) {
|
||||
/* Extensions are optional, can successfully exit. */
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < extension_count; i++) {
|
||||
XrExtensionProperties ext{XR_TYPE_EXTENSION_PROPERTIES};
|
||||
extensions.push_back(ext);
|
||||
}
|
||||
|
||||
/* Actually get the extensions. */
|
||||
CHECK_XR(xrEnumerateInstanceExtensionProperties(
|
||||
layer_name, extension_count, &extension_count, extensions.data()),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
}
|
||||
void Context::enumerateExtensions()
|
||||
{
|
||||
enumerateExtensionsEx(m_oxr->extensions, nullptr);
|
||||
}
|
||||
|
||||
void Context::enumerateApiLayers()
|
||||
{
|
||||
uint32_t layer_count = 0;
|
||||
|
||||
/* Get count for array creation/init first. */
|
||||
CHECK_XR(xrEnumerateApiLayerProperties(0, &layer_count, nullptr),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
|
||||
if (layer_count == 0) {
|
||||
/* Layers are optional, can safely exit. */
|
||||
return;
|
||||
}
|
||||
|
||||
m_oxr->layers = std::vector<XrApiLayerProperties>(layer_count);
|
||||
for (XrApiLayerProperties &layer : m_oxr->layers) {
|
||||
layer.type = XR_TYPE_API_LAYER_PROPERTIES;
|
||||
}
|
||||
|
||||
/* Actually get the layers. */
|
||||
CHECK_XR(xrEnumerateApiLayerProperties(layer_count, &layer_count, m_oxr->layers.data()),
|
||||
"Failed to query OpenXR runtime information. Do you have an active runtime set up?");
|
||||
for (XrApiLayerProperties &layer : m_oxr->layers) {
|
||||
/* Each layer may have own extensions */
|
||||
enumerateExtensionsEx(m_oxr->extensions, layer.layerName);
|
||||
}
|
||||
}
|
||||
|
||||
static bool openxr_layer_is_available(const std::vector<XrApiLayerProperties> layers_info,
|
||||
const std::string &layer_name)
|
||||
{
|
||||
for (const XrApiLayerProperties &layer_info : layers_info) {
|
||||
if (layer_info.layerName == layer_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
static bool openxr_extension_is_available(const std::vector<XrExtensionProperties> extensions_info,
|
||||
const std::string &extension_name)
|
||||
{
|
||||
for (const XrExtensionProperties &ext_info : extensions_info) {
|
||||
if (ext_info.extensionName == extension_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather an array of names for the API-layers to enable.
|
||||
*/
|
||||
void Context::getAPILayersToEnable(std::vector<const char *> &r_ext_names)
|
||||
{
|
||||
static std::vector<std::string> try_layers;
|
||||
|
||||
try_layers.clear();
|
||||
|
||||
XR_DEBUG_ONLY_CALL(this, try_layers.push_back("XR_APILAYER_LUNARG_core_validation"));
|
||||
|
||||
r_ext_names.reserve(try_layers.size());
|
||||
|
||||
for (const std::string &layer : try_layers) {
|
||||
if (openxr_layer_is_available(m_oxr->layers, layer)) {
|
||||
r_ext_names.push_back(layer.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *openxr_ext_name_from_wm_gpu_binding(VAMR_GraphicsBindingType binding)
|
||||
{
|
||||
switch (binding) {
|
||||
case VAMR_GraphicsBindingTypeOpenGL:
|
||||
return XR_KHR_OPENGL_ENABLE_EXTENSION_NAME;
|
||||
#ifdef WIN32
|
||||
case VAMR_GraphicsBindingTypeD3D11:
|
||||
return XR_KHR_D3D11_ENABLE_EXTENSION_NAME;
|
||||
#endif
|
||||
case VAMR_GraphicsBindingTypeUnknown:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather an array of names for the extensions to enable.
|
||||
*/
|
||||
void Context::getExtensionsToEnable(std::vector<const char *> &r_ext_names)
|
||||
{
|
||||
assert(m_gpu_binding_type != VAMR_GraphicsBindingTypeUnknown);
|
||||
|
||||
const char *gpu_binding = openxr_ext_name_from_wm_gpu_binding(m_gpu_binding_type);
|
||||
static std::vector<std::string> try_ext;
|
||||
|
||||
try_ext.clear();
|
||||
|
||||
/* Try enabling debug extension */
|
||||
#ifndef WIN32
|
||||
XR_DEBUG_ONLY_CALL(this, try_ext.push_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME));
|
||||
#endif
|
||||
|
||||
r_ext_names.reserve(try_ext.size() + 1); /* + 1 for graphics binding extension. */
|
||||
|
||||
/* Add graphics binding extension. */
|
||||
assert(gpu_binding);
|
||||
assert(openxr_extension_is_available(m_oxr->extensions, gpu_binding));
|
||||
r_ext_names.push_back(gpu_binding);
|
||||
|
||||
for (const std::string &ext : try_ext) {
|
||||
if (openxr_extension_is_available(m_oxr->extensions, ext)) {
|
||||
r_ext_names.push_back(ext.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide which graphics binding extension to use based on
|
||||
* #VAMR_ContextCreateInfo.gpu_binding_candidates and available extensions.
|
||||
*/
|
||||
VAMR_GraphicsBindingType Context::determineGraphicsBindingTypeToEnable(
|
||||
const VAMR_ContextCreateInfo *create_info)
|
||||
{
|
||||
assert(create_info->gpu_binding_candidates != NULL);
|
||||
assert(create_info->gpu_binding_candidates_count > 0);
|
||||
|
||||
for (uint32_t i = 0; i < create_info->gpu_binding_candidates_count; i++) {
|
||||
assert(create_info->gpu_binding_candidates[i] != VAMR_GraphicsBindingTypeUnknown);
|
||||
const char *ext_name = openxr_ext_name_from_wm_gpu_binding(
|
||||
create_info->gpu_binding_candidates[i]);
|
||||
if (openxr_extension_is_available(m_oxr->extensions, ext_name)) {
|
||||
return create_info->gpu_binding_candidates[i];
|
||||
}
|
||||
}
|
||||
|
||||
return VAMR_GraphicsBindingTypeUnknown;
|
||||
}
|
||||
|
||||
/** \} */ /* OpenXR API-Layers and Extensions */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Session management
|
||||
*
|
||||
* Manage session lifetime and delegate public calls to #VAMR::Session.
|
||||
* \{ */
|
||||
|
||||
void Context::startSession(const VAMR_SessionBeginInfo *begin_info)
|
||||
{
|
||||
if (m_session == nullptr) {
|
||||
m_session = std::unique_ptr<Session>(new Session(this));
|
||||
}
|
||||
|
||||
m_session->start(begin_info);
|
||||
}
|
||||
void Context::endSession()
|
||||
{
|
||||
m_session->requestEnd();
|
||||
}
|
||||
|
||||
bool Context::isSessionRunning() const
|
||||
{
|
||||
return m_session && m_session->isRunning();
|
||||
}
|
||||
|
||||
void Context::drawSessionViews(void *draw_customdata)
|
||||
{
|
||||
m_session->draw(draw_customdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates event to session, allowing context to destruct the session if needed.
|
||||
*/
|
||||
void Context::handleSessionStateChange(const XrEventDataSessionStateChanged *lifecycle)
|
||||
{
|
||||
if (m_session && m_session->handleStateChangeEvent(lifecycle) == Session::SESSION_DESTROY) {
|
||||
m_session = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* Session Management */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Public Accessors and Mutators
|
||||
*
|
||||
* Public as in, exposed in the VAMR API.
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Set context for binding and unbinding a graphics context for a session. The binding callback
|
||||
* may create a new context thereby. In fact that's the sole reason for this callback approach to
|
||||
* binding. Just make sure to have an unbind function set that properly destructs.
|
||||
*
|
||||
* \param bind_fn Function to retrieve (possibly create) a graphics context.
|
||||
* \param unbind_fn Function to release (possibly free) a graphics context.
|
||||
*/
|
||||
void Context::setGraphicsContextBindFuncs(VAMR_GraphicsContextBindFn bind_fn,
|
||||
VAMR_GraphicsContextUnbindFn unbind_fn)
|
||||
{
|
||||
if (m_session) {
|
||||
m_session->unbindGraphicsContext();
|
||||
}
|
||||
m_custom_funcs.gpu_ctx_bind_fn = bind_fn;
|
||||
m_custom_funcs.gpu_ctx_unbind_fn = unbind_fn;
|
||||
}
|
||||
|
||||
void Context::setDrawViewFunc(VAMR_DrawViewFn draw_view_fn)
|
||||
{
|
||||
m_custom_funcs.draw_view_fn = draw_view_fn;
|
||||
}
|
||||
|
||||
/** \} */ /* Public Accessors and Mutators */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name VAMR Internal Accessors and Mutators
|
||||
*
|
||||
* \{ */
|
||||
|
||||
OpenXRRuntimeID Context::getOpenXRRuntimeID() const
|
||||
{
|
||||
return m_runtime_id;
|
||||
}
|
||||
|
||||
const CustomFuncs *Context::getCustomFuncs() const
|
||||
{
|
||||
return &m_custom_funcs;
|
||||
}
|
||||
|
||||
VAMR_GraphicsBindingType Context::getGraphicsBindingType() const
|
||||
{
|
||||
return m_gpu_binding_type;
|
||||
}
|
||||
|
||||
XrInstance Context::getInstance() const
|
||||
{
|
||||
return m_oxr->instance;
|
||||
}
|
||||
|
||||
bool Context::isDebugMode() const
|
||||
{
|
||||
return m_debug;
|
||||
}
|
||||
|
||||
bool Context::isDebugTimeMode() const
|
||||
{
|
||||
return m_debug_time;
|
||||
}
|
||||
|
||||
/** \} */ /* VAMR Internal Accessors and Mutators */
|
||||
|
||||
} // namespace VAMR
|
130
intern/vamr/intern/Context.h
Normal file
130
intern/vamr/intern/Context.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __CONTEXT_H__
|
||||
#define __CONTEXT_H__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "VAMR_IContext.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
struct CustomFuncs {
|
||||
/** Function to retrieve (possibly create) a graphics context */
|
||||
VAMR_GraphicsContextBindFn gpu_ctx_bind_fn{nullptr};
|
||||
/** Function to release (possibly free) a graphics context */
|
||||
VAMR_GraphicsContextUnbindFn gpu_ctx_unbind_fn{nullptr};
|
||||
|
||||
/** Custom per-view draw function for Blender side drawing. */
|
||||
VAMR_DrawViewFn draw_view_fn{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* In some occasions, runtime specific handling is needed, e.g. to work around runtime bugs.
|
||||
*/
|
||||
enum OpenXRRuntimeID {
|
||||
OPENXR_RUNTIME_MONADO,
|
||||
OPENXR_RUNTIME_OCULUS,
|
||||
OPENXR_RUNTIME_WMR, /* Windows Mixed Reality */
|
||||
|
||||
OPENXR_RUNTIME_UNKNOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Main VAMR container to manage OpenXR through.
|
||||
*
|
||||
* Creating a context using #VAMR_ContextCreate involves dynamically connecting to the OpenXR
|
||||
* runtime, likely reading the OS OpenXR configuration (i.e. active_runtime.json). So this is
|
||||
* something that should better be done using lazy-initialization.
|
||||
*/
|
||||
class Context : public VAMR::IContext {
|
||||
public:
|
||||
Context(const VAMR_ContextCreateInfo *create_info);
|
||||
~Context();
|
||||
void initialize(const VAMR_ContextCreateInfo *create_info);
|
||||
|
||||
void startSession(const VAMR_SessionBeginInfo *begin_info) override;
|
||||
void endSession() override;
|
||||
bool isSessionRunning() const override;
|
||||
void drawSessionViews(void *draw_customdata) override;
|
||||
|
||||
static void setErrorHandler(VAMR_ErrorHandlerFn handler_fn, void *customdata);
|
||||
void dispatchErrorMessage(const class Exception *exception) const override;
|
||||
|
||||
void setGraphicsContextBindFuncs(VAMR_GraphicsContextBindFn bind_fn,
|
||||
VAMR_GraphicsContextUnbindFn unbind_fn) override;
|
||||
void setDrawViewFunc(VAMR_DrawViewFn draw_view_fn) override;
|
||||
|
||||
void handleSessionStateChange(const XrEventDataSessionStateChanged *lifecycle);
|
||||
|
||||
OpenXRRuntimeID getOpenXRRuntimeID() const;
|
||||
const CustomFuncs *getCustomFuncs() const;
|
||||
VAMR_GraphicsBindingType getGraphicsBindingType() const;
|
||||
XrInstance getInstance() const;
|
||||
bool isDebugMode() const;
|
||||
bool isDebugTimeMode() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<struct OpenXRInstanceData> m_oxr;
|
||||
|
||||
OpenXRRuntimeID m_runtime_id{OPENXR_RUNTIME_UNKNOWN};
|
||||
|
||||
/* The active VAMR XR Session. Null while no session runs. */
|
||||
std::unique_ptr<class Session> m_session;
|
||||
|
||||
/** Active graphics binding type. */
|
||||
VAMR_GraphicsBindingType m_gpu_binding_type{VAMR_GraphicsBindingTypeUnknown};
|
||||
|
||||
/** Names of enabled extensions */
|
||||
std::vector<const char *> m_enabled_extensions;
|
||||
/** Names of enabled API-layers */
|
||||
std::vector<const char *> m_enabled_layers;
|
||||
|
||||
static VAMR_ErrorHandlerFn s_error_handler;
|
||||
static void *s_error_handler_customdata;
|
||||
CustomFuncs m_custom_funcs;
|
||||
|
||||
/** Enable debug message prints and OpenXR API validation layers */
|
||||
bool m_debug{false};
|
||||
bool m_debug_time{false};
|
||||
|
||||
void createOpenXRInstance();
|
||||
void storeInstanceProperties();
|
||||
void initDebugMessenger();
|
||||
|
||||
void printInstanceInfo();
|
||||
void printAvailableAPILayersAndExtensionsInfo();
|
||||
void printExtensionsAndAPILayersToEnable();
|
||||
|
||||
void enumerateApiLayers();
|
||||
void enumerateExtensions();
|
||||
void enumerateExtensionsEx(std::vector<XrExtensionProperties> &extensions,
|
||||
const char *layer_name);
|
||||
void getAPILayersToEnable(std::vector<const char *> &r_ext_names);
|
||||
void getExtensionsToEnable(std::vector<const char *> &r_ext_names);
|
||||
VAMR_GraphicsBindingType determineGraphicsBindingTypeToEnable(
|
||||
const VAMR_ContextCreateInfo *create_info);
|
||||
};
|
||||
|
||||
} // namespace VAMR
|
||||
|
||||
#endif // __CONTEXT_H__
|
70
intern/vamr/intern/Event.cc
Normal file
70
intern/vamr/intern/Event.cc
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "VAMR_Types.h"
|
||||
#include "VAMR_capi.h"
|
||||
|
||||
#include "openxr_includes.h"
|
||||
|
||||
#include "Context.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
static bool VAMR_EventPollNext(XrInstance instance, XrEventDataBuffer &r_event_data)
|
||||
{
|
||||
/* (Re-)initialize as required by specification */
|
||||
r_event_data.type = XR_TYPE_EVENT_DATA_BUFFER;
|
||||
r_event_data.next = nullptr;
|
||||
|
||||
return (xrPollEvent(instance, &r_event_data) == XR_SUCCESS);
|
||||
}
|
||||
|
||||
::VAMR_TSuccess VAMR_EventsHandle(Context *xr_context)
|
||||
{
|
||||
XrEventDataBuffer event_buffer; /* structure big enought to hold all possible events */
|
||||
|
||||
if (xr_context == NULL) {
|
||||
return VAMR_Failure;
|
||||
}
|
||||
|
||||
while (VAMR_EventPollNext(xr_context->getInstance(), event_buffer)) {
|
||||
XrEventDataBaseHeader *event = (XrEventDataBaseHeader *)&event_buffer; /* base event struct */
|
||||
|
||||
switch (event->type) {
|
||||
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
|
||||
xr_context->handleSessionStateChange((XrEventDataSessionStateChanged *)event);
|
||||
return VAMR_Success;
|
||||
|
||||
case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
|
||||
VAMR_ContextDestroy((VAMR_ContextHandle)xr_context);
|
||||
return VAMR_Success;
|
||||
default:
|
||||
XR_DEBUG_PRINTF(xr_context, "Unhandled event: %i\n", event->type);
|
||||
return VAMR_Failure;
|
||||
}
|
||||
}
|
||||
|
||||
return VAMR_Failure;
|
||||
}
|
||||
|
||||
} // namespace VAMR
|
55
intern/vamr/intern/Exception.h
Normal file
55
intern/vamr/intern/Exception.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __EXCEPTION_H__
|
||||
#define __EXCEPTION_H__
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
/**
|
||||
* For now just a general Exception type (note that it's in namespace VAMR, so name shouldn't cause
|
||||
* conflicts).
|
||||
*/
|
||||
class Exception : public std::exception {
|
||||
friend class Context;
|
||||
|
||||
public:
|
||||
Exception(const char *msg, const char *file, int line, int res = 0)
|
||||
: std::exception(), m_msg(msg), m_file(file), m_line(line), m_res(res)
|
||||
{
|
||||
}
|
||||
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *m_msg;
|
||||
const char *m_file;
|
||||
const int m_line;
|
||||
int m_res;
|
||||
};
|
||||
|
||||
} // namespace VAMR
|
||||
|
||||
#endif // __EXCEPTION_H__
|
308
intern/vamr/intern/GraphicsBinding.cc
Normal file
308
intern/vamr/intern/GraphicsBinding.cc
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
#if 0
|
||||
# if defined(WITH_X11)
|
||||
# include "GHOST_ContextGLX.h"
|
||||
# elif defined(WIN32)
|
||||
# include "GHOST_ContextWGL.h"
|
||||
# include "GHOST_ContextD3D.h"
|
||||
# endif
|
||||
#endif
|
||||
#include "VAMR_capi.h"
|
||||
|
||||
#include "IGraphicsBinding.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
static bool choose_swapchain_format_from_candidates(std::vector<int64_t> gpu_binding_formats,
|
||||
std::vector<int64_t> runtime_formats,
|
||||
int64_t *r_result)
|
||||
{
|
||||
if (gpu_binding_formats.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto res = std::find_first_of(gpu_binding_formats.begin(),
|
||||
gpu_binding_formats.end(),
|
||||
runtime_formats.begin(),
|
||||
runtime_formats.end());
|
||||
if (res == gpu_binding_formats.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_result = *res;
|
||||
return true;
|
||||
}
|
||||
|
||||
class GraphicsBindingOpenGL : public IGraphicsBinding {
|
||||
public:
|
||||
~GraphicsBindingOpenGL()
|
||||
{
|
||||
if (m_fbo != 0) {
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkVersionRequirements(GHOST_Context *ghost_ctx,
|
||||
XrInstance instance,
|
||||
XrSystemId system_id,
|
||||
std::string *r_requirement_info) const override
|
||||
{
|
||||
#if 0
|
||||
# if defined(WITH_X11)
|
||||
GHOST_ContextGLX *ctx_gl = static_cast<GHOST_ContextGLX *>(ghost_ctx);
|
||||
# else
|
||||
GHOST_ContextWGL *ctx_gl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
|
||||
# endif
|
||||
XrGraphicsRequirementsOpenGLKHR gpu_requirements{XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR};
|
||||
const XrVersion gl_version = XR_MAKE_VERSION(
|
||||
ctx_gl->m_contextMajorVersion, ctx_gl->m_contextMinorVersion, 0);
|
||||
|
||||
xrGetOpenGLGraphicsRequirementsKHR(instance, system_id, &gpu_requirements);
|
||||
|
||||
if (r_requirement_info) {
|
||||
std::ostringstream strstream;
|
||||
strstream << "Min OpenGL version "
|
||||
<< XR_VERSION_MAJOR(gpu_requirements.minApiVersionSupported) << "."
|
||||
<< XR_VERSION_MINOR(gpu_requirements.minApiVersionSupported) << std::endl;
|
||||
strstream << "Max OpenGL version "
|
||||
<< XR_VERSION_MAJOR(gpu_requirements.maxApiVersionSupported) << "."
|
||||
<< XR_VERSION_MINOR(gpu_requirements.maxApiVersionSupported) << std::endl;
|
||||
|
||||
*r_requirement_info = strstream.str();
|
||||
}
|
||||
|
||||
return (gl_version >= gpu_requirements.minApiVersionSupported) &&
|
||||
(gl_version <= gpu_requirements.maxApiVersionSupported);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void initFromGhostContext(GHOST_Context *ghost_ctx) override
|
||||
{
|
||||
#if 0
|
||||
# if defined(WITH_X11)
|
||||
GHOST_ContextGLX *ctx_glx = static_cast<GHOST_ContextGLX *>(ghost_ctx);
|
||||
XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx->m_display, ctx_glx->m_fbconfig);
|
||||
|
||||
oxr_binding.glx.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
|
||||
oxr_binding.glx.xDisplay = ctx_glx->m_display;
|
||||
oxr_binding.glx.glxFBConfig = ctx_glx->m_fbconfig;
|
||||
oxr_binding.glx.glxDrawable = ctx_glx->m_window;
|
||||
oxr_binding.glx.glxContext = ctx_glx->m_context;
|
||||
oxr_binding.glx.visualid = visual_info->visualid;
|
||||
# elif defined(WIN32)
|
||||
GHOST_ContextWGL *ctx_wgl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
|
||||
|
||||
oxr_binding.wgl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
|
||||
oxr_binding.wgl.hDC = ctx_wgl->m_hDC;
|
||||
oxr_binding.wgl.hGLRC = ctx_wgl->m_hGLRC;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Generate a framebuffer to use for blitting into the texture */
|
||||
glGenFramebuffers(1, &m_fbo);
|
||||
}
|
||||
|
||||
bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
int64_t *r_result) const override
|
||||
{
|
||||
std::vector<int64_t> gpu_binding_formats = {GL_RGBA8};
|
||||
return choose_swapchain_format_from_candidates(gpu_binding_formats, runtime_formats, r_result);
|
||||
}
|
||||
|
||||
std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
|
||||
{
|
||||
std::vector<XrSwapchainImageOpenGLKHR> ogl_images(image_count);
|
||||
std::vector<XrSwapchainImageBaseHeader *> base_images;
|
||||
|
||||
// Need to return vector of base header pointers, so of a different type. Need to build a new
|
||||
// list with this type, and keep the initial one alive.
|
||||
for (XrSwapchainImageOpenGLKHR &image : ogl_images) {
|
||||
image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
|
||||
base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
|
||||
}
|
||||
|
||||
// Keep alive.
|
||||
m_image_cache.push_back(std::move(ogl_images));
|
||||
|
||||
return base_images;
|
||||
}
|
||||
|
||||
void submitToSwapchain(XrSwapchainImageBaseHeader *swapchain_image,
|
||||
const VAMR_DrawViewInfo *draw_info) override
|
||||
{
|
||||
XrSwapchainImageOpenGLKHR *ogl_swapchain_image = reinterpret_cast<XrSwapchainImageOpenGLKHR *>(
|
||||
swapchain_image);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
|
||||
|
||||
glFramebufferTexture2D(
|
||||
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_swapchain_image->image, 0);
|
||||
|
||||
glBlitFramebuffer(draw_info->ofsx,
|
||||
draw_info->ofsy,
|
||||
draw_info->ofsx + draw_info->width,
|
||||
draw_info->ofsy + draw_info->height,
|
||||
draw_info->ofsx,
|
||||
draw_info->ofsy,
|
||||
draw_info->ofsx + draw_info->width,
|
||||
draw_info->ofsy + draw_info->height,
|
||||
GL_COLOR_BUFFER_BIT,
|
||||
GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<std::vector<XrSwapchainImageOpenGLKHR>> m_image_cache;
|
||||
GLuint m_fbo{0};
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
class GraphicsBindingD3D : public IGraphicsBinding {
|
||||
public:
|
||||
~GraphicsBindingD3D()
|
||||
{
|
||||
if (m_shared_resource) {
|
||||
m_ghost_ctx->disposeSharedOpenGLResource(m_shared_resource);
|
||||
}
|
||||
}
|
||||
|
||||
bool checkVersionRequirements(GHOST_Context *ghost_ctx,
|
||||
XrInstance instance,
|
||||
XrSystemId system_id,
|
||||
std::string *r_requirement_info) const override
|
||||
{
|
||||
|
||||
GHOST_ContextD3D *ctx_dx = static_cast<GHOST_ContextD3D *>(ghost_ctx);
|
||||
XrGraphicsRequirementsD3D11KHR gpu_requirements{XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR};
|
||||
|
||||
xrGetD3D11GraphicsRequirementsKHR(instance, system_id, &gpu_requirements);
|
||||
|
||||
if (r_requirement_info) {
|
||||
std::ostringstream strstream;
|
||||
strstream << "Min DirectX 11 Feature Level " << gpu_requirements.minFeatureLevel
|
||||
<< std::endl;
|
||||
|
||||
*r_requirement_info = std::move(strstream.str());
|
||||
}
|
||||
|
||||
return ctx_dx->m_device->GetFeatureLevel() >= gpu_requirements.minFeatureLevel;
|
||||
}
|
||||
|
||||
void initFromGhostContext(GHOST_Context *ghost_ctx) override
|
||||
{
|
||||
GHOST_ContextD3D *ctx_d3d = static_cast<GHOST_ContextD3D *>(ghost_ctx);
|
||||
|
||||
oxr_binding.d3d11.type = XR_TYPE_GRAPHICS_BINDING_D3D11_KHR;
|
||||
oxr_binding.d3d11.device = ctx_d3d->m_device;
|
||||
m_ghost_ctx = ctx_d3d;
|
||||
}
|
||||
|
||||
bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
int64_t *r_result) const override
|
||||
{
|
||||
std::vector<int64_t> gpu_binding_formats = {DXGI_FORMAT_R8G8B8A8_UNORM};
|
||||
return choose_swapchain_format_from_candidates(gpu_binding_formats, runtime_formats, r_result);
|
||||
}
|
||||
|
||||
std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
|
||||
{
|
||||
std::vector<XrSwapchainImageD3D11KHR> d3d_images(image_count);
|
||||
std::vector<XrSwapchainImageBaseHeader *> base_images;
|
||||
|
||||
// Need to return vector of base header pointers, so of a different type. Need to build a new
|
||||
// list with this type, and keep the initial one alive.
|
||||
for (XrSwapchainImageD3D11KHR &image : d3d_images) {
|
||||
image.type = XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR;
|
||||
base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
|
||||
}
|
||||
|
||||
// Keep alive.
|
||||
m_image_cache.push_back(std::move(d3d_images));
|
||||
|
||||
return base_images;
|
||||
}
|
||||
|
||||
void submitToSwapchain(XrSwapchainImageBaseHeader *swapchain_image,
|
||||
const VAMR_DrawViewInfo *draw_info) override
|
||||
{
|
||||
XrSwapchainImageD3D11KHR *d3d_swapchain_image = reinterpret_cast<XrSwapchainImageD3D11KHR *>(
|
||||
swapchain_image);
|
||||
|
||||
# if 0
|
||||
/* Ideally we'd just create a render target view for the OpenXR swapchain image texture and
|
||||
* blit from the OpenGL context into it. The NV_DX_interop extension doesn't want to work with
|
||||
* this though. At least not with Optimus hardware. See:
|
||||
* https://github.com/mpv-player/mpv/issues/2949#issuecomment-197262807.
|
||||
*/
|
||||
|
||||
ID3D11RenderTargetView *rtv;
|
||||
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
|
||||
m_ghost_ctx->m_device->CreateRenderTargetView(d3d_swapchain_image->texture, &rtv_desc, &rtv);
|
||||
if (!m_shared_resource) {
|
||||
m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(
|
||||
draw_info->width, draw_info->height, rtv);
|
||||
}
|
||||
m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
|
||||
# else
|
||||
if (!m_shared_resource) {
|
||||
m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(draw_info->width,
|
||||
draw_info->height);
|
||||
}
|
||||
m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
|
||||
|
||||
m_ghost_ctx->m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
m_ghost_ctx->m_device_ctx->CopyResource(d3d_swapchain_image->texture,
|
||||
m_ghost_ctx->getSharedTexture2D(m_shared_resource));
|
||||
# endif
|
||||
}
|
||||
|
||||
private:
|
||||
GHOST_ContextD3D *m_ghost_ctx;
|
||||
GHOST_SharedOpenGLResource *m_shared_resource;
|
||||
std::list<std::vector<XrSwapchainImageD3D11KHR>> m_image_cache;
|
||||
};
|
||||
#endif // WIN32
|
||||
|
||||
std::unique_ptr<IGraphicsBinding> GraphicsBindingCreateFromType(VAMR_GraphicsBindingType type)
|
||||
{
|
||||
switch (type) {
|
||||
case VAMR_GraphicsBindingTypeOpenGL:
|
||||
return std::unique_ptr<GraphicsBindingOpenGL>(new GraphicsBindingOpenGL());
|
||||
#ifdef WIN32
|
||||
case VAMR_GraphicsBindingTypeD3D11:
|
||||
return std::unique_ptr<GraphicsBindingD3D>(new GraphicsBindingD3D());
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace VAMR
|
74
intern/vamr/intern/IGraphicsBinding.h
Normal file
74
intern/vamr/intern/IGraphicsBinding.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __IGRAPHICSBINDING_H__
|
||||
#define __IGRAPHICSBINDING_H__
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "openxr_includes.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
class IGraphicsBinding {
|
||||
friend std::unique_ptr<IGraphicsBinding> GraphicsBindingCreateFromType(
|
||||
VAMR_GraphicsBindingType type);
|
||||
|
||||
public:
|
||||
union {
|
||||
#if defined(WITH_X11)
|
||||
XrGraphicsBindingOpenGLXlibKHR glx;
|
||||
#elif defined(WIN32)
|
||||
XrGraphicsBindingOpenGLWin32KHR wgl;
|
||||
XrGraphicsBindingD3D11KHR d3d11;
|
||||
#endif
|
||||
} oxr_binding;
|
||||
|
||||
/**
|
||||
* Does __not__ require this object is initialized (can be called prior to
|
||||
* #initFromGhostContext). It's actually meant to be called first.
|
||||
*
|
||||
* \param r_requirement_info Return argument to retrieve an informal string on the requirements
|
||||
* to be met. Useful for error/debug messages.
|
||||
*/
|
||||
virtual bool checkVersionRequirements(class GHOST_Context *ghost_ctx,
|
||||
XrInstance instance,
|
||||
XrSystemId system_id,
|
||||
std::string *r_requirement_info) const = 0;
|
||||
virtual void initFromGhostContext(class GHOST_Context *ghost_ctx) = 0;
|
||||
virtual bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
int64_t *r_result) const = 0;
|
||||
virtual std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(
|
||||
uint32_t image_count) = 0;
|
||||
virtual void submitToSwapchain(XrSwapchainImageBaseHeader *swapchain_image,
|
||||
const VAMR_DrawViewInfo *draw_info) = 0;
|
||||
|
||||
protected:
|
||||
/* Use GraphicsBindingCreateFromType */
|
||||
IGraphicsBinding() = default;
|
||||
};
|
||||
|
||||
std::unique_ptr<IGraphicsBinding> GraphicsBindingCreateFromType(VAMR_GraphicsBindingType type);
|
||||
|
||||
} // namespace VAMR
|
||||
|
||||
#endif /* __IGRAPHICSBINDING_H__ */
|
575
intern/vamr/intern/Session.cc
Normal file
575
intern/vamr/intern/Session.cc
Normal file
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
|
||||
#include "VAMR_capi.h"
|
||||
|
||||
#include "openxr_includes.h"
|
||||
|
||||
#include "Context.h"
|
||||
#include "Exception.h"
|
||||
#include "IGraphicsBinding.h"
|
||||
#include "Session.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
struct OpenXRSessionData {
|
||||
XrSystemId system_id{XR_NULL_SYSTEM_ID};
|
||||
XrSession session{XR_NULL_HANDLE};
|
||||
XrSessionState session_state{XR_SESSION_STATE_UNKNOWN};
|
||||
|
||||
// Only stereo rendering supported now.
|
||||
const XrViewConfigurationType view_type{XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO};
|
||||
XrSpace reference_space;
|
||||
std::vector<XrView> views;
|
||||
std::vector<XrSwapchain> swapchains;
|
||||
std::map<XrSwapchain, std::vector<XrSwapchainImageBaseHeader *>> swapchain_images;
|
||||
int32_t swapchain_image_width, swapchain_image_height;
|
||||
};
|
||||
|
||||
struct DrawInfo {
|
||||
XrFrameState frame_state;
|
||||
|
||||
/** Time at frame start to benchmark frame render durations. */
|
||||
std::chrono::high_resolution_clock::time_point frame_begin_time;
|
||||
/* Time previous frames took for rendering (in ms) */
|
||||
std::list<double> last_frame_times;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Create, Initialize and Destruct
|
||||
*
|
||||
* \{ */
|
||||
|
||||
Session::Session(Context *xr_context) : m_context(xr_context), m_oxr(new OpenXRSessionData())
|
||||
{
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
unbindGraphicsContext();
|
||||
|
||||
for (XrSwapchain &swapchain : m_oxr->swapchains) {
|
||||
CHECK_XR_ASSERT(xrDestroySwapchain(swapchain));
|
||||
}
|
||||
m_oxr->swapchains.clear();
|
||||
if (m_oxr->reference_space != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroySpace(m_oxr->reference_space));
|
||||
}
|
||||
if (m_oxr->session != XR_NULL_HANDLE) {
|
||||
CHECK_XR_ASSERT(xrDestroySession(m_oxr->session));
|
||||
}
|
||||
|
||||
m_oxr->session = XR_NULL_HANDLE;
|
||||
m_oxr->session_state = XR_SESSION_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* A system in OpenXR the combination of some sort of HMD plus controllers and whatever other
|
||||
* devices are managed through OpenXR. So this attempts to init the HMD and the other devices.
|
||||
*/
|
||||
void Session::initSystem()
|
||||
{
|
||||
assert(m_context->getInstance() != XR_NULL_HANDLE);
|
||||
assert(m_oxr->system_id == XR_NULL_SYSTEM_ID);
|
||||
|
||||
XrSystemGetInfo system_info{};
|
||||
system_info.type = XR_TYPE_SYSTEM_GET_INFO;
|
||||
system_info.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
|
||||
CHECK_XR(xrGetSystem(m_context->getInstance(), &system_info, &m_oxr->system_id),
|
||||
"Failed to get device information. Is a device plugged in?");
|
||||
}
|
||||
|
||||
/** \} */ /* Create, Initialize and Destruct */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name State Management
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void create_reference_space(OpenXRSessionData *oxr, const VAMR_Pose *base_pose)
|
||||
{
|
||||
XrReferenceSpaceCreateInfo create_info{XR_TYPE_REFERENCE_SPACE_CREATE_INFO};
|
||||
create_info.poseInReferenceSpace.orientation.w = 1.0f;
|
||||
|
||||
create_info.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
|
||||
#if 0
|
||||
/* Proper reference space set up is not supported yet. We simply hand OpenXR
|
||||
* the global space as reference space and apply its pose onto the active
|
||||
* camera matrix to get a basic viewing experience going. If there's no active
|
||||
* camera with stick to the world origin.
|
||||
*
|
||||
* Once we have proper reference space set up (i.e. a way to define origin, up-
|
||||
* direction and an initial view rotation perpendicular to the up-direction),
|
||||
* we can hand OpenXR a proper reference pose/space.
|
||||
*/
|
||||
create_info.poseInReferenceSpace.position.x = base_pose->position[0];
|
||||
create_info.poseInReferenceSpace.position.y = base_pose->position[2];
|
||||
create_info.poseInReferenceSpace.position.z = -base_pose->position[1];
|
||||
create_info.poseInReferenceSpace.orientation.x = base_pose->orientation_quat[1];
|
||||
create_info.poseInReferenceSpace.orientation.y = base_pose->orientation_quat[3];
|
||||
create_info.poseInReferenceSpace.orientation.z = -base_pose->orientation_quat[2];
|
||||
create_info.poseInReferenceSpace.orientation.w = base_pose->orientation_quat[0];
|
||||
#else
|
||||
(void)base_pose;
|
||||
#endif
|
||||
|
||||
CHECK_XR(xrCreateReferenceSpace(oxr->session, &create_info, &oxr->reference_space),
|
||||
"Failed to create reference space.");
|
||||
}
|
||||
|
||||
void Session::start(const VAMR_SessionBeginInfo *begin_info)
|
||||
{
|
||||
assert(m_context->getInstance() != XR_NULL_HANDLE);
|
||||
assert(m_oxr->session == XR_NULL_HANDLE);
|
||||
if (m_context->getCustomFuncs()->gpu_ctx_bind_fn == nullptr) {
|
||||
THROW_XR(
|
||||
"Invalid API usage: No way to bind graphics context to the XR session. Call "
|
||||
"VAMR_GraphicsContextBindFuncs() with valid parameters before starting the "
|
||||
"session (through VAMR_SessionStart()).");
|
||||
}
|
||||
|
||||
initSystem();
|
||||
|
||||
bindGraphicsContext();
|
||||
if (m_gpu_ctx == nullptr) {
|
||||
THROW_XR(
|
||||
"Invalid API usage: No graphics context returned through the callback set with "
|
||||
"VAMR_GraphicsContextBindFuncs(). This is required for session starting (through "
|
||||
"VAMR_SessionStart()).");
|
||||
}
|
||||
|
||||
std::string requirement_str;
|
||||
m_gpu_binding = GraphicsBindingCreateFromType(m_context->getGraphicsBindingType());
|
||||
if (!m_gpu_binding->checkVersionRequirements(
|
||||
m_gpu_ctx, m_context->getInstance(), m_oxr->system_id, &requirement_str)) {
|
||||
std::ostringstream strstream;
|
||||
strstream << "Available graphics context version does not meet the following requirements: "
|
||||
<< requirement_str;
|
||||
THROW_XR(strstream.str().c_str());
|
||||
}
|
||||
m_gpu_binding->initFromGhostContext(m_gpu_ctx);
|
||||
|
||||
XrSessionCreateInfo create_info{};
|
||||
create_info.type = XR_TYPE_SESSION_CREATE_INFO;
|
||||
create_info.systemId = m_oxr->system_id;
|
||||
create_info.next = &m_gpu_binding->oxr_binding;
|
||||
|
||||
CHECK_XR(xrCreateSession(m_context->getInstance(), &create_info, &m_oxr->session),
|
||||
"Failed to create VR session. The OpenXR runtime may have additional requirements for "
|
||||
"the graphics driver that are not met. Other causes are possible too however.\nTip: "
|
||||
"The --debug-xr command line option for Blender might allow the runtime to output "
|
||||
"detailed error information to the command line.");
|
||||
|
||||
prepareDrawing();
|
||||
create_reference_space(m_oxr.get(), &begin_info->base_pose);
|
||||
}
|
||||
|
||||
void Session::requestEnd()
|
||||
{
|
||||
xrRequestExitSession(m_oxr->session);
|
||||
}
|
||||
|
||||
void Session::end()
|
||||
{
|
||||
assert(m_oxr->session != XR_NULL_HANDLE);
|
||||
|
||||
CHECK_XR(xrEndSession(m_oxr->session), "Failed to cleanly end the VR session.");
|
||||
unbindGraphicsContext();
|
||||
m_draw_info = nullptr;
|
||||
}
|
||||
|
||||
Session::eLifeExpectancy Session::handleStateChangeEvent(
|
||||
const XrEventDataSessionStateChanged *lifecycle)
|
||||
{
|
||||
m_oxr->session_state = lifecycle->state;
|
||||
|
||||
/* Runtime may send events for apparently destroyed session. Our handle should be NULL then. */
|
||||
assert((m_oxr->session == XR_NULL_HANDLE) || (m_oxr->session == lifecycle->session));
|
||||
|
||||
switch (lifecycle->state) {
|
||||
case XR_SESSION_STATE_READY: {
|
||||
XrSessionBeginInfo begin_info{};
|
||||
|
||||
begin_info.type = XR_TYPE_SESSION_BEGIN_INFO;
|
||||
begin_info.primaryViewConfigurationType = m_oxr->view_type;
|
||||
CHECK_XR(xrBeginSession(m_oxr->session, &begin_info),
|
||||
"Failed to cleanly begin the VR session.");
|
||||
break;
|
||||
}
|
||||
case XR_SESSION_STATE_STOPPING:
|
||||
/* Runtime will change state to STATE_EXITING, don't destruct session yet. */
|
||||
end();
|
||||
break;
|
||||
case XR_SESSION_STATE_EXITING:
|
||||
case XR_SESSION_STATE_LOSS_PENDING:
|
||||
return SESSION_DESTROY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SESSION_KEEP_ALIVE;
|
||||
}
|
||||
/** \} */ /* State Management */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Drawing
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static std::vector<XrSwapchainImageBaseHeader *> swapchain_images_create(
|
||||
XrSwapchain swapchain, IGraphicsBinding *gpu_binding)
|
||||
{
|
||||
std::vector<XrSwapchainImageBaseHeader *> images;
|
||||
uint32_t image_count;
|
||||
|
||||
CHECK_XR(xrEnumerateSwapchainImages(swapchain, 0, &image_count, nullptr),
|
||||
"Failed to get count of swapchain images to create for the VR session.");
|
||||
images = gpu_binding->createSwapchainImages(image_count);
|
||||
CHECK_XR(xrEnumerateSwapchainImages(swapchain, images.size(), &image_count, images[0]),
|
||||
"Failed to create swapchain images for the VR session.");
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
static unique_oxr_ptr<XrSwapchain> swapchain_create(const XrSession session,
|
||||
IGraphicsBinding *gpu_binding,
|
||||
const XrViewConfigurationView *xr_view)
|
||||
{
|
||||
XrSwapchainCreateInfo create_info{XR_TYPE_SWAPCHAIN_CREATE_INFO};
|
||||
unique_oxr_ptr<XrSwapchain> swapchain(xrDestroySwapchain);
|
||||
uint32_t format_count = 0;
|
||||
int64_t chosen_format;
|
||||
|
||||
CHECK_XR(xrEnumerateSwapchainFormats(session, 0, &format_count, nullptr),
|
||||
"Failed to get count of swapchain image formats.");
|
||||
std::vector<int64_t> swapchain_formats(format_count);
|
||||
CHECK_XR(xrEnumerateSwapchainFormats(
|
||||
session, swapchain_formats.size(), &format_count, swapchain_formats.data()),
|
||||
"Failed to get swapchain image formats.");
|
||||
assert(swapchain_formats.size() == format_count);
|
||||
|
||||
if (!gpu_binding->chooseSwapchainFormat(swapchain_formats, &chosen_format)) {
|
||||
THROW_XR("Error: No format matching OpenXR runtime supported swapchain formats found.");
|
||||
}
|
||||
|
||||
create_info.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT |
|
||||
XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
create_info.format = chosen_format;
|
||||
create_info.sampleCount = xr_view->recommendedSwapchainSampleCount;
|
||||
create_info.width = xr_view->recommendedImageRectWidth;
|
||||
create_info.height = xr_view->recommendedImageRectHeight;
|
||||
create_info.faceCount = 1;
|
||||
create_info.arraySize = 1;
|
||||
create_info.mipCount = 1;
|
||||
CHECK_XR(swapchain.construct(xrCreateSwapchain, session, &create_info),
|
||||
"Failed to create OpenXR swapchain.");
|
||||
|
||||
return swapchain;
|
||||
}
|
||||
|
||||
void Session::prepareDrawing()
|
||||
{
|
||||
std::vector<XrViewConfigurationView> view_configs;
|
||||
uint32_t view_count;
|
||||
|
||||
CHECK_XR(
|
||||
xrEnumerateViewConfigurationViews(
|
||||
m_context->getInstance(), m_oxr->system_id, m_oxr->view_type, 0, &view_count, nullptr),
|
||||
"Failed to get count of view configurations.");
|
||||
view_configs.resize(view_count, {XR_TYPE_VIEW_CONFIGURATION_VIEW});
|
||||
CHECK_XR(xrEnumerateViewConfigurationViews(m_context->getInstance(),
|
||||
m_oxr->system_id,
|
||||
m_oxr->view_type,
|
||||
view_configs.size(),
|
||||
&view_count,
|
||||
view_configs.data()),
|
||||
"Failed to get count of view configurations.");
|
||||
|
||||
for (const XrViewConfigurationView &view : view_configs) {
|
||||
unique_oxr_ptr<XrSwapchain> swapchain = swapchain_create(
|
||||
m_oxr->session, m_gpu_binding.get(), &view);
|
||||
auto images = swapchain_images_create(swapchain.get(), m_gpu_binding.get());
|
||||
|
||||
m_oxr->swapchain_image_width = view.recommendedImageRectWidth;
|
||||
m_oxr->swapchain_image_height = view.recommendedImageRectHeight;
|
||||
m_oxr->swapchains.push_back(swapchain.get());
|
||||
m_oxr->swapchain_images.insert(std::make_pair(swapchain.get(), std::move(images)));
|
||||
|
||||
swapchain.release();
|
||||
}
|
||||
|
||||
m_oxr->views.resize(view_count, {XR_TYPE_VIEW});
|
||||
|
||||
m_draw_info = std::unique_ptr<DrawInfo>(new DrawInfo());
|
||||
}
|
||||
|
||||
void Session::beginFrameDrawing()
|
||||
{
|
||||
XrFrameWaitInfo wait_info{XR_TYPE_FRAME_WAIT_INFO};
|
||||
XrFrameBeginInfo begin_info{XR_TYPE_FRAME_BEGIN_INFO};
|
||||
XrFrameState frame_state{XR_TYPE_FRAME_STATE};
|
||||
|
||||
// TODO Blocking call. Does this intefer with other drawing?
|
||||
CHECK_XR(xrWaitFrame(m_oxr->session, &wait_info, &frame_state),
|
||||
"Failed to synchronize frame rates between Blender and the device.");
|
||||
|
||||
CHECK_XR(xrBeginFrame(m_oxr->session, &begin_info),
|
||||
"Failed to submit frame rendering start state.");
|
||||
|
||||
m_draw_info->frame_state = frame_state;
|
||||
|
||||
if (m_context->isDebugTimeMode()) {
|
||||
m_draw_info->frame_begin_time = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
}
|
||||
|
||||
static void print_debug_timings(DrawInfo *draw_info)
|
||||
{
|
||||
/** Render time of last 8 frames (in ms) to calculate an average. */
|
||||
std::chrono::duration<double, std::milli> duration = std::chrono::high_resolution_clock::now() -
|
||||
draw_info->frame_begin_time;
|
||||
const double duration_ms = duration.count();
|
||||
const int avg_frame_count = 8;
|
||||
double avg_ms_tot = 0.0;
|
||||
|
||||
if (draw_info->last_frame_times.size() >= avg_frame_count) {
|
||||
draw_info->last_frame_times.pop_front();
|
||||
assert(draw_info->last_frame_times.size() == avg_frame_count - 1);
|
||||
}
|
||||
draw_info->last_frame_times.push_back(duration_ms);
|
||||
for (double ms_iter : draw_info->last_frame_times) {
|
||||
avg_ms_tot += ms_iter;
|
||||
}
|
||||
|
||||
printf("VR frame render time: %.0fms - %.2f FPS (%.2f FPS 8 frames average)\n",
|
||||
duration_ms,
|
||||
1000.0 / duration_ms,
|
||||
1000.0 / (avg_ms_tot / draw_info->last_frame_times.size()));
|
||||
}
|
||||
|
||||
void Session::endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> *layers)
|
||||
{
|
||||
XrFrameEndInfo end_info{XR_TYPE_FRAME_END_INFO};
|
||||
|
||||
end_info.displayTime = m_draw_info->frame_state.predictedDisplayTime;
|
||||
end_info.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
||||
end_info.layerCount = layers->size();
|
||||
end_info.layers = layers->data();
|
||||
|
||||
CHECK_XR(xrEndFrame(m_oxr->session, &end_info), "Failed to submit rendered frame.");
|
||||
|
||||
if (m_context->isDebugTimeMode()) {
|
||||
print_debug_timings(m_draw_info.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Session::draw(void *draw_customdata)
|
||||
{
|
||||
std::vector<XrCompositionLayerProjectionView>
|
||||
projection_layer_views; // Keep alive until xrEndFrame() call!
|
||||
XrCompositionLayerProjection proj_layer;
|
||||
std::vector<XrCompositionLayerBaseHeader *> layers;
|
||||
|
||||
beginFrameDrawing();
|
||||
|
||||
if (m_draw_info->frame_state.shouldRender) {
|
||||
proj_layer = drawLayer(projection_layer_views, draw_customdata);
|
||||
layers.push_back(reinterpret_cast<XrCompositionLayerBaseHeader *>(&proj_layer));
|
||||
}
|
||||
|
||||
endFrameDrawing(&layers);
|
||||
}
|
||||
|
||||
static void vamr_draw_view_info_from_view(const XrView &view, VAMR_DrawViewInfo &r_info)
|
||||
{
|
||||
#if 0
|
||||
/* Set and convert to Blender coodinate space */
|
||||
r_info.pose.position[0] = view.pose.position.x;
|
||||
r_info.pose.position[1] = -view.pose.position.z;
|
||||
r_info.pose.position[2] = view.pose.position.y;
|
||||
r_info.pose.orientation_quat[0] = view.pose.orientation.w;
|
||||
r_info.pose.orientation_quat[1] = view.pose.orientation.x;
|
||||
r_info.pose.orientation_quat[2] = -view.pose.orientation.z;
|
||||
r_info.pose.orientation_quat[3] = view.pose.orientation.y;
|
||||
#else
|
||||
r_info.pose.position[0] = view.pose.position.x;
|
||||
r_info.pose.position[1] = view.pose.position.y;
|
||||
r_info.pose.position[2] = view.pose.position.z;
|
||||
r_info.pose.orientation_quat[0] = view.pose.orientation.w;
|
||||
r_info.pose.orientation_quat[1] = view.pose.orientation.x;
|
||||
r_info.pose.orientation_quat[2] = view.pose.orientation.y;
|
||||
r_info.pose.orientation_quat[3] = view.pose.orientation.z;
|
||||
#endif
|
||||
|
||||
r_info.fov.angle_left = view.fov.angleLeft;
|
||||
r_info.fov.angle_right = view.fov.angleRight;
|
||||
r_info.fov.angle_up = view.fov.angleUp;
|
||||
r_info.fov.angle_down = view.fov.angleDown;
|
||||
}
|
||||
|
||||
static bool vamr_draw_view_expects_srgb_buffer(const Context *context)
|
||||
{
|
||||
/* WMR seems to be faulty and doesn't do OETF transform correctly. So expect a SRGB buffer to
|
||||
* compensate. */
|
||||
return context->getOpenXRRuntimeID() == OPENXR_RUNTIME_WMR;
|
||||
}
|
||||
|
||||
void Session::drawView(XrSwapchain swapchain,
|
||||
XrCompositionLayerProjectionView &proj_layer_view,
|
||||
XrView &view,
|
||||
void *draw_customdata)
|
||||
{
|
||||
XrSwapchainImageAcquireInfo acquire_info{XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO};
|
||||
XrSwapchainImageWaitInfo wait_info{XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO};
|
||||
XrSwapchainImageReleaseInfo release_info{XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO};
|
||||
XrSwapchainImageBaseHeader *swapchain_image;
|
||||
VAMR_DrawViewInfo draw_view_info{};
|
||||
uint32_t swapchain_idx;
|
||||
|
||||
CHECK_XR(xrAcquireSwapchainImage(swapchain, &acquire_info, &swapchain_idx),
|
||||
"Failed to acquire swapchain image for the VR session.");
|
||||
wait_info.timeout = XR_INFINITE_DURATION;
|
||||
CHECK_XR(xrWaitSwapchainImage(swapchain, &wait_info),
|
||||
"Failed to acquire swapchain image for the VR session.");
|
||||
|
||||
proj_layer_view.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
||||
proj_layer_view.pose = view.pose;
|
||||
proj_layer_view.fov = view.fov;
|
||||
proj_layer_view.subImage.swapchain = swapchain;
|
||||
proj_layer_view.subImage.imageRect.offset = {0, 0};
|
||||
proj_layer_view.subImage.imageRect.extent = {m_oxr->swapchain_image_width,
|
||||
m_oxr->swapchain_image_height};
|
||||
|
||||
swapchain_image = m_oxr->swapchain_images[swapchain][swapchain_idx];
|
||||
|
||||
draw_view_info.expects_srgb_buffer = vamr_draw_view_expects_srgb_buffer(m_context);
|
||||
draw_view_info.ofsx = proj_layer_view.subImage.imageRect.offset.x;
|
||||
draw_view_info.ofsy = proj_layer_view.subImage.imageRect.offset.y;
|
||||
draw_view_info.width = proj_layer_view.subImage.imageRect.extent.width;
|
||||
draw_view_info.height = proj_layer_view.subImage.imageRect.extent.height;
|
||||
vamr_draw_view_info_from_view(view, draw_view_info);
|
||||
|
||||
m_context->getCustomFuncs()->draw_view_fn(&draw_view_info, draw_customdata);
|
||||
m_gpu_binding->submitToSwapchain(swapchain_image, &draw_view_info);
|
||||
|
||||
CHECK_XR(xrReleaseSwapchainImage(swapchain, &release_info),
|
||||
"Failed to release swapchain image used to submit VR session frame.");
|
||||
}
|
||||
|
||||
XrCompositionLayerProjection Session::drawLayer(
|
||||
std::vector<XrCompositionLayerProjectionView> &proj_layer_views, void *draw_customdata)
|
||||
{
|
||||
XrViewLocateInfo viewloc_info{XR_TYPE_VIEW_LOCATE_INFO};
|
||||
XrViewState view_state{XR_TYPE_VIEW_STATE};
|
||||
XrCompositionLayerProjection layer{XR_TYPE_COMPOSITION_LAYER_PROJECTION};
|
||||
uint32_t view_count;
|
||||
|
||||
viewloc_info.viewConfigurationType = m_oxr->view_type;
|
||||
viewloc_info.displayTime = m_draw_info->frame_state.predictedDisplayTime;
|
||||
viewloc_info.space = m_oxr->reference_space;
|
||||
|
||||
CHECK_XR(xrLocateViews(m_oxr->session,
|
||||
&viewloc_info,
|
||||
&view_state,
|
||||
m_oxr->views.size(),
|
||||
&view_count,
|
||||
m_oxr->views.data()),
|
||||
"Failed to query frame view and projection state.");
|
||||
assert(m_oxr->swapchains.size() == view_count);
|
||||
|
||||
proj_layer_views.resize(view_count);
|
||||
|
||||
for (uint32_t view_idx = 0; view_idx < view_count; view_idx++) {
|
||||
drawView(m_oxr->swapchains[view_idx],
|
||||
proj_layer_views[view_idx],
|
||||
m_oxr->views[view_idx],
|
||||
draw_customdata);
|
||||
}
|
||||
|
||||
layer.space = m_oxr->reference_space;
|
||||
layer.viewCount = proj_layer_views.size();
|
||||
layer.views = proj_layer_views.data();
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
/** \} */ /* Drawing */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name State Queries
|
||||
*
|
||||
* \{ */
|
||||
|
||||
bool Session::isRunning() const
|
||||
{
|
||||
if (m_oxr->session == XR_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
switch (m_oxr->session_state) {
|
||||
case XR_SESSION_STATE_READY:
|
||||
case XR_SESSION_STATE_SYNCHRONIZED:
|
||||
case XR_SESSION_STATE_VISIBLE:
|
||||
case XR_SESSION_STATE_FOCUSED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* State Queries */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Graphics Context Injection
|
||||
*
|
||||
* Sessions need access to Ghost graphics context information. Additionally, this API allows
|
||||
* creating contexts on the fly (created on start, destructed on end). For this, callbacks to bind
|
||||
* (potentially create) and unbind (potentially destruct) a Ghost graphics context have to be set,
|
||||
* which will be called on session start and end respectively.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void Session::bindGraphicsContext()
|
||||
{
|
||||
const CustomFuncs *custom_funcs = m_context->getCustomFuncs();
|
||||
assert(custom_funcs->gpu_ctx_bind_fn);
|
||||
m_gpu_ctx = static_cast<GHOST_Context *>(
|
||||
custom_funcs->gpu_ctx_bind_fn(m_context->getGraphicsBindingType()));
|
||||
}
|
||||
void Session::unbindGraphicsContext()
|
||||
{
|
||||
const CustomFuncs *custom_funcs = m_context->getCustomFuncs();
|
||||
if (custom_funcs->gpu_ctx_unbind_fn) {
|
||||
custom_funcs->gpu_ctx_unbind_fn(m_context->getGraphicsBindingType(), m_gpu_ctx);
|
||||
}
|
||||
m_gpu_ctx = nullptr;
|
||||
}
|
||||
|
||||
/** \} */ /* Graphics Context Injection */
|
||||
|
||||
} // namespace VAMR
|
82
intern/vamr/intern/Session.h
Normal file
82
intern/vamr/intern/Session.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __SESSION_H__
|
||||
#define __SESSION_H__
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
class Session {
|
||||
public:
|
||||
enum eLifeExpectancy {
|
||||
SESSION_KEEP_ALIVE,
|
||||
SESSION_DESTROY,
|
||||
};
|
||||
|
||||
Session(class Context *xr_context);
|
||||
~Session();
|
||||
|
||||
void start(const VAMR_SessionBeginInfo *begin_info);
|
||||
void requestEnd();
|
||||
|
||||
eLifeExpectancy handleStateChangeEvent(const struct XrEventDataSessionStateChanged *lifecycle);
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
void unbindGraphicsContext(); /* public so context can ensure it's unbound as needed. */
|
||||
|
||||
void draw(void *draw_customdata);
|
||||
|
||||
private:
|
||||
/** Pointer back to context managing this session. Would be nice to avoid, but needed to access
|
||||
* custom callbacks set before session start. */
|
||||
class Context *m_context;
|
||||
|
||||
std::unique_ptr<struct OpenXRSessionData> m_oxr; /* Could use stack, but PImpl is preferable */
|
||||
|
||||
/** Active Ghost graphic context. Owned by Blender, not VAMR. */
|
||||
class GHOST_Context *m_gpu_ctx{nullptr};
|
||||
std::unique_ptr<class IGraphicsBinding> m_gpu_binding;
|
||||
|
||||
/** Rendering information. Set when drawing starts. */
|
||||
std::unique_ptr<struct DrawInfo> m_draw_info;
|
||||
|
||||
void initSystem();
|
||||
void end();
|
||||
|
||||
void bindGraphicsContext();
|
||||
|
||||
void prepareDrawing();
|
||||
XrCompositionLayerProjection drawLayer(
|
||||
std::vector<XrCompositionLayerProjectionView> &proj_layer_views, void *draw_customdata);
|
||||
void drawView(XrSwapchain swapchain,
|
||||
XrCompositionLayerProjectionView &proj_layer_view,
|
||||
XrView &view,
|
||||
void *draw_customdata);
|
||||
void beginFrameDrawing();
|
||||
void endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> *layers);
|
||||
};
|
||||
|
||||
} // namespace VAMR
|
||||
|
||||
#endif /* __SESSION_H__ */
|
73
intern/vamr/intern/VAMR.cc
Normal file
73
intern/vamr/intern/VAMR.cc
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*
|
||||
* Abstraction for XR (VR, AR, MR, ..) access via OpenXR.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include "VAMR_capi.h"
|
||||
|
||||
#include "openxr_includes.h"
|
||||
|
||||
#include "Context.h"
|
||||
#include "Exception.h"
|
||||
#include "utils.h"
|
||||
|
||||
using namespace VAMR;
|
||||
|
||||
/**
|
||||
* \brief Initialize the XR-Context.
|
||||
* Includes setting up the OpenXR instance, querying available extensions and API layers,
|
||||
* enabling extensions (currently graphics binding extension only) and API layers.
|
||||
*/
|
||||
VAMR_ContextHandle VAMR_ContextCreate(const VAMR_ContextCreateInfo *create_info)
|
||||
{
|
||||
Context *xr_context = new Context(create_info);
|
||||
|
||||
// TODO VAMR_Context's should probably be owned by the GHOST_System, which will handle context
|
||||
// creation and destruction. Try-catch logic can be moved to C-API then.
|
||||
try {
|
||||
xr_context->initialize(create_info);
|
||||
}
|
||||
catch (Exception &e) {
|
||||
xr_context->dispatchErrorMessage(&e);
|
||||
delete xr_context;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (VAMR_ContextHandle)xr_context;
|
||||
}
|
||||
|
||||
void VAMR_ContextDestroy(VAMR_ContextHandle xr_contexthandle)
|
||||
{
|
||||
delete (Context *)xr_contexthandle;
|
||||
}
|
||||
|
||||
void VAMR_ErrorHandler(VAMR_ErrorHandlerFn handler_fn, void *customdata)
|
||||
{
|
||||
Context::setErrorHandler(handler_fn, customdata);
|
||||
}
|
||||
|
||||
VAMR_TSuccess VAMR_EventsHandle(VAMR_ContextHandle xr_contexthandle)
|
||||
{
|
||||
return VAMR_EventsHandle((Context *)xr_contexthandle);
|
||||
}
|
52
intern/vamr/intern/openxr_includes.h
Normal file
52
intern/vamr/intern/openxr_includes.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*
|
||||
* \note This is taken mostly from the OpenXR SDK, but with modified D3D versions (e.g. d3d11_4.h
|
||||
* -> d3d11.h). Take care for that when updating, we don't want to require newest Win SDKs to be
|
||||
* installed.
|
||||
*/
|
||||
|
||||
#ifndef __VAMR_OPENXR_INCLUDES_H__
|
||||
#define __VAMR_OPENXR_INCLUDES_H__
|
||||
|
||||
/* Platform headers */
|
||||
#ifdef XR_USE_PLATFORM_WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Graphics headers */
|
||||
#ifdef XR_USE_GRAPHICS_API_D3D10
|
||||
# include <d3d10_1.h>
|
||||
#endif
|
||||
#ifdef XR_USE_GRAPHICS_API_D3D11
|
||||
# include <d3d11.h>
|
||||
#endif
|
||||
#ifdef XR_USE_GRAPHICS_API_D3D12
|
||||
# include <d3d12.h>
|
||||
#endif
|
||||
#ifdef WITH_X11
|
||||
# include <GL/glxew.h>
|
||||
#endif
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#endif /* __VAMR_OPENXR_INCLUDES_H__ */
|
136
intern/vamr/intern/utils.h
Normal file
136
intern/vamr/intern/utils.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup VAMR
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace VAMR {
|
||||
|
||||
#define CHECK_XR(call, error_msg) \
|
||||
{ \
|
||||
XrResult _res = call; \
|
||||
if (XR_FAILED(_res)) { \
|
||||
throw VAMR::Exception(error_msg, __FILE__, __LINE__, _res); \
|
||||
} \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
#define CHECK_XR_ASSERT(call) \
|
||||
{ \
|
||||
XrResult _res = call; \
|
||||
assert(_res == XR_SUCCESS); \
|
||||
(void)_res; \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
#define THROW_XR(error_msg) throw VAMR::Exception(error_msg, __FILE__, __LINE__);
|
||||
|
||||
#define XR_DEBUG_ONLY_BEGIN(ctx) \
|
||||
if ((ctx)->isDebugMode()) { \
|
||||
(void)0
|
||||
#define XR_DEBUG_ONLY_END \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
#define XR_DEBUG_PRINTF(ctx, ...) \
|
||||
if ((ctx)->isDebugMode()) { \
|
||||
printf(__VA_ARGS__); \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
#define XR_DEBUG_ONLY_CALL(ctx, call) \
|
||||
if ((ctx)->isDebugMode()) { \
|
||||
call; \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
/**
|
||||
* Helper for RAII usage of OpenXR handles (defined with XR_DEFINE_HANDLE). This is based on
|
||||
* `std::unique_ptr`, to give similar behavior and usage (e.g. functions like #get() and #release()
|
||||
* are supported).
|
||||
*/
|
||||
template<typename _OXR_HANDLE> class unique_oxr_ptr {
|
||||
public:
|
||||
using xr_destroy_func = XrResult (*)(_OXR_HANDLE);
|
||||
|
||||
unique_oxr_ptr(xr_destroy_func destroy_fn) : m_destroy_fn(destroy_fn)
|
||||
{
|
||||
}
|
||||
|
||||
unique_oxr_ptr(unique_oxr_ptr &&other) : m_ptr(other.release()), m_destroy_fn(other.m_destroy_fn)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the pointer from a xrCreate function passed as \a create_fn, with additional
|
||||
* arguments forwarded from \a args.
|
||||
* For example, this:
|
||||
* \code
|
||||
* some_unique_oxr_ptr.contruct(xrCreateFoo, some_arg, some_other_arg);
|
||||
* \endcode
|
||||
* effectively results in this call:
|
||||
* \code
|
||||
* xrCreateFoo(some_arg, some_other_arg, &some_unique_oxr_ptr.m_ptr);
|
||||
* \endcode
|
||||
*/
|
||||
template<typename _create_func, typename... _Args>
|
||||
XrResult construct(_create_func create_fn, _Args &&... args)
|
||||
{
|
||||
assert(m_ptr == XR_NULL_HANDLE);
|
||||
return create_fn(std::forward<_Args>(args)..., &m_ptr);
|
||||
}
|
||||
|
||||
~unique_oxr_ptr()
|
||||
{
|
||||
if (m_ptr != XR_NULL_HANDLE) {
|
||||
m_destroy_fn(m_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
_OXR_HANDLE get()
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
_OXR_HANDLE release()
|
||||
{
|
||||
_OXR_HANDLE ptr = get();
|
||||
m_ptr = XR_NULL_HANDLE;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* operator= defines not needed for now. */
|
||||
|
||||
unique_oxr_ptr(const unique_oxr_ptr &) = delete;
|
||||
unique_oxr_ptr &operator=(const unique_oxr_ptr &) = delete;
|
||||
|
||||
private:
|
||||
_OXR_HANDLE m_ptr{XR_NULL_HANDLE};
|
||||
xr_destroy_func m_destroy_fn;
|
||||
};
|
||||
|
||||
::VAMR_TSuccess VAMR_EventsHandle(class Context *xr_context);
|
||||
|
||||
} // namespace VAMR
|
||||
|
||||
#endif /* __UTILS_H__ */
|
8
release/windows/batch/blender_oculus.cmd
Normal file
8
release/windows/batch/blender_oculus.cmd
Normal file
@@ -0,0 +1,8 @@
|
||||
@echo off
|
||||
echo Starting Blender with Oculus OpenXR support. This assumes the Oculus runtime
|
||||
echo is installed in the default location. If this is not the case, please adjust
|
||||
echo the path inside oculus.json.
|
||||
echo.
|
||||
pause
|
||||
set XR_RUNTIME_JSON=%~dp0oculus.json
|
||||
blender
|
7
release/windows/batch/oculus.json
Normal file
7
release/windows/batch/oculus.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"file_format_version": "1.0.0",
|
||||
"runtime": {
|
||||
"library_path": "c:\\Program Files\\Oculus\\Support\\oculus-runtime\\LibOVRRT64_1.dll"
|
||||
},
|
||||
"api_layer": { }
|
||||
}
|
@@ -151,6 +151,8 @@ enum {
|
||||
G_DEBUG_IO = (1 << 17), /* IO Debugging (for Collada, ...)*/
|
||||
G_DEBUG_GPU_SHADERS = (1 << 18), /* GLSL shaders */
|
||||
G_DEBUG_GPU_FORCE_WORKAROUNDS = (1 << 19), /* force gpu workarounds bypassing detections. */
|
||||
G_DEBUG_XR = (1 << 20), /* XR/OpenXR messages */
|
||||
G_DEBUG_XR_TIME = (1 << 21), /* XR/OpenXR timing messages */
|
||||
};
|
||||
|
||||
#define G_DEBUG_ALL \
|
||||
|
@@ -627,6 +627,13 @@ void perspective_m4(float mat[4][4],
|
||||
const float top,
|
||||
const float nearClip,
|
||||
const float farClip);
|
||||
void perspective_m4_fov(float mat[4][4],
|
||||
const float angle_left,
|
||||
const float angle_right,
|
||||
const float angle_up,
|
||||
const float angle_down,
|
||||
const float nearClip,
|
||||
const float farClip);
|
||||
void orthographic_m4(float mat[4][4],
|
||||
const float left,
|
||||
const float right,
|
||||
|
@@ -4637,6 +4637,33 @@ void perspective_m4(float mat[4][4],
|
||||
mat[3][3] = 0.0f;
|
||||
}
|
||||
|
||||
void perspective_m4_fov(float mat[4][4],
|
||||
const float angle_left,
|
||||
const float angle_right,
|
||||
const float angle_up,
|
||||
const float angle_down,
|
||||
const float nearClip,
|
||||
const float farClip)
|
||||
{
|
||||
const float tan_angle_left = tanf(angle_left);
|
||||
const float tan_angle_right = tanf(angle_right);
|
||||
const float tan_angle_up = tanf(angle_up);
|
||||
const float tan_angle_down = tanf(angle_down);
|
||||
const float Xdelta = tan_angle_right - tan_angle_left;
|
||||
const float Ydelta = tan_angle_up - tan_angle_down;
|
||||
|
||||
mat[0][0] = 2 / Xdelta;
|
||||
mat[1][1] = 2 / Ydelta;
|
||||
mat[2][0] = (tan_angle_right + tan_angle_left) / Xdelta;
|
||||
mat[2][1] = (tan_angle_up + tan_angle_down) / Ydelta;
|
||||
mat[2][2] = -(farClip + nearClip) / (farClip - nearClip);
|
||||
mat[2][3] = -1;
|
||||
mat[3][2] = -(farClip * (nearClip + nearClip)) / (farClip - nearClip);
|
||||
|
||||
mat[0][1] = mat[0][2] = mat[0][3] = mat[1][0] = mat[1][2] = mat[1][3] = mat[3][0] = mat[3][1] =
|
||||
mat[3][3] = 0.0f;
|
||||
}
|
||||
|
||||
/* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
|
||||
* (used to jitter the view) */
|
||||
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
|
||||
|
@@ -7695,6 +7695,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
|
||||
wm->undo_stack = NULL;
|
||||
|
||||
wm->message_bus = NULL;
|
||||
wm->xr_context = NULL;
|
||||
|
||||
BLI_listbase_clear(&wm->jobs);
|
||||
BLI_listbase_clear(&wm->drags);
|
||||
|
@@ -149,6 +149,11 @@ void DRW_opengl_context_destroy(void);
|
||||
void DRW_opengl_context_enable(void);
|
||||
void DRW_opengl_context_disable(void);
|
||||
|
||||
/* Not nice to expose these. Code to render offscreen viewports can save expensive context switches
|
||||
* by using this directly however. */
|
||||
void *DRW_opengl_context_get(void);
|
||||
void *DRW_gpu_context_get(void);
|
||||
|
||||
/* For garbage collection */
|
||||
void DRW_cache_free_old_batches(struct Main *bmain);
|
||||
|
||||
|
@@ -3004,6 +3004,16 @@ void DRW_opengl_context_disable(void)
|
||||
DRW_opengl_context_disable_ex(true);
|
||||
}
|
||||
|
||||
void *DRW_opengl_context_get(void)
|
||||
{
|
||||
return DST.gl_context;
|
||||
}
|
||||
|
||||
void *DRW_gpu_context_get(void)
|
||||
{
|
||||
return DST.gpu_context;
|
||||
}
|
||||
|
||||
void DRW_opengl_render_context_enable(void *re_gl_context)
|
||||
{
|
||||
/* If thread is main you should use DRW_opengl_context_enable(). */
|
||||
|
@@ -575,6 +575,24 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
|
||||
const bool do_color_management,
|
||||
struct GPUOffScreen *ofs,
|
||||
struct GPUViewport *viewport);
|
||||
void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct View3DShading *shading_override,
|
||||
int drawtype,
|
||||
int winx,
|
||||
int winy,
|
||||
unsigned int draw_flags,
|
||||
float viewmat[4][4],
|
||||
float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
float lens,
|
||||
bool do_sky,
|
||||
bool is_persp,
|
||||
const char *viewname,
|
||||
const bool do_color_management,
|
||||
struct GPUOffScreen *ofs,
|
||||
struct GPUViewport *viewport);
|
||||
void ED_view3d_draw_setup_view(struct wmWindow *win,
|
||||
struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
|
@@ -1673,6 +1673,86 @@ void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
|
||||
G.f &= ~G_FLAG_RENDER_VIEWPORT;
|
||||
}
|
||||
|
||||
void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
View3DShading *shading_override,
|
||||
int drawtype,
|
||||
int winx,
|
||||
int winy,
|
||||
uint draw_flags,
|
||||
float viewmat[4][4],
|
||||
float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
float lens,
|
||||
bool do_sky,
|
||||
bool is_persp,
|
||||
const char *viewname,
|
||||
const bool do_color_management,
|
||||
GPUOffScreen *ofs,
|
||||
GPUViewport *viewport)
|
||||
{
|
||||
View3D v3d = {NULL};
|
||||
ARegion ar = {NULL};
|
||||
RegionView3D rv3d = {{{0}}};
|
||||
|
||||
/* connect data */
|
||||
v3d.regionbase.first = v3d.regionbase.last = &ar;
|
||||
ar.regiondata = &rv3d;
|
||||
ar.regiontype = RGN_TYPE_WINDOW;
|
||||
|
||||
View3DShading *source_shading_settings = &scene->display.shading;
|
||||
if (draw_flags & V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS && shading_override != NULL) {
|
||||
source_shading_settings = shading_override;
|
||||
}
|
||||
memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
|
||||
v3d.shading.type = drawtype;
|
||||
|
||||
if (drawtype == OB_MATERIAL) {
|
||||
v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
|
||||
}
|
||||
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
|
||||
v3d.flag2 |= V3D_SHOW_ANNOTATION;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
|
||||
v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
|
||||
v3d.grid = 1.0f;
|
||||
v3d.gridlines = 16;
|
||||
v3d.gridsubdiv = 10;
|
||||
|
||||
/* Show grid, disable other overlays (set all available _HIDE_ flags). */
|
||||
v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
|
||||
V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
|
||||
V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
|
||||
v3d.flag |= V3D_HIDE_HELPLINES;
|
||||
}
|
||||
else {
|
||||
v3d.flag2 = V3D_HIDE_OVERLAYS;
|
||||
}
|
||||
|
||||
rv3d.persp = RV3D_PERSP;
|
||||
v3d.clip_start = clip_start;
|
||||
v3d.clip_end = clip_end;
|
||||
v3d.lens = lens;
|
||||
|
||||
ED_view3d_draw_offscreen(depsgraph,
|
||||
scene,
|
||||
drawtype,
|
||||
&v3d,
|
||||
&ar,
|
||||
winx,
|
||||
winy,
|
||||
viewmat,
|
||||
winmat,
|
||||
do_sky,
|
||||
is_persp,
|
||||
viewname,
|
||||
do_color_management,
|
||||
ofs,
|
||||
viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility func for ED_view3d_draw_offscreen
|
||||
*
|
||||
@@ -1866,6 +1946,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
|
||||
v3d.flag2 |= V3D_SHOW_ANNOTATION;
|
||||
}
|
||||
if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
|
||||
v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
|
||||
}
|
||||
|
||||
v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD;
|
||||
|
||||
|
@@ -185,6 +185,7 @@ typedef enum eGPUBuiltinShader {
|
||||
GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR,
|
||||
/* basic image drawing */
|
||||
GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB,
|
||||
GPU_SHADER_2D_IMAGE_RECT_LINEAR_TO_SRGB,
|
||||
GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR,
|
||||
GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR,
|
||||
/**
|
||||
|
@@ -93,6 +93,7 @@ GPUViewport *GPU_viewport_create(void);
|
||||
void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect);
|
||||
void GPU_viewport_unbind(GPUViewport *viewport);
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect);
|
||||
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, const rcti *rect, bool to_srgb);
|
||||
void GPU_viewport_free(GPUViewport *viewport);
|
||||
|
||||
GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs);
|
||||
|
@@ -1015,6 +1015,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
|
||||
.vert = datatoc_gpu_shader_2D_image_vert_glsl,
|
||||
.frag = datatoc_gpu_shader_image_linear_frag_glsl,
|
||||
},
|
||||
[GPU_SHADER_2D_IMAGE_RECT_LINEAR_TO_SRGB] =
|
||||
{
|
||||
.vert = datatoc_gpu_shader_2D_image_rect_vert_glsl,
|
||||
.frag = datatoc_gpu_shader_image_linear_frag_glsl,
|
||||
},
|
||||
[GPU_SHADER_2D_IMAGE] =
|
||||
{
|
||||
.vert = datatoc_gpu_shader_2D_image_vert_glsl,
|
||||
|
@@ -505,7 +505,7 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, const rcti *rect, bool to_srgb)
|
||||
{
|
||||
DefaultFramebufferList *dfbl = viewport->fbl;
|
||||
|
||||
@@ -532,7 +532,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
float y1 = rect->ymin;
|
||||
float y2 = rect->ymin + h;
|
||||
|
||||
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
|
||||
GPUShader *shader = GPU_shader_get_builtin_shader(
|
||||
to_srgb ? GPU_SHADER_2D_IMAGE_RECT_LINEAR_TO_SRGB : GPU_SHADER_2D_IMAGE_RECT_COLOR);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_texture_bind(color, 0);
|
||||
@@ -550,6 +551,11 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
GPU_texture_unbind(color);
|
||||
}
|
||||
|
||||
void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
|
||||
{
|
||||
GPU_viewport_draw_to_screen_ex(viewport, rect, false);
|
||||
}
|
||||
|
||||
void GPU_viewport_unbind(GPUViewport *UNUSED(viewport))
|
||||
{
|
||||
GPU_framebuffer_restore();
|
||||
|
@@ -585,6 +585,7 @@ enum {
|
||||
V3D_OFSDRAW_NONE = (0),
|
||||
V3D_OFSDRAW_SHOW_ANNOTATION = (1 << 0),
|
||||
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS = (1 << 1),
|
||||
V3D_OFSDRAW_SHOW_GRIDFLOOR = (1 << 2),
|
||||
};
|
||||
|
||||
#define RV3D_CAMZOOM_MIN -30
|
||||
|
@@ -42,6 +42,7 @@ struct wmKeyMap;
|
||||
struct wmMsgBus;
|
||||
struct wmOperator;
|
||||
struct wmOperatorType;
|
||||
struct GHOST_XrContext;
|
||||
|
||||
/* forwards */
|
||||
struct PointerRNA;
|
||||
@@ -180,6 +181,9 @@ typedef struct wmWindowManager {
|
||||
|
||||
struct wmMsgBus *message_bus;
|
||||
|
||||
//#ifdef WITH_OPENXR
|
||||
void *xr_context; /* GHOST_XrContextHandle */
|
||||
//#endif
|
||||
} wmWindowManager;
|
||||
|
||||
/* wmWindowManager.initialized */
|
||||
|
@@ -309,6 +309,10 @@ if(WITH_OPENSUBDIV)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
add_definitions(-DWITH_OPENXR)
|
||||
endif()
|
||||
|
||||
add_definitions(${GL_DEFINITIONS})
|
||||
|
||||
blender_add_lib(bf_python "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -59,6 +59,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
|
||||
{(char *)"openmp", NULL},
|
||||
{(char *)"openvdb", NULL},
|
||||
{(char *)"alembic", NULL},
|
||||
{(char *)"openxr", NULL},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
@@ -268,6 +269,12 @@ static PyObject *make_builtopts_info(void)
|
||||
SetObjIncref(Py_False);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENXR
|
||||
SetObjIncref(Py_True);
|
||||
#else
|
||||
SetObjIncref(Py_False);
|
||||
#endif
|
||||
|
||||
#undef SetObjIncref
|
||||
|
||||
return builtopts_info;
|
||||
|
@@ -72,6 +72,7 @@ set(SRC
|
||||
intern/wm_splash_screen.c
|
||||
intern/wm_stereo.c
|
||||
intern/wm_subwindow.c
|
||||
intern/wm_surface.c
|
||||
intern/wm_toolsystem.c
|
||||
intern/wm_tooltip.c
|
||||
intern/wm_uilist_type.c
|
||||
@@ -98,6 +99,7 @@ set(SRC
|
||||
wm_event_system.h
|
||||
wm_event_types.h
|
||||
wm_files.h
|
||||
wm_surface.h
|
||||
wm_window.h
|
||||
gizmo/WM_gizmo_api.h
|
||||
gizmo/WM_gizmo_types.h
|
||||
@@ -175,4 +177,20 @@ if(WITH_COMPOSITOR)
|
||||
add_definitions(-DWITH_COMPOSITOR)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
add_definitions(-DWITH_OPENXR)
|
||||
|
||||
list(APPEND INC
|
||||
../../../intern/vamr
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
intern/wm_xr.c
|
||||
)
|
||||
|
||||
list(APPEND LIB
|
||||
bf_intern_vamr
|
||||
)
|
||||
endif()
|
||||
|
||||
blender_add_lib_nolist(bf_windowmanager "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
@@ -152,6 +152,10 @@ void *WM_opengl_context_create(void);
|
||||
void WM_opengl_context_dispose(void *context);
|
||||
void WM_opengl_context_activate(void *context);
|
||||
void WM_opengl_context_release(void *context);
|
||||
#ifdef WIN32
|
||||
void *WM_directx_context_create(void);
|
||||
void WM_directx_context_dispose(void *context);
|
||||
#endif
|
||||
|
||||
/* defines for 'type' WM_window_open_temp */
|
||||
enum {
|
||||
|
@@ -374,6 +374,10 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
|
||||
WM_msgbus_destroy(wm->message_bus);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENXR
|
||||
wm_xr_context_destroy(wm);
|
||||
#endif
|
||||
|
||||
BLI_freelistN(&wm->paintcursors);
|
||||
|
||||
WM_drag_free_list(&wm->drags);
|
||||
|
@@ -72,6 +72,7 @@
|
||||
#include "wm_draw.h"
|
||||
#include "wm_window.h"
|
||||
#include "wm_event_system.h"
|
||||
#include "wm_surface.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "BKE_subsurf.h"
|
||||
@@ -315,7 +316,7 @@ static void wm_draw_region_buffer_free(ARegion *ar)
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_draw_offscreen_texture_parameters(GPUOffScreen *offscreen)
|
||||
void wm_draw_offscreen_texture_parameters(GPUOffScreen *offscreen)
|
||||
{
|
||||
/* Setup offscreen color texture for drawing. */
|
||||
GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
|
||||
@@ -747,6 +748,39 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
|
||||
}
|
||||
}
|
||||
|
||||
void wm_draw_upside_down(int sizex, int sizey, bool to_srgb)
|
||||
{
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
|
||||
immBindBuiltinProgram(to_srgb ? GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB : GPU_SHADER_2D_IMAGE);
|
||||
|
||||
/* wmOrtho for the screen has this same offset */
|
||||
const float halfx = GLA_PIXEL_OFS / sizex;
|
||||
const float halfy = GLA_PIXEL_OFS / sizex;
|
||||
|
||||
immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
|
||||
|
||||
immBegin(GPU_PRIM_TRI_FAN, 4);
|
||||
|
||||
immAttr2f(texcoord, halfx, 1.0f + halfy);
|
||||
immVertex2f(pos, 0.0f, 0.0f);
|
||||
|
||||
immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
|
||||
immVertex2f(pos, sizex, 0.0f);
|
||||
|
||||
immAttr2f(texcoord, 1.0f + halfx, halfy);
|
||||
immVertex2f(pos, sizex, sizey);
|
||||
|
||||
immAttr2f(texcoord, halfx, halfy);
|
||||
immVertex2f(pos, 0.0f, sizey);
|
||||
|
||||
immEnd();
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
static void wm_draw_window(bContext *C, wmWindow *win)
|
||||
{
|
||||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
@@ -817,6 +851,20 @@ static void wm_draw_window(bContext *C, wmWindow *win)
|
||||
screen->do_draw = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw offscreen contexts not bound to a specific window.
|
||||
*/
|
||||
static void wm_draw_surface(bContext *C, wmSurface *surface)
|
||||
{
|
||||
wm_window_clear_drawable(CTX_wm_manager(C));
|
||||
wm_surface_make_drawable(surface);
|
||||
|
||||
surface->draw(C);
|
||||
|
||||
/* Avoid interference with window drawable */
|
||||
wm_surface_clear_drawable();
|
||||
}
|
||||
|
||||
/****************** main update call **********************/
|
||||
|
||||
/* quick test to prevent changing window drawable */
|
||||
@@ -944,6 +992,9 @@ void wm_draw_update(bContext *C)
|
||||
CTX_wm_window_set(C, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw non-windows (surfaces) */
|
||||
wm_surfaces_iter(C, wm_draw_surface);
|
||||
}
|
||||
|
||||
void wm_draw_region_clear(wmWindow *win, ARegion *UNUSED(ar))
|
||||
|
@@ -99,6 +99,7 @@
|
||||
#include "wm_event_system.h"
|
||||
#include "wm.h"
|
||||
#include "wm_files.h"
|
||||
#include "wm_surface.h"
|
||||
#include "wm_window.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
@@ -526,6 +527,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
|
||||
BKE_keyconfig_pref_type_free();
|
||||
|
||||
wm_operatortype_free();
|
||||
wm_surfaces_free();
|
||||
wm_dropbox_free();
|
||||
WM_menutype_free();
|
||||
WM_uilisttype_free();
|
||||
|
@@ -3325,6 +3325,39 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef WITH_OPENXR
|
||||
static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
/* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
|
||||
if (wm_xr_context_ensure(C, wm) == false) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wm_xr_session_toggle(C, wm->xr_context);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void WM_OT_xr_session_toggle(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Toggle VR Session";
|
||||
ot->idname = "WM_OT_xr_session_toggle";
|
||||
ot->description =
|
||||
"Attempt to open a view for use with virtual reality headsets, or close it if already "
|
||||
"opened";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = wm_xr_session_toggle_exec;
|
||||
|
||||
/* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
|
||||
* UI instead. Not meant as a permanent solution. */
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
#endif /* WITH_OPENXR */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operator Registration & Keymaps
|
||||
* \{ */
|
||||
@@ -3366,6 +3399,9 @@ void wm_operatortypes_register(void)
|
||||
WM_operatortype_append(WM_OT_call_panel);
|
||||
WM_operatortype_append(WM_OT_radial_control);
|
||||
WM_operatortype_append(WM_OT_stereo3d_set);
|
||||
#ifdef WITH_OPENXR
|
||||
WM_operatortype_append(WM_OT_xr_session_toggle);
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
WM_operatortype_append(WM_OT_console_toggle);
|
||||
#endif
|
||||
|
118
source/blender/windowmanager/intern/wm_surface.c
Normal file
118
source/blender/windowmanager/intern/wm_surface.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_threads.h"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GPU_batch_presets.h"
|
||||
#include "GPU_framebuffer.h"
|
||||
#include "GPU_immediate.h"
|
||||
#include "GPU_context.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
#include "WM_api.h"
|
||||
#include "wm.h"
|
||||
|
||||
#include "wm_surface.h"
|
||||
|
||||
static ListBase global_surface_list = {NULL, NULL};
|
||||
static wmSurface *g_drawable = NULL;
|
||||
|
||||
void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *))
|
||||
{
|
||||
for (wmSurface *surf = global_surface_list.first; surf; surf = surf->next) {
|
||||
cb(C, surf);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_clear_drawable(void)
|
||||
{
|
||||
if (g_drawable) {
|
||||
BLF_batch_reset();
|
||||
gpu_batch_presets_reset();
|
||||
immDeactivate();
|
||||
|
||||
g_drawable = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_set_drawable(wmSurface *surface, bool activate)
|
||||
{
|
||||
BLI_assert(ELEM(g_drawable, NULL, surface));
|
||||
|
||||
g_drawable = surface;
|
||||
if (activate) {
|
||||
GHOST_ActivateOpenGLContext(surface->ghost_ctx);
|
||||
}
|
||||
|
||||
GPU_context_active_set(surface->gpu_ctx);
|
||||
immActivate();
|
||||
}
|
||||
|
||||
void wm_surface_make_drawable(wmSurface *surface)
|
||||
{
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
|
||||
if (surface != g_drawable) {
|
||||
wm_surface_clear_drawable();
|
||||
wm_surface_set_drawable(surface, true);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_reset_drawable(void)
|
||||
{
|
||||
BLI_assert(BLI_thread_is_main());
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
|
||||
if (g_drawable) {
|
||||
wm_surface_clear_drawable();
|
||||
wm_surface_set_drawable(g_drawable, true);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_surface_add(wmSurface *surface)
|
||||
{
|
||||
BLI_addtail(&global_surface_list, surface);
|
||||
}
|
||||
|
||||
void wm_surface_remove(wmSurface *surface)
|
||||
{
|
||||
BLI_remlink(&global_surface_list, surface);
|
||||
surface->free_data(surface);
|
||||
MEM_freeN(surface);
|
||||
}
|
||||
|
||||
void wm_surfaces_free(void)
|
||||
{
|
||||
for (wmSurface *surf = global_surface_list.first, *surf_next; surf; surf = surf_next) {
|
||||
surf_next = surf->next;
|
||||
wm_surface_remove(surf);
|
||||
}
|
||||
|
||||
BLI_assert(BLI_listbase_is_empty(&global_surface_list));
|
||||
}
|
@@ -57,6 +57,11 @@
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
/* TODO Call through wm_xr.c */
|
||||
#ifdef WITH_OPENXR
|
||||
# include "VAMR_capi.h"
|
||||
#endif
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
#include "wm.h"
|
||||
@@ -1612,6 +1617,9 @@ void wm_window_process_events(const bContext *C)
|
||||
GHOST_DispatchEvents(g_system);
|
||||
}
|
||||
hasevent |= wm_window_timer(C);
|
||||
#ifdef WITH_OPENXR
|
||||
hasevent |= VAMR_EventsHandle(CTX_wm_manager(C)->xr_context);
|
||||
#endif
|
||||
|
||||
/* no event, we sleep 5 milliseconds */
|
||||
if (hasevent == 0) {
|
||||
@@ -1932,6 +1940,9 @@ void wm_window_raise(wmWindow *win)
|
||||
/** \name Window Buffers
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \brief Push rendered buffer to the screen.
|
||||
*/
|
||||
void wm_window_swap_buffers(wmWindow *win)
|
||||
{
|
||||
GHOST_SwapWindowBuffers(win->ghostwin);
|
||||
@@ -2433,3 +2444,24 @@ void WM_opengl_context_release(void *context)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef WIN32
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Direct DirectX Context Management
|
||||
* \{ */
|
||||
|
||||
void *WM_directx_context_create(void)
|
||||
{
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
return GHOST_CreateDirectXContext(g_system);
|
||||
}
|
||||
|
||||
void WM_directx_context_dispose(void *context)
|
||||
{
|
||||
BLI_assert(GPU_framebuffer_active_get() == NULL);
|
||||
GHOST_DisposeDirectXContext(g_system, context);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#endif
|
||||
|
518
source/blender/windowmanager/intern/wm_xr.c
Normal file
518
source/blender/windowmanager/intern/wm_xr.c
Normal file
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name Window-Manager XR API
|
||||
*
|
||||
* Implements Blender specific functionality for the VAMR API.
|
||||
*/
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "DRW_engine.h"
|
||||
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "GPU_context.h"
|
||||
#include "GPU_draw.h"
|
||||
#include "GPU_matrix.h"
|
||||
#include "GPU_viewport.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "wm.h"
|
||||
#include "wm_surface.h"
|
||||
#include "wm_window.h"
|
||||
|
||||
#include "VAMR_capi.h"
|
||||
|
||||
static wmSurface *g_xr_surface = NULL;
|
||||
|
||||
typedef struct {
|
||||
VAMR_GraphicsBindingType gpu_binding_type;
|
||||
GPUOffScreen *offscreen;
|
||||
GPUViewport *viewport;
|
||||
GPUFrameBuffer *fbo;
|
||||
GPUTexture *fbo_tex;
|
||||
bool viewport_bound;
|
||||
|
||||
GHOST_ContextHandle secondary_ghost_ctx;
|
||||
} wmXrSurfaceData;
|
||||
|
||||
typedef struct {
|
||||
wmWindowManager *wm;
|
||||
bContext *evil_C;
|
||||
} wmXrErrorHandlerData;
|
||||
|
||||
void wm_xr_draw_view(const VAMR_DrawViewInfo *, void *);
|
||||
void *wm_xr_session_gpu_binding_context_create(VAMR_GraphicsBindingType);
|
||||
void wm_xr_session_gpu_binding_context_destroy(VAMR_GraphicsBindingType, void *);
|
||||
wmSurface *wm_xr_session_surface_create(wmWindowManager *, unsigned int);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-Context
|
||||
*
|
||||
* All XR functionality is accessed through a #VAMR_Context handle.
|
||||
* The lifetime of this context also determines the lifetime of the OpenXR instance, which is the
|
||||
* representation of the OpenXR runtime connection within the application.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void wm_xr_error_handler(const VAMR_Error *error)
|
||||
{
|
||||
wmXrErrorHandlerData *handler_data = error->customdata;
|
||||
wmWindowManager *wm = handler_data->wm;
|
||||
|
||||
BKE_reports_clear(&wm->reports);
|
||||
WM_report(RPT_ERROR, error->user_message);
|
||||
WM_report_banner_show();
|
||||
UI_popup_menu_reports(handler_data->evil_C, &wm->reports);
|
||||
|
||||
if (wm->xr_context) {
|
||||
/* Just play safe and destroy the entire context. */
|
||||
VAMR_ContextDestroy(wm->xr_context);
|
||||
wm->xr_context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool wm_xr_context_ensure(bContext *C, wmWindowManager *wm)
|
||||
{
|
||||
if (wm->xr_context) {
|
||||
return true;
|
||||
}
|
||||
static wmXrErrorHandlerData error_customdata;
|
||||
|
||||
/* Set up error handling */
|
||||
error_customdata.wm = wm;
|
||||
error_customdata.evil_C = C;
|
||||
VAMR_ErrorHandler(wm_xr_error_handler, &error_customdata);
|
||||
|
||||
{
|
||||
const VAMR_GraphicsBindingType gpu_bindings_candidates[] = {
|
||||
VAMR_GraphicsBindingTypeOpenGL,
|
||||
#ifdef WIN32
|
||||
VAMR_GraphicsBindingTypeD3D11,
|
||||
#endif
|
||||
};
|
||||
VAMR_ContextCreateInfo create_info = {
|
||||
.gpu_binding_candidates = gpu_bindings_candidates,
|
||||
.gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates)};
|
||||
|
||||
if (G.debug & G_DEBUG_XR) {
|
||||
create_info.context_flag |= VAMR_ContextDebug;
|
||||
}
|
||||
if (G.debug & G_DEBUG_XR_TIME) {
|
||||
create_info.context_flag |= VAMR_ContextDebugTime;
|
||||
}
|
||||
|
||||
if (!(wm->xr_context = VAMR_ContextCreate(&create_info))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set up context callbacks */
|
||||
VAMR_GraphicsContextBindFuncs(wm->xr_context,
|
||||
wm_xr_session_gpu_binding_context_create,
|
||||
wm_xr_session_gpu_binding_context_destroy);
|
||||
VAMR_DrawViewFunc(wm->xr_context, wm_xr_draw_view);
|
||||
}
|
||||
BLI_assert(wm->xr_context != NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wm_xr_context_destroy(wmWindowManager *wm)
|
||||
{
|
||||
if (wm->xr_context != NULL) {
|
||||
VAMR_ContextDestroy(wm->xr_context);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* XR-Context */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-Session
|
||||
*
|
||||
* \{ */
|
||||
|
||||
void *wm_xr_session_gpu_binding_context_create(VAMR_GraphicsBindingType graphics_binding)
|
||||
{
|
||||
wmSurface *surface = wm_xr_session_surface_create(G_MAIN->wm.first, graphics_binding);
|
||||
wmXrSurfaceData *data = surface->customdata;
|
||||
|
||||
wm_surface_add(surface);
|
||||
|
||||
return data->secondary_ghost_ctx ? data->secondary_ghost_ctx : surface->ghost_ctx;
|
||||
}
|
||||
|
||||
void wm_xr_session_gpu_binding_context_destroy(VAMR_GraphicsBindingType UNUSED(graphics_lib),
|
||||
void *UNUSED(context))
|
||||
{
|
||||
if (g_xr_surface) { /* Might have been freed already */
|
||||
wm_surface_remove(g_xr_surface);
|
||||
}
|
||||
|
||||
wm_window_reset_drawable();
|
||||
}
|
||||
|
||||
static void wm_xr_session_begin_info_create(const Scene *scene, VAMR_SessionBeginInfo *begin_info)
|
||||
{
|
||||
if (scene->camera) {
|
||||
copy_v3_v3(begin_info->base_pose.position, scene->camera->loc);
|
||||
if (ELEM(scene->camera->rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) {
|
||||
axis_angle_to_quat(
|
||||
begin_info->base_pose.orientation_quat, scene->camera->rotAxis, scene->camera->rotAngle);
|
||||
}
|
||||
else if (scene->camera->rotmode == ROT_MODE_QUAT) {
|
||||
copy_v4_v4(begin_info->base_pose.orientation_quat, scene->camera->quat);
|
||||
}
|
||||
else {
|
||||
eul_to_quat(begin_info->base_pose.orientation_quat, scene->camera->rot);
|
||||
}
|
||||
}
|
||||
else {
|
||||
copy_v3_fl(begin_info->base_pose.position, 0.0f);
|
||||
unit_qt(begin_info->base_pose.orientation_quat);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_xr_session_toggle(bContext *C, void *xr_context_ptr)
|
||||
{
|
||||
VAMR_ContextHandle xr_context = xr_context_ptr;
|
||||
|
||||
if (xr_context && VAMR_SessionIsRunning(xr_context)) {
|
||||
VAMR_SessionEnd(xr_context);
|
||||
}
|
||||
else {
|
||||
VAMR_SessionBeginInfo begin_info;
|
||||
|
||||
wm_xr_session_begin_info_create(CTX_data_scene(C), &begin_info);
|
||||
|
||||
VAMR_SessionStart(xr_context, &begin_info);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */ /* XR-Session */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR-Session Surface
|
||||
*
|
||||
* A wmSurface is used to manage drawing of the VR viewport. It's created and destroyed with the
|
||||
* session.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
static void wm_xr_surface_viewport_bind(wmXrSurfaceData *surface_data, const rcti *rect)
|
||||
{
|
||||
if (surface_data->viewport_bound == false) {
|
||||
GPU_viewport_bind(surface_data->viewport, rect);
|
||||
}
|
||||
surface_data->viewport_bound = true;
|
||||
}
|
||||
static void wm_xr_surface_viewport_unbind(wmXrSurfaceData *surface_data)
|
||||
{
|
||||
if (surface_data->viewport_bound) {
|
||||
GPU_viewport_unbind(surface_data->viewport);
|
||||
}
|
||||
surface_data->viewport_bound = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Call Ghost-XR to draw a frame
|
||||
*
|
||||
* Draw callback for the XR-session surface. It's expected to be called on each main loop iteration
|
||||
* and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view,
|
||||
* #wm_xr_draw_view() will be called through Ghost-XR (see VAMR_DrawViewFunc()).
|
||||
*/
|
||||
static void wm_xr_session_surface_draw(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
|
||||
|
||||
if (!VAMR_SessionIsRunning(wm->xr_context)) {
|
||||
return;
|
||||
}
|
||||
VAMR_SessionDrawViews(wm->xr_context, C);
|
||||
if (surface_data->viewport) {
|
||||
/* Still bound from view drawing. */
|
||||
wm_xr_surface_viewport_unbind(surface_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_session_free_data(wmSurface *surface)
|
||||
{
|
||||
wmXrSurfaceData *data = surface->customdata;
|
||||
|
||||
if (data->secondary_ghost_ctx) {
|
||||
#ifdef WIN32
|
||||
if (data->gpu_binding_type == VAMR_GraphicsBindingTypeD3D11) {
|
||||
WM_directx_context_dispose(data->secondary_ghost_ctx);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
GPU_context_active_set(surface->gpu_ctx);
|
||||
DRW_opengl_context_enable_ex(false);
|
||||
if (data->viewport) {
|
||||
GPU_viewport_clear_from_offscreen(data->viewport);
|
||||
GPU_viewport_free(data->viewport);
|
||||
}
|
||||
if (data->offscreen) {
|
||||
GPU_offscreen_free(data->offscreen);
|
||||
}
|
||||
if (data->fbo) {
|
||||
GPU_framebuffer_free(data->fbo);
|
||||
}
|
||||
if (data->fbo_tex) {
|
||||
GPU_texture_free(data->fbo_tex);
|
||||
}
|
||||
DRW_opengl_context_disable_ex(false);
|
||||
|
||||
MEM_freeN(surface->customdata);
|
||||
|
||||
g_xr_surface = NULL;
|
||||
}
|
||||
|
||||
static bool wm_xr_session_surface_offscreen_ensure(const VAMR_DrawViewInfo *draw_view)
|
||||
{
|
||||
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
|
||||
char err_out[256] = "unknown";
|
||||
bool failure = false;
|
||||
|
||||
if (surface_data->offscreen &&
|
||||
(GPU_offscreen_width(surface_data->offscreen) == draw_view->width) &&
|
||||
(GPU_offscreen_height(surface_data->offscreen) == draw_view->height)) {
|
||||
BLI_assert(surface_data->viewport);
|
||||
return true;
|
||||
}
|
||||
|
||||
DRW_opengl_context_enable();
|
||||
if (surface_data->offscreen) {
|
||||
GPU_viewport_clear_from_offscreen(surface_data->viewport);
|
||||
GPU_viewport_free(surface_data->viewport);
|
||||
GPU_offscreen_free(surface_data->offscreen);
|
||||
}
|
||||
|
||||
if (!(surface_data->offscreen = GPU_offscreen_create(
|
||||
draw_view->width, draw_view->height, 0, true, false, err_out))) {
|
||||
failure = true;
|
||||
}
|
||||
if ((failure == false) &&
|
||||
!(surface_data->viewport = GPU_viewport_create_from_offscreen(surface_data->offscreen))) {
|
||||
GPU_offscreen_free(surface_data->offscreen);
|
||||
failure = true;
|
||||
}
|
||||
|
||||
surface_data->fbo = GPU_framebuffer_create();
|
||||
surface_data->fbo_tex = GPU_texture_create_2d(
|
||||
draw_view->width, draw_view->height, GPU_RGBA8, NULL, NULL);
|
||||
GPU_framebuffer_ensure_config(
|
||||
&surface_data->fbo, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(surface_data->fbo_tex)});
|
||||
|
||||
DRW_opengl_context_disable();
|
||||
|
||||
if (failure) {
|
||||
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wmSurface *wm_xr_session_surface_create(wmWindowManager *UNUSED(wm), unsigned int gpu_binding_type)
|
||||
{
|
||||
if (g_xr_surface) {
|
||||
BLI_assert(false);
|
||||
return g_xr_surface;
|
||||
}
|
||||
|
||||
wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
|
||||
wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData");
|
||||
|
||||
#ifndef WIN32
|
||||
BLI_assert(gpu_binding_type == VAMR_GraphicsBindingTypeOpenGL);
|
||||
#endif
|
||||
|
||||
surface->draw = wm_xr_session_surface_draw;
|
||||
surface->free_data = wm_xr_session_free_data;
|
||||
|
||||
data->gpu_binding_type = gpu_binding_type;
|
||||
surface->customdata = data;
|
||||
|
||||
surface->ghost_ctx = DRW_opengl_context_get();
|
||||
DRW_opengl_context_enable();
|
||||
|
||||
switch (gpu_binding_type) {
|
||||
case VAMR_GraphicsBindingTypeOpenGL:
|
||||
break;
|
||||
#ifdef WIN32
|
||||
case VAMR_GraphicsBindingTypeD3D11:
|
||||
data->secondary_ghost_ctx = WM_directx_context_create();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
surface->gpu_ctx = DRW_gpu_context_get();
|
||||
|
||||
DRW_opengl_context_disable();
|
||||
|
||||
g_xr_surface = surface;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/** \} */ /* XR-Session Surface */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Drawing
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Proper reference space set up is not supported yet. We simply hand OpenXR the global space as
|
||||
* reference space and apply its pose onto the active camera matrix to get a basic viewing
|
||||
* experience going. If there's no active camera with stick to the world origin.
|
||||
*/
|
||||
static void wm_xr_draw_matrices_create(const Scene *scene,
|
||||
const VAMR_DrawViewInfo *draw_view,
|
||||
const float clip_start,
|
||||
const float clip_end,
|
||||
float r_view_mat[4][4],
|
||||
float r_proj_mat[4][4])
|
||||
{
|
||||
float scalemat[4][4], quat[4];
|
||||
float temp[4][4];
|
||||
|
||||
perspective_m4_fov(r_proj_mat,
|
||||
draw_view->fov.angle_left,
|
||||
draw_view->fov.angle_right,
|
||||
draw_view->fov.angle_up,
|
||||
draw_view->fov.angle_down,
|
||||
clip_start,
|
||||
clip_end);
|
||||
|
||||
scale_m4_fl(scalemat, 1.0f);
|
||||
invert_qt_qt_normalized(quat, draw_view->pose.orientation_quat);
|
||||
quat_to_mat4(temp, quat);
|
||||
translate_m4(temp,
|
||||
-draw_view->pose.position[0],
|
||||
-draw_view->pose.position[1],
|
||||
-draw_view->pose.position[2]);
|
||||
|
||||
if (scene->camera) {
|
||||
invert_m4_m4(scene->camera->imat, scene->camera->obmat);
|
||||
mul_m4_m4m4(r_view_mat, temp, scene->camera->imat);
|
||||
}
|
||||
else {
|
||||
copy_m4_m4(r_view_mat, temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Draw a viewport for a single eye.
|
||||
*
|
||||
* This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
|
||||
* callback (see VAMR_DrawViewFunc()) and executed for each view (read: eye).
|
||||
*/
|
||||
void wm_xr_draw_view(const VAMR_DrawViewInfo *draw_view, void *customdata)
|
||||
{
|
||||
bContext *C = customdata;
|
||||
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
|
||||
const float clip_start = 0.01f, clip_end = 500.0f;
|
||||
const float lens = 50.0f;
|
||||
const rcti rect = {
|
||||
.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1};
|
||||
|
||||
GPUOffScreen *offscreen;
|
||||
GPUViewport *viewport;
|
||||
View3DShading shading;
|
||||
float viewmat[4][4], winmat[4][4];
|
||||
|
||||
wm_xr_draw_matrices_create(CTX_data_scene(C), draw_view, clip_start, clip_end, viewmat, winmat);
|
||||
|
||||
if (!wm_xr_session_surface_offscreen_ensure(draw_view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
offscreen = surface_data->offscreen;
|
||||
viewport = surface_data->viewport;
|
||||
wm_xr_surface_viewport_bind(surface_data, &rect);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
BKE_screen_view3d_shading_init(&shading);
|
||||
shading.flag |= V3D_SHADING_WORLD_ORIENTATION;
|
||||
shading.flag &= ~V3D_SHADING_SPECULAR_HIGHLIGHT;
|
||||
shading.background_type = V3D_SHADING_BACKGROUND_WORLD;
|
||||
ED_view3d_draw_offscreen_simple(CTX_data_ensure_evaluated_depsgraph(C),
|
||||
CTX_data_scene(C),
|
||||
&shading,
|
||||
OB_SOLID,
|
||||
draw_view->width,
|
||||
draw_view->height,
|
||||
/* Draw floor for better orientation */
|
||||
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | V3D_OFSDRAW_SHOW_GRIDFLOOR,
|
||||
viewmat,
|
||||
winmat,
|
||||
clip_start,
|
||||
clip_end,
|
||||
lens,
|
||||
true,
|
||||
true,
|
||||
NULL,
|
||||
false,
|
||||
offscreen,
|
||||
viewport);
|
||||
|
||||
GPU_framebuffer_bind(surface_data->fbo);
|
||||
|
||||
GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
|
||||
|
||||
wm_draw_offscreen_texture_parameters(offscreen);
|
||||
|
||||
wmViewport(&rect);
|
||||
if (surface_data->secondary_ghost_ctx &&
|
||||
GHOST_isUpsideDownContext(surface_data->secondary_ghost_ctx)) {
|
||||
GPU_texture_bind(texture, 0);
|
||||
wm_draw_upside_down(draw_view->width, draw_view->height, draw_view->expects_srgb_buffer);
|
||||
GPU_texture_unbind(texture);
|
||||
}
|
||||
else {
|
||||
GPU_viewport_draw_to_screen_ex(viewport, &rect, draw_view->expects_srgb_buffer);
|
||||
}
|
||||
/* Leave viewport bound so VAMR can use its context/framebuffer, its unbound in
|
||||
* wm_xr_session_surface_draw(). */
|
||||
// GPU_viewport_unbind(viewport);
|
||||
}
|
||||
|
||||
/** \} */ /* XR Drawing */
|
@@ -98,4 +98,16 @@ void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
|
||||
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
|
||||
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
|
||||
|
||||
/* wm_draw.c */
|
||||
struct GPUOffScreen;
|
||||
void wm_draw_offscreen_texture_parameters(struct GPUOffScreen *offscreen);
|
||||
void wm_draw_upside_down(int sizex, int sizey, bool to_srgb);
|
||||
|
||||
#ifdef WITH_OPENXR
|
||||
/* wm_xr.c */
|
||||
bool wm_xr_context_ensure(bContext *C, wmWindowManager *wm);
|
||||
void wm_xr_context_destroy(wmWindowManager *wm);
|
||||
void wm_xr_session_toggle(bContext *C, void *xr_context);
|
||||
#endif
|
||||
|
||||
#endif /* __WM_H__ */
|
||||
|
57
source/blender/windowmanager/wm_surface.h
Normal file
57
source/blender/windowmanager/wm_surface.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup wm
|
||||
*
|
||||
* \name WM-Surface
|
||||
*
|
||||
* Container to manage painting in an offscreen context.
|
||||
*/
|
||||
|
||||
#ifndef __WM_SURFACE_H__
|
||||
#define __WM_SURFACE_H__
|
||||
|
||||
struct bContext;
|
||||
|
||||
typedef struct wmSurface {
|
||||
struct wmSurface *next, *prev;
|
||||
|
||||
GHOST_ContextHandle ghost_ctx;
|
||||
struct GPUContext *gpu_ctx;
|
||||
|
||||
void *customdata;
|
||||
|
||||
void (*draw)(struct bContext *);
|
||||
/** Free customdata, not the surface itself (done by wm_surface API) */
|
||||
void (*free_data)(struct wmSurface *);
|
||||
} wmSurface;
|
||||
|
||||
/* Create/Free */
|
||||
void wm_surface_add(wmSurface *surface);
|
||||
void wm_surface_remove(wmSurface *surface);
|
||||
void wm_surfaces_free(void);
|
||||
|
||||
/* Utils */
|
||||
void wm_surfaces_iter(struct bContext *C, void (*cb)(bContext *, wmSurface *));
|
||||
|
||||
/* Drawing */
|
||||
void wm_surface_make_drawable(wmSurface *surface);
|
||||
void wm_surface_clear_drawable(void);
|
||||
void wm_surface_set_drawable(wmSurface *surface, bool activate);
|
||||
void wm_surface_reset_drawable(void);
|
||||
|
||||
#endif /* __WM_SURFACE_H__ */
|
@@ -118,6 +118,10 @@ if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
add_definitions(-DWITH_OPENXR)
|
||||
endif()
|
||||
|
||||
# Setup the exe sources and buildinfo
|
||||
set(SRC
|
||||
creator.c
|
||||
@@ -838,6 +842,8 @@ elseif(WIN32)
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_debug_gpu_glitchworkaround.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_debug_log.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_factory_startup.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/blender_oculus.cmd
|
||||
${CMAKE_SOURCE_DIR}/release/windows/batch/oculus.json
|
||||
DESTINATION "."
|
||||
)
|
||||
|
||||
|
@@ -604,6 +604,10 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
|
||||
BLI_argsPrintArgDoc(ba, "--debug-gpu-shaders");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-gpu-force-workarounds");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-wm");
|
||||
# ifdef WITH_OPENXR
|
||||
BLI_argsPrintArgDoc(ba, "--debug-xr");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-xr-time");
|
||||
# endif
|
||||
BLI_argsPrintArgDoc(ba, "--debug-all");
|
||||
BLI_argsPrintArgDoc(ba, "--debug-io");
|
||||
|
||||
@@ -941,6 +945,16 @@ static const char arg_handle_debug_mode_generic_set_doc_wm[] =
|
||||
"\n\t"
|
||||
"Enable debug messages for the window manager, shows all operators in search, shows "
|
||||
"keymap errors.";
|
||||
# ifdef WITH_OPENXR
|
||||
static const char arg_handle_debug_mode_generic_set_doc_xr[] =
|
||||
"\n\t"
|
||||
"Enable debug messages for virtual reality contexts.\n"
|
||||
"\tEnables the OpenXR API validation layer, (OpenXR) debug messages and general information "
|
||||
"prints.";
|
||||
static const char arg_handle_debug_mode_generic_set_doc_xr_time[] =
|
||||
"\n\t"
|
||||
"Enable debug messages for virtual reality frame rendering times.";
|
||||
# endif
|
||||
static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
|
||||
"\n\t"
|
||||
"Enable time profiling for background jobs.";
|
||||
@@ -2081,6 +2095,16 @@ void main_args_setup(bContext *C, bArgs *ba)
|
||||
(void *)G_DEBUG_HANDLERS);
|
||||
BLI_argsAdd(
|
||||
ba, 1, NULL, "--debug-wm", CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
|
||||
# ifdef WITH_OPENXR
|
||||
BLI_argsAdd(
|
||||
ba, 1, NULL, "--debug-xr", CB_EX(arg_handle_debug_mode_generic_set, xr), (void *)G_DEBUG_XR);
|
||||
BLI_argsAdd(ba,
|
||||
1,
|
||||
NULL,
|
||||
"--debug-xr-time",
|
||||
CB_EX(arg_handle_debug_mode_generic_set, xr_time),
|
||||
(void *)G_DEBUG_XR_TIME);
|
||||
# endif
|
||||
BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
|
||||
|
||||
BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL);
|
||||
|
@@ -50,6 +50,9 @@ def _init_addon_blacklist():
|
||||
# netrender has known problems re-registering
|
||||
BLACKLIST_ADDONS.add("netrender")
|
||||
|
||||
if not bpy.app.build_options.openxr:
|
||||
BLACKLIST_ADDONS.add("viewport_vr_preview")
|
||||
|
||||
for mod in addon_utils.modules():
|
||||
if addon_utils.module_bl_info(mod)['blender'] < (2, 80, 0):
|
||||
BLACKLIST_ADDONS.add(mod.__name__)
|
||||
|
@@ -54,6 +54,9 @@ MODULE_SYS_PATHS = {
|
||||
if not bpy.app.build_options.freestyle:
|
||||
BLACKLIST.add("render_freestyle_svg")
|
||||
|
||||
if not bpy.app.build_options.openxr:
|
||||
BLACKLIST.add("viewport_vr_preview")
|
||||
|
||||
BLACKLIST_DIRS = (
|
||||
os.path.join(bpy.utils.resource_path('USER'), "scripts"),
|
||||
) + tuple(addon_utils.paths()[1:])
|
||||
|
Reference in New Issue
Block a user