Compare commits
200 Commits
filebrowse
...
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)
|
||||
|
23
GNUmakefile
23
GNUmakefile
@@ -233,19 +233,12 @@ endif
|
||||
ifneq "$(findstring ninja, $(MAKECMDGOALS))" ""
|
||||
BUILD_CMAKE_ARGS:=$(BUILD_CMAKE_ARGS) -G Ninja
|
||||
BUILD_COMMAND:=ninja
|
||||
DEPS_BUILD_COMMAND:=ninja
|
||||
else
|
||||
ifneq ("$(wildcard $(BUILD_DIR)/build.ninja)","")
|
||||
BUILD_COMMAND:=ninja
|
||||
else
|
||||
BUILD_COMMAND:=make -s
|
||||
endif
|
||||
|
||||
ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","")
|
||||
DEPS_BUILD_COMMAND:=ninja
|
||||
else
|
||||
DEPS_BUILD_COMMAND:=make -s
|
||||
endif
|
||||
endif
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -340,7 +333,7 @@ deps: .FORCE
|
||||
|
||||
@echo
|
||||
@echo Building dependencies ...
|
||||
$(DEPS_BUILD_COMMAND) -C "$(DEPS_BUILD_DIR)" -j $(NPROCS) $(DEPS_TARGET)
|
||||
$(BUILD_COMMAND) -C "$(DEPS_BUILD_DIR)" -j $(NPROCS) $(DEPS_TARGET)
|
||||
@echo
|
||||
@echo Dependencies successfully built and installed to $(DEPS_INSTALL_DIR).
|
||||
@echo
|
||||
@@ -375,7 +368,7 @@ package_archive: .FORCE
|
||||
# Tests
|
||||
#
|
||||
test: .FORCE
|
||||
python3 ./build_files/utils/make_test.py "$(BUILD_DIR)"
|
||||
cd $(BUILD_DIR) ; ctest . --output-on-failure
|
||||
|
||||
# run pep8 check check on scripts we distribute.
|
||||
test_pep8: .FORCE
|
||||
@@ -531,7 +524,17 @@ icons_geom: .FORCE
|
||||
"$(BLENDER_DIR)/release/datafiles/blender_icons_geom_update.py"
|
||||
|
||||
update: .FORCE
|
||||
python3 ./build_files/utils/make_update.py
|
||||
if [ "$(OS_NCASE)" = "darwin" ] && [ ! -d "../lib/$(OS_NCASE)" ]; then \
|
||||
svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/$(OS_NCASE) ../lib/$(OS_NCASE) ; \
|
||||
fi
|
||||
if [ -d "../lib" ]; then \
|
||||
svn cleanup ../lib/* ; \
|
||||
svn update ../lib/* ; \
|
||||
fi
|
||||
git pull --rebase
|
||||
git submodule update --init --recursive
|
||||
git submodule foreach git checkout master
|
||||
git submodule foreach git pull --rebase origin master
|
||||
|
||||
format: .FORCE
|
||||
PATH="../lib/${OS_NCASE}/llvm/bin/:$(PATH)" \
|
||||
|
@@ -58,6 +58,7 @@ else()
|
||||
endif()
|
||||
|
||||
include(cmake/zlib.cmake)
|
||||
include(cmake/blendthumb.cmake)
|
||||
include(cmake/openal.cmake)
|
||||
include(cmake/png.cmake)
|
||||
include(cmake/jpeg.cmake)
|
||||
@@ -98,6 +99,7 @@ else()
|
||||
include(cmake/pugixml.cmake)
|
||||
endif()
|
||||
include(cmake/openimagedenoise.cmake)
|
||||
include(cmake/openxr.cmake)
|
||||
|
||||
if(WITH_WEBP)
|
||||
include(cmake/webp.cmake)
|
||||
|
67
build_files/build_environment/cmake/blendthumb.cmake
Normal file
67
build_files/build_environment/cmake/blendthumb.cmake
Normal file
@@ -0,0 +1,67 @@
|
||||
# ***** 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 *****
|
||||
|
||||
if(BUILD_MODE STREQUAL Release)
|
||||
if(WIN32)
|
||||
set(THUMB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../release/windows/blendthumb)
|
||||
|
||||
ExternalProject_Add(external_zlib_32
|
||||
URL ${ZLIB_URI}
|
||||
CMAKE_GENERATOR ${GENERATOR_32}
|
||||
URL_HASH MD5=${ZLIB_HASH}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
PREFIX ${BUILD_DIR}/zlib32
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib32 ${DEFAULT_CMAKE_FLAGS}
|
||||
INSTALL_DIR ${LIBDIR}/zlib32
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_zlib_64
|
||||
URL ${ZLIB_URI}
|
||||
CMAKE_GENERATOR ${GENERATOR_64}
|
||||
URL_HASH MD5=${ZLIB_HASH}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
PREFIX ${BUILD_DIR}/zlib64
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/zlib64 ${DEFAULT_CMAKE_FLAGS}
|
||||
INSTALL_DIR ${LIBDIR}/zlib64
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_blendthumb_32
|
||||
CMAKE_GENERATOR ${GENERATOR_32}
|
||||
SOURCE_DIR ${THUMB_DIR}
|
||||
PREFIX ${BUILD_DIR}/blendthumb32
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blendThumb32 ${DEFAULT_CMAKE_FLAGS} -DZLIB_INCLUDE=${LIBDIR}/zlib32/include -DZLIB_LIBS=${LIBDIR}/zlib32/lib/zlibstatic.lib
|
||||
INSTALL_DIR ${LIBDIR}/blendthumb32
|
||||
)
|
||||
add_dependencies(
|
||||
external_blendthumb_32
|
||||
external_zlib_32
|
||||
)
|
||||
|
||||
ExternalProject_Add(external_blendthumb_64
|
||||
CMAKE_GENERATOR ${GENERATOR_64}
|
||||
SOURCE_DIR ${THUMB_DIR}
|
||||
PREFIX ${BUILD_DIR}/blendthumb64
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/blendThumb64 ${DEFAULT_CMAKE_FLAGS} -DZLIB_INCLUDE=${LIBDIR}/zlib64/include -DZLIB_LIBS=${LIBDIR}/zlib64/lib/zlibstatic.lib
|
||||
INSTALL_DIR ${LIBDIR}/blendthumb64
|
||||
)
|
||||
add_dependencies(
|
||||
external_blendthumb_64
|
||||
external_zlib_64
|
||||
)
|
||||
endif()
|
||||
endif()
|
@@ -51,6 +51,9 @@ if(BUILD_MODE STREQUAL Release)
|
||||
# tiff
|
||||
${CMAKE_COMMAND} -E copy ${LIBDIR}/tiff/lib/tiff.lib ${HARVEST_TARGET}/tiff/lib/libtiff.lib &&
|
||||
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/tiff/include/ ${HARVEST_TARGET}/tiff/include/ &&
|
||||
# BlendThumb
|
||||
${CMAKE_COMMAND} -E copy ${LIBDIR}/BlendThumb64/bin/blendthumb.dll ${HARVEST_TARGET}/ThumbHandler/lib/BlendThumb64.dll &&
|
||||
${CMAKE_COMMAND} -E copy ${LIBDIR}/BlendThumb32/bin/blendthumb.dll ${HARVEST_TARGET}/ThumbHandler/lib/BlendThumb.dll &&
|
||||
# hidapi
|
||||
${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/hidapi/ ${HARVEST_TARGET}/hidapi/ &&
|
||||
# webp, straight up copy
|
||||
@@ -171,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"
|
||||
@@ -1114,7 +1153,7 @@ run_ldconfig() {
|
||||
WARNING "--no-sudo enabled, impossible to run ldconfig for $1, you'll have to do it yourself..."
|
||||
else
|
||||
INFO "Running ldconfig for $1..."
|
||||
$SUDO sh -c "/bin/echo -e \"$_lib_path\n$_lib64_path\" > $_ldconf_path"
|
||||
$SUDO sh -c "echo -e \"$_lib_path\n$_lib64_path\" > $_ldconf_path"
|
||||
$SUDO /sbin/ldconfig # XXX OpenSuse does not include sbin in command path with sudo!!!
|
||||
fi
|
||||
PRINT ""
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -3454,7 +3602,7 @@ install_RPM() {
|
||||
$SUDO dnf -y update
|
||||
|
||||
elif [ "$RPM" = "RHEL" ]; then
|
||||
if [ "`grep '[^.]6\.' /etc/redhat-release`" ]; then
|
||||
if [ "`grep '6\.' /etc/redhat-release`" ]; then
|
||||
ERROR "Building with GCC 4.4 is not supported!"
|
||||
exit 1
|
||||
else
|
||||
@@ -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})
|
@@ -1,112 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
class Builder:
|
||||
def __init__(self, name, branch):
|
||||
self.name = name
|
||||
self.branch = branch
|
||||
|
||||
# Buildbot runs from build/ directory
|
||||
self.blender_dir = os.path.abspath(os.path.join('..', 'blender.git'))
|
||||
self.build_dir = os.path.abspath(os.path.join('..', 'build', name))
|
||||
self.install_dir = os.path.abspath(os.path.join('..', 'install', name))
|
||||
self.upload_dir = os.path.abspath(os.path.join('..', 'install'))
|
||||
|
||||
# Detect platform
|
||||
if name.startswith('mac'):
|
||||
self.platform = 'mac'
|
||||
self.command_prefix = []
|
||||
elif name.startswith('linux'):
|
||||
self.platform = 'linux'
|
||||
self.command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
|
||||
elif name.startswith('win'):
|
||||
self.platform = 'win'
|
||||
self.command_prefix = []
|
||||
else:
|
||||
raise ValueError('Unkonw platform for builder ' + self.platform)
|
||||
|
||||
# Always 64 bit now
|
||||
self.bits = 64
|
||||
|
||||
def create_builder_from_arguments():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('builder_name')
|
||||
parser.add_argument('branch', default='master', nargs='?')
|
||||
args = parser.parse_args()
|
||||
return Builder(args.builder_name, args.branch)
|
||||
|
||||
|
||||
class VersionInfo:
|
||||
def __init__(self, builder):
|
||||
# Get version information
|
||||
buildinfo_h = os.path.join(builder.build_dir, "source", "creator", "buildinfo.h")
|
||||
blender_h = os.path.join(builder.blender_dir, "source", "blender", "blenkernel", "BKE_blender_version.h")
|
||||
|
||||
version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION'))
|
||||
self.version = "%d.%d" % (version_number // 100, version_number % 100)
|
||||
self.version_char = self._parse_header_file(blender_h, 'BLENDER_VERSION_CHAR')
|
||||
self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE')
|
||||
self.version_cycle_number = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE_NUMBER')
|
||||
self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
|
||||
|
||||
if self.version_cycle == "release":
|
||||
# Final release
|
||||
self.full_version = self.version + self.version_char
|
||||
self.is_development_build = False
|
||||
elif self.version_cycle == "rc":
|
||||
# Release candidate
|
||||
version_cycle = self.version_cycle + self.version_cycle_number
|
||||
if len(self.version_char) == 0:
|
||||
self.full_version = self.version + version_cycle
|
||||
else:
|
||||
self.full_version = self.version + self.version_char + '-' + version_cycle
|
||||
self.is_development_build = False
|
||||
else:
|
||||
# Development build
|
||||
self.full_version = self.version + '-' + self.hash
|
||||
self.is_development_build = True
|
||||
|
||||
def _parse_header_file(self, filename, define):
|
||||
import re
|
||||
regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
|
||||
with open(filename, "r") as file:
|
||||
for l in file:
|
||||
match = regex.match(l)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def call(cmd, env=None, exit_on_error=True):
|
||||
print(' '.join(cmd))
|
||||
|
||||
# Flush to ensure correct order output on Windows.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
retcode = subprocess.call(cmd, env=env)
|
||||
if exit_on_error and retcode != 0:
|
||||
sys.exit(retcode)
|
||||
return retcode
|
@@ -18,80 +18,149 @@
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import buildbot_utils
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
def get_cmake_options(builder):
|
||||
config_file = "build_files/cmake/config/blender_release.cmake"
|
||||
options = ['-DCMAKE_BUILD_TYPE:STRING=Release', '-DWITH_GTESTS=ON']
|
||||
# get builder name
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write("Not enough arguments, expecting builder name\n")
|
||||
sys.exit(1)
|
||||
|
||||
if builder.platform == 'mac':
|
||||
options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
|
||||
options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')
|
||||
elif builder.platform == 'win':
|
||||
options.extend(['-G', 'Visual Studio 15 2017 Win64'])
|
||||
elif builder.platform == 'linux':
|
||||
config_file = "build_files/buildbot/config/blender_linux.cmake"
|
||||
builder = sys.argv[1]
|
||||
|
||||
options.append("-C" + os.path.join(builder.blender_dir, config_file))
|
||||
options.append("-DCMAKE_INSTALL_PREFIX=%s" % (builder.install_dir))
|
||||
# we run from build/ directory
|
||||
blender_dir = os.path.join('..', 'blender.git')
|
||||
|
||||
return options
|
||||
|
||||
def update_git(builder):
|
||||
# Do extra git fetch because not all platform/git/buildbot combinations
|
||||
# update the origin remote, causing buildinfo to detect local changes.
|
||||
os.chdir(builder.blender_dir)
|
||||
def parse_header_file(filename, define):
|
||||
import re
|
||||
regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
|
||||
with open(filename, "r") as file:
|
||||
for l in file:
|
||||
match = regex.match(l)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return None
|
||||
|
||||
print("Fetching remotes")
|
||||
command = ['git', 'fetch', '--all']
|
||||
buildbot_utils.call(builder.command_prefix + command)
|
||||
if 'cmake' in builder:
|
||||
# cmake
|
||||
|
||||
def clean_directories(builder):
|
||||
# Make sure no garbage remained from the previous run
|
||||
if os.path.isdir(builder.install_dir):
|
||||
shutil.rmtree(builder.install_dir)
|
||||
# Some fine-tuning configuration
|
||||
blender_dir = os.path.abspath(blender_dir)
|
||||
build_dir = os.path.abspath(os.path.join('..', 'build', builder))
|
||||
install_dir = os.path.abspath(os.path.join('..', 'install', builder))
|
||||
targets = ['blender']
|
||||
command_prefix = []
|
||||
|
||||
# Make sure build directory exists and enter it
|
||||
os.makedirs(builder.build_dir, exist_ok=True)
|
||||
bits = 64
|
||||
|
||||
# Remove buildinfo files to force buildbot to re-generate them.
|
||||
for buildinfo in ('buildinfo.h', 'buildinfo.h.txt', ):
|
||||
full_path = os.path.join(builder.build_dir, 'source', 'creator', buildinfo)
|
||||
if os.path.exists(full_path):
|
||||
print("Removing {}" . format(buildinfo))
|
||||
os.remove(full_path)
|
||||
# Config file to be used (relative to blender's sources root)
|
||||
cmake_config_file = "build_files/cmake/config/blender_release.cmake"
|
||||
|
||||
def cmake_configure(builder):
|
||||
# CMake configuration
|
||||
os.chdir(builder.build_dir)
|
||||
# Set build options.
|
||||
cmake_options = []
|
||||
cmake_extra_options = ['-DCMAKE_BUILD_TYPE:STRING=Release',
|
||||
'-DWITH_GTESTS=ON']
|
||||
|
||||
cmake_cache = os.path.join(builder.build_dir, 'CMakeCache.txt')
|
||||
if os.path.exists(cmake_cache):
|
||||
print("Removing CMake cache")
|
||||
os.remove(cmake_cache)
|
||||
if builder.startswith('mac'):
|
||||
# Set up OSX architecture
|
||||
if builder.endswith('x86_64_10_9_cmake'):
|
||||
cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
|
||||
cmake_extra_options.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9')
|
||||
|
||||
print("CMake configure:")
|
||||
cmake_options = get_cmake_options(builder)
|
||||
command = ['cmake', builder.blender_dir] + cmake_options
|
||||
buildbot_utils.call(builder.command_prefix + command)
|
||||
elif builder.startswith('win'):
|
||||
if builder.startswith('win64'):
|
||||
cmake_options.extend(['-G', 'Visual Studio 15 2017 Win64'])
|
||||
elif builder.startswith('win32'):
|
||||
bits = 32
|
||||
cmake_options.extend(['-G', 'Visual Studio 15 2017'])
|
||||
|
||||
def cmake_build(builder):
|
||||
# CMake build
|
||||
os.chdir(builder.build_dir)
|
||||
elif builder.startswith('linux'):
|
||||
cmake_config_file = "build_files/buildbot/config/blender_linux.cmake"
|
||||
tokens = builder.split("_")
|
||||
glibc = tokens[1]
|
||||
if glibc == 'glibc224':
|
||||
deb_name = "stretch"
|
||||
if builder.endswith('x86_64_cmake'):
|
||||
chroot_name = 'buildbot_' + deb_name + '_x86_64'
|
||||
elif builder.endswith('i686_cmake'):
|
||||
bits = 32
|
||||
chroot_name = 'buildbot_' + deb_name + '_i686'
|
||||
command_prefix = ['schroot', '-c', chroot_name, '--']
|
||||
elif glibc == 'glibc217':
|
||||
command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
|
||||
|
||||
if builder.platform == 'win':
|
||||
command = ['cmake', '--build', '.', '--target', 'install', '--config', 'Release']
|
||||
cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file))
|
||||
|
||||
# Prepare CMake options needed to configure cuda binaries compilation, 64bit only.
|
||||
if bits == 64:
|
||||
cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=ON")
|
||||
cmake_options.append("-DCUDA_64_BIT_DEVICE_CODE=ON")
|
||||
else:
|
||||
command = ['make', '-s', '-j2', 'install']
|
||||
cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=OFF")
|
||||
|
||||
print("CMake build:")
|
||||
buildbot_utils.call(builder.command_prefix + command)
|
||||
cmake_options.append("-DCMAKE_INSTALL_PREFIX=%s" % (install_dir))
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = buildbot_utils.create_builder_from_arguments()
|
||||
update_git(builder)
|
||||
clean_directories(builder)
|
||||
cmake_configure(builder)
|
||||
cmake_build(builder)
|
||||
cmake_options += cmake_extra_options
|
||||
|
||||
# Make sure no garbage remained from the previous run
|
||||
if os.path.isdir(install_dir):
|
||||
shutil.rmtree(install_dir)
|
||||
|
||||
for target in targets:
|
||||
print("Building target %s" % (target))
|
||||
# Construct build directory name based on the target
|
||||
target_build_dir = build_dir
|
||||
target_command_prefix = command_prefix[:]
|
||||
if target != 'blender':
|
||||
target_build_dir += '_' + target
|
||||
target_name = 'install'
|
||||
# Tweaking CMake options to respect the target
|
||||
target_cmake_options = cmake_options[:]
|
||||
# Do extra git fetch because not all platform/git/buildbot combinations
|
||||
# update the origin remote, causing buildinfo to detect local changes.
|
||||
os.chdir(blender_dir)
|
||||
print("Fetching remotes")
|
||||
command = ['git', 'fetch', '--all']
|
||||
print(command)
|
||||
retcode = subprocess.call(target_command_prefix + command)
|
||||
if retcode != 0:
|
||||
sys.exit(retcode)
|
||||
# Make sure build directory exists and enter it
|
||||
if not os.path.isdir(target_build_dir):
|
||||
os.mkdir(target_build_dir)
|
||||
os.chdir(target_build_dir)
|
||||
# Configure the build
|
||||
print("CMake options:")
|
||||
print(target_cmake_options)
|
||||
if os.path.exists('CMakeCache.txt'):
|
||||
print("Removing CMake cache")
|
||||
os.remove('CMakeCache.txt')
|
||||
# Remove buildinfo files to force buildbot to re-generate them.
|
||||
for buildinfo in ('buildinfo.h', 'buildinfo.h.txt', ):
|
||||
full_path = os.path.join('source', 'creator', buildinfo)
|
||||
if os.path.exists(full_path):
|
||||
print("Removing {}" . format(buildinfo))
|
||||
os.remove(full_path)
|
||||
retcode = subprocess.call(target_command_prefix + ['cmake', blender_dir] + target_cmake_options)
|
||||
if retcode != 0:
|
||||
print('Configuration FAILED!')
|
||||
sys.exit(retcode)
|
||||
|
||||
if 'win32' in builder or 'win64' in builder:
|
||||
command = ['cmake', '--build', '.', '--target', target_name, '--config', 'Release']
|
||||
else:
|
||||
command = ['make', '-s', '-j2', target_name]
|
||||
|
||||
print("Executing command:")
|
||||
print(command)
|
||||
retcode = subprocess.call(target_command_prefix + command)
|
||||
|
||||
if retcode != 0:
|
||||
sys.exit(retcode)
|
||||
|
||||
else:
|
||||
print("Unknown building system")
|
||||
sys.exit(1)
|
||||
|
@@ -22,36 +22,47 @@
|
||||
# system and zipping it into buildbot_upload.zip. This is then uploaded
|
||||
# to the master in the next buildbot step.
|
||||
|
||||
import buildbot_utils
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
def get_package_name(builder, platform=None):
|
||||
info = buildbot_utils.VersionInfo(builder)
|
||||
# get builder name
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write("Not enough arguments, expecting builder name\n")
|
||||
sys.exit(1)
|
||||
|
||||
package_name = 'blender-' + info.full_version
|
||||
if platform:
|
||||
package_name += '-' + platform
|
||||
if builder.branch != 'master' and info.is_development_build:
|
||||
package_name = builder.branch + "-" + package_name
|
||||
builder = sys.argv[1]
|
||||
# Never write branch if it is master.
|
||||
branch = sys.argv[2] if (len(sys.argv) >= 3 and sys.argv[2] != 'master') else ''
|
||||
|
||||
return package_name
|
||||
blender_dir = os.path.join('..', 'blender.git')
|
||||
build_dir = os.path.join('..', 'build', builder)
|
||||
install_dir = os.path.join('..', 'install', builder)
|
||||
buildbot_upload_zip = os.path.abspath(os.path.join(os.path.dirname(install_dir), "buildbot_upload.zip"))
|
||||
|
||||
def create_buildbot_upload_zip(builder, package_files):
|
||||
import zipfile
|
||||
upload_filename = None # Name of the archive to be uploaded
|
||||
# (this is the name of archive which will appear on the
|
||||
# download page)
|
||||
upload_filepath = None # Filepath to be uploaded to the server
|
||||
# (this folder will be packed)
|
||||
|
||||
buildbot_upload_zip = os.path.join(builder.upload_dir, "buildbot_upload.zip")
|
||||
if os.path.exists(buildbot_upload_zip):
|
||||
os.remove(buildbot_upload_zip)
|
||||
|
||||
try:
|
||||
z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED)
|
||||
for filepath, filename in package_files:
|
||||
z.write(filepath, arcname=filename)
|
||||
z.close()
|
||||
except Exception as ex:
|
||||
sys.stderr.write('Create buildbot_upload.zip failed: ' + str(ex) + '\n')
|
||||
sys.exit(1)
|
||||
def parse_header_file(filename, define):
|
||||
import re
|
||||
regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
|
||||
with open(filename, "r") as file:
|
||||
for l in file:
|
||||
match = regex.match(l)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return None
|
||||
|
||||
|
||||
# Make sure install directory always exists
|
||||
if not os.path.exists(install_dir):
|
||||
os.makedirs(install_dir)
|
||||
|
||||
|
||||
def create_tar_bz2(src, dest, package_name):
|
||||
# One extra to remove leading os.sep when cleaning root for package_root
|
||||
@@ -69,120 +80,163 @@ def create_tar_bz2(src, dest, package_name):
|
||||
package.add(entry[0], entry[1], recursive=False)
|
||||
package.close()
|
||||
|
||||
def cleanup_files(dirpath, extension):
|
||||
for f in os.listdir(dirpath):
|
||||
filepath = os.path.join(dirpath, f)
|
||||
if os.path.isfile(filepath) and f.endswith(extension):
|
||||
os.remove(filepath)
|
||||
|
||||
if builder.find('cmake') != -1:
|
||||
# CMake
|
||||
if 'win' in builder or 'mac' in builder:
|
||||
os.chdir(build_dir)
|
||||
|
||||
files = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')]
|
||||
for f in files:
|
||||
os.remove(f)
|
||||
retcode = subprocess.call(['cpack', '-G', 'ZIP'])
|
||||
result_file = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')][0]
|
||||
|
||||
# TODO(sergey): Such magic usually happens in SCon's packaging but we don't have it
|
||||
# in the CMake yet. For until then we do some magic here.
|
||||
tokens = result_file.split('-')
|
||||
blender_version = tokens[1].split('.')
|
||||
blender_full_version = '.'.join(blender_version[0:2])
|
||||
git_hash = tokens[2].split('.')[1]
|
||||
platform = builder.split('_')[0]
|
||||
if platform == 'mac':
|
||||
# Special exception for OSX
|
||||
platform = 'OSX-10.9-'
|
||||
if builder.endswith('x86_64_10_9_cmake'):
|
||||
platform += 'x86_64'
|
||||
if builder.endswith('vc2015'):
|
||||
platform += "-vc14"
|
||||
builderified_name = 'blender-{}-{}-{}'.format(blender_full_version, git_hash, platform)
|
||||
# NOTE: Blender 2.7 is already respected by blender_full_version.
|
||||
if branch != '' and branch != 'blender2.7':
|
||||
builderified_name = branch + "-" + builderified_name
|
||||
|
||||
os.rename(result_file, "{}.zip".format(builderified_name))
|
||||
# create zip file
|
||||
try:
|
||||
if os.path.exists(buildbot_upload_zip):
|
||||
os.remove(buildbot_upload_zip)
|
||||
z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED)
|
||||
z.write("{}.zip".format(builderified_name))
|
||||
z.close()
|
||||
sys.exit(retcode)
|
||||
except Exception as ex:
|
||||
sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n')
|
||||
sys.exit(1)
|
||||
|
||||
elif builder.startswith('linux_'):
|
||||
blender = os.path.join(install_dir, 'blender')
|
||||
|
||||
buildinfo_h = os.path.join(build_dir, "source", "creator", "buildinfo.h")
|
||||
blender_h = os.path.join(blender_dir, "source", "blender", "blenkernel", "BKE_blender_version.h")
|
||||
|
||||
# Get version information
|
||||
blender_version = int(parse_header_file(blender_h, 'BLENDER_VERSION'))
|
||||
blender_version = "%d.%d" % (blender_version // 100, blender_version % 100)
|
||||
blender_hash = parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
|
||||
blender_glibc = builder.split('_')[1]
|
||||
command_prefix = []
|
||||
bits = 64
|
||||
blender_arch = 'x86_64'
|
||||
|
||||
if blender_glibc == 'glibc224':
|
||||
if builder.endswith('x86_64_cmake'):
|
||||
chroot_name = 'buildbot_stretch_x86_64'
|
||||
elif builder.endswith('i686_cmake'):
|
||||
chroot_name = 'buildbot_stretch_i686'
|
||||
bits = 32
|
||||
blender_arch = 'i686'
|
||||
command_prefix = ['schroot', '-c', chroot_name, '--']
|
||||
elif blender_glibc == 'glibc217':
|
||||
command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
|
||||
|
||||
# Strip all unused symbols from the binaries
|
||||
print("Stripping binaries...")
|
||||
subprocess.call(command_prefix + ['strip', '--strip-all', blender])
|
||||
|
||||
print("Stripping python...")
|
||||
py_target = os.path.join(install_dir, blender_version)
|
||||
subprocess.call(command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';'])
|
||||
|
||||
# Copy all specific files which are too specific to be copied by
|
||||
# the CMake rules themselves
|
||||
print("Copying extra scripts and libs...")
|
||||
|
||||
extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
|
||||
mesalibs = os.path.join(extra, 'mesalibs' + str(bits) + '.tar.bz2')
|
||||
software_gl = os.path.join(blender_dir, 'release', 'bin', 'blender-softwaregl')
|
||||
icons = os.path.join(blender_dir, 'release', 'freedesktop', 'icons')
|
||||
|
||||
os.system('tar -xpf %s -C %s' % (mesalibs, install_dir))
|
||||
os.system('cp %s %s' % (software_gl, install_dir))
|
||||
os.system('cp -r %s %s' % (icons, install_dir))
|
||||
os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl')))
|
||||
|
||||
# Construct archive name
|
||||
package_name = 'blender-%s-%s-linux-%s-%s' % (blender_version,
|
||||
blender_hash,
|
||||
blender_glibc,
|
||||
blender_arch)
|
||||
# NOTE: Blender 2.7 is already respected by blender_full_version.
|
||||
if branch != '' and branch != 'blender2.7':
|
||||
package_name = branch + "-" + package_name
|
||||
|
||||
upload_filename = package_name + ".tar.bz2"
|
||||
|
||||
print("Creating .tar.bz2 archive")
|
||||
upload_filepath = install_dir + '.tar.bz2'
|
||||
create_tar_bz2(install_dir, upload_filepath, package_name)
|
||||
else:
|
||||
print("Unknown building system")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def pack_mac(builder):
|
||||
info = buildbot_utils.VersionInfo(builder)
|
||||
if upload_filepath is None:
|
||||
# clean release directory if it already exists
|
||||
release_dir = 'release'
|
||||
|
||||
os.chdir(builder.build_dir)
|
||||
cleanup_files(builder.build_dir, '.dmg')
|
||||
if os.path.exists(release_dir):
|
||||
for f in os.listdir(release_dir):
|
||||
if os.path.isfile(os.path.join(release_dir, f)):
|
||||
os.remove(os.path.join(release_dir, f))
|
||||
|
||||
package_name = get_package_name(builder, 'macOS')
|
||||
package_filename = package_name + '.dmg'
|
||||
package_filepath = os.path.join(builder.build_dir, package_filename)
|
||||
# create release package
|
||||
try:
|
||||
subprocess.call(['make', 'package_archive'])
|
||||
except Exception as ex:
|
||||
sys.stderr.write('Make package release failed' + str(ex) + '\n')
|
||||
sys.exit(1)
|
||||
|
||||
release_dir = os.path.join(builder.blender_dir, 'release', 'darwin')
|
||||
bundle_sh = os.path.join(release_dir, 'bundle.sh')
|
||||
if info.is_development_build:
|
||||
background_image = os.path.join(release_dir, 'buildbot', 'background.tif')
|
||||
# find release directory, must exist this time
|
||||
if not os.path.exists(release_dir):
|
||||
sys.stderr.write("Failed to find release directory %r.\n" % release_dir)
|
||||
sys.exit(1)
|
||||
|
||||
command = [bundle_sh]
|
||||
command += ['--source', builder.install_dir]
|
||||
command += ['--dmg', package_filepath]
|
||||
command += ['--background-image', background_image]
|
||||
buildbot_utils.call(command)
|
||||
# find release package
|
||||
file = None
|
||||
filepath = None
|
||||
|
||||
create_buildbot_upload_zip(builder, [(package_filepath, package_filename)])
|
||||
for f in os.listdir(release_dir):
|
||||
rf = os.path.join(release_dir, f)
|
||||
if os.path.isfile(rf) and f.startswith('blender'):
|
||||
file = f
|
||||
filepath = rf
|
||||
|
||||
if not file:
|
||||
sys.stderr.write("Failed to find release package.\n")
|
||||
sys.exit(1)
|
||||
|
||||
def pack_win(builder):
|
||||
info = buildbot_utils.VersionInfo(builder)
|
||||
upload_filename = file
|
||||
upload_filepath = filepath
|
||||
|
||||
os.chdir(builder.build_dir)
|
||||
cleanup_files(builder.build_dir, '.zip')
|
||||
|
||||
# CPack will add the platform name
|
||||
cpack_name = get_package_name(builder, None)
|
||||
package_name = get_package_name(builder, 'windows' + str(builder.bits))
|
||||
|
||||
command = ['cmake', '-DCPACK_OVERRIDE_PACKAGENAME:STRING=' + cpack_name, '.']
|
||||
buildbot_utils.call(builder.command_prefix + command)
|
||||
command = ['cpack', '-G', 'ZIP']
|
||||
buildbot_utils.call(builder.command_prefix + command)
|
||||
|
||||
package_filename = package_name + '.zip'
|
||||
package_filepath = os.path.join(builder.build_dir, package_filename)
|
||||
package_files = [(package_filepath, package_filename)]
|
||||
|
||||
if info.version_cycle == 'release':
|
||||
# Installer only for final release builds, otherwise will get
|
||||
# 'this product is already installed' messages.
|
||||
command = ['cpack', '-G', 'WIX']
|
||||
buildbot_utils.call(builder.command_prefix + command)
|
||||
|
||||
package_filename = package_name + '.msi'
|
||||
package_filepath = os.path.join(builder.build_dir, package_filename)
|
||||
package_files += [(package_filepath, package_filename)]
|
||||
|
||||
create_buildbot_upload_zip(builder, package_files)
|
||||
|
||||
|
||||
def pack_linux(builder):
|
||||
blender_executable = os.path.join(builder.install_dir, 'blender')
|
||||
|
||||
info = buildbot_utils.VersionInfo(builder)
|
||||
blender_glibc = builder.name.split('_')[1]
|
||||
blender_arch = 'x86_64'
|
||||
|
||||
# Strip all unused symbols from the binaries
|
||||
print("Stripping binaries...")
|
||||
buildbot_utils.call(builder.command_prefix + ['strip', '--strip-all', blender_executable])
|
||||
|
||||
print("Stripping python...")
|
||||
py_target = os.path.join(builder.install_dir, info.version)
|
||||
buildbot_utils.call(builder.command_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';'])
|
||||
|
||||
# Copy all specific files which are too specific to be copied by
|
||||
# the CMake rules themselves
|
||||
print("Copying extra scripts and libs...")
|
||||
|
||||
extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
|
||||
mesalibs = os.path.join(extra, 'mesalibs' + str(builder.bits) + '.tar.bz2')
|
||||
software_gl = os.path.join(builder.blender_dir, 'release', 'bin', 'blender-softwaregl')
|
||||
icons = os.path.join(builder.blender_dir, 'release', 'freedesktop', 'icons')
|
||||
|
||||
os.system('tar -xpf %s -C %s' % (mesalibs, builder.install_dir))
|
||||
os.system('cp %s %s' % (software_gl, builder.install_dir))
|
||||
os.system('cp -r %s %s' % (icons, builder.install_dir))
|
||||
os.system('chmod 755 %s' % (os.path.join(builder.install_dir, 'blender-softwaregl')))
|
||||
|
||||
# Construct package name
|
||||
platform_name = 'linux-' + blender_glibc + '-' + blender_arch
|
||||
package_name = get_package_name(builder, platform_name)
|
||||
package_filename = package_name + ".tar.bz2"
|
||||
|
||||
print("Creating .tar.bz2 archive")
|
||||
package_filepath = builder.install_dir + '.tar.bz2'
|
||||
create_tar_bz2(builder.install_dir, package_filepath, package_name)
|
||||
|
||||
# Create buildbot_upload.zip
|
||||
create_buildbot_upload_zip(builder, [(package_filepath, package_filename)])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = buildbot_utils.create_builder_from_arguments()
|
||||
|
||||
# Make sure install directory always exists
|
||||
os.makedirs(builder.install_dir, exist_ok=True)
|
||||
|
||||
if builder.platform == 'mac':
|
||||
pack_mac(builder)
|
||||
elif builder.platform == 'win':
|
||||
pack_win(builder)
|
||||
elif builder.platform == 'linux':
|
||||
pack_linux(builder)
|
||||
# create zip file
|
||||
try:
|
||||
upload_zip = os.path.join(buildbot_upload_zip)
|
||||
if os.path.exists(upload_zip):
|
||||
os.remove(upload_zip)
|
||||
z = zipfile.ZipFile(upload_zip, "w", compression=zipfile.ZIP_STORED)
|
||||
z.write(upload_filepath, arcname=upload_filename)
|
||||
z.close()
|
||||
except Exception as ex:
|
||||
sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n')
|
||||
sys.exit(1)
|
||||
|
@@ -21,17 +21,23 @@
|
||||
# Runs on buildbot slave, rsync zip directly to buildbot server rather
|
||||
# than using upload which is much slower
|
||||
|
||||
import buildbot_utils
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = buildbot_utils.create_builder_from_arguments()
|
||||
# get builder name
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write("Not enough arguments, expecting builder name\n")
|
||||
sys.exit(1)
|
||||
|
||||
# rsync, this assumes ssh keys are setup so no password is needed
|
||||
local_zip = "buildbot_upload.zip"
|
||||
remote_folder = "builder.blender.org:/data/buildbot-master/uploaded/"
|
||||
remote_zip = remote_folder + "buildbot_upload_" + builder.name + ".zip"
|
||||
builder = sys.argv[1]
|
||||
|
||||
command = ["rsync", "-avz", local_zip, remote_zip]
|
||||
buildbot_utils.call(command)
|
||||
# rsync, this assumes ssh keys are setup so no password is needed
|
||||
local_zip = "buildbot_upload.zip"
|
||||
remote_folder = "builder.blender.org:/data/buildbot-master/uploaded/"
|
||||
remote_zip = remote_folder + "buildbot_upload_" + builder + ".zip"
|
||||
command = "rsync -avz %s %s" % (local_zip, remote_zip)
|
||||
|
||||
print(command)
|
||||
|
||||
ret = os.system(command)
|
||||
sys.exit(ret)
|
||||
|
@@ -18,39 +18,59 @@
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import buildbot_utils
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
|
||||
def get_ctest_environment(builder):
|
||||
info = buildbot_utils.VersionInfo(builder)
|
||||
blender_version_dir = os.path.join(builder.install_dir, info.version)
|
||||
# get builder name
|
||||
if len(sys.argv) < 2:
|
||||
sys.stderr.write("Not enough arguments, expecting builder name\n")
|
||||
sys.exit(1)
|
||||
|
||||
env = os.environ.copy()
|
||||
env['BLENDER_SYSTEM_SCRIPTS'] = os.path.join(blender_version_dir, 'scripts')
|
||||
env['BLENDER_SYSTEM_DATAFILES'] = os.path.join(blender_version_dir, 'datafiles')
|
||||
return env
|
||||
builder = sys.argv[1]
|
||||
|
||||
def get_ctest_arguments(builder):
|
||||
args = ['--output-on-failure']
|
||||
if builder.platform == 'win':
|
||||
args += ['-C', 'Release']
|
||||
return args
|
||||
# we run from build/ directory
|
||||
blender_dir = '../blender.git'
|
||||
|
||||
def test(builder):
|
||||
os.chdir(builder.build_dir)
|
||||
|
||||
command = builder.command_prefix + ['ctest'] + get_ctest_arguments(builder)
|
||||
ctest_env = get_ctest_environment(builder)
|
||||
buildbot_utils.call(command, env=ctest_env, exit_on_error=False)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "cmake" in builder:
|
||||
print("Automated tests are still DISABLED!")
|
||||
sys.exit(0)
|
||||
|
||||
builder = buildbot_utils.create_builder_from_arguments()
|
||||
test(builder)
|
||||
build_dir = os.path.abspath(os.path.join('..', 'build', builder))
|
||||
install_dir = os.path.abspath(os.path.join('..', 'install', builder))
|
||||
# NOTE: For quick test only to see if the approach work.
|
||||
# n the future must be replaced with an actual blender version.
|
||||
blender_version = '2.80'
|
||||
blender_version_dir = os.path.join(install_dir, blender_version)
|
||||
command_prefix = []
|
||||
extra_ctest_args = []
|
||||
|
||||
if builder.startswith('win'):
|
||||
extra_ctest_args += ['-C', 'Release']
|
||||
elif builder.startswith('linux'):
|
||||
tokens = builder.split("_")
|
||||
glibc = tokens[1]
|
||||
if glibc == 'glibc224':
|
||||
deb_name = "stretch"
|
||||
if builder.endswith('x86_64_cmake'):
|
||||
chroot_name = 'buildbot_' + deb_name + '_x86_64'
|
||||
elif builder.endswith('i686_cmake'):
|
||||
chroot_name = 'buildbot_' + deb_name + '_i686'
|
||||
command_prefix = ['schroot', '--preserve-environment', '-c', chroot_name, '--']
|
||||
elif glibc == 'glibc217':
|
||||
command_prefix = ['scl', 'enable', 'devtoolset-6', '--']
|
||||
|
||||
ctest_env = os.environ.copy()
|
||||
ctest_env['BLENDER_SYSTEM_SCRIPTS'] = os.path.join(blender_version_dir, 'scripts')
|
||||
ctest_env['BLENDER_SYSTEM_DATAFILES'] = os.path.join(blender_version_dir, 'datafiles')
|
||||
|
||||
os.chdir(build_dir)
|
||||
retcode = subprocess.call(command_prefix + ['ctest', '--output-on-failure'] + extra_ctest_args,
|
||||
env=ctest_env)
|
||||
|
||||
# Always exit with a success, for until we know all the tests are passing
|
||||
# on all builders.
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("Unknown building system")
|
||||
sys.exit(1)
|
||||
|
@@ -1,31 +0,0 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import buildbot_utils
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = buildbot_utils.create_builder_from_arguments()
|
||||
os.chdir(builder.blender_dir)
|
||||
|
||||
# Run make update which handles all libraries and submodules.
|
||||
make_update = os.path.join(builder.blender_dir, "build_files", "utils", "make_update.py")
|
||||
buildbot_utils.call([sys.executable, make_update])
|
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
|
||||
)
|
@@ -14,15 +14,12 @@
|
||||
|
||||
macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
|
||||
if(WITH_GTESTS)
|
||||
set(TARGET_NAME ${NAME}_test)
|
||||
get_property(_current_include_directories
|
||||
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PROPERTY INCLUDE_DIRECTORIES)
|
||||
set(TEST_INC
|
||||
${_current_include_directories}
|
||||
${CMAKE_SOURCE_DIR}/tests/gtests
|
||||
)
|
||||
set(TEST_INC_SYS
|
||||
${GLOG_INCLUDE_DIRS}
|
||||
${GFLAGS_INCLUDE_DIRS}
|
||||
${CMAKE_SOURCE_DIR}/extern/gtest/include
|
||||
@@ -30,10 +27,8 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
|
||||
)
|
||||
unset(_current_include_directories)
|
||||
|
||||
add_executable(${TARGET_NAME} ${SRC})
|
||||
target_include_directories(${TARGET_NAME} PUBLIC "${TEST_INC}")
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC "${TEST_INC_SYS}")
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
add_executable(${NAME}_test ${SRC})
|
||||
target_link_libraries(${NAME}_test
|
||||
${EXTRA_LIBS}
|
||||
${PLATFORM_LINKLIBS}
|
||||
bf_testing_main
|
||||
@@ -46,22 +41,20 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
|
||||
${GLOG_LIBRARIES}
|
||||
${GFLAGS_LIBRARIES})
|
||||
if(WITH_OPENMP_STATIC)
|
||||
target_link_libraries(${TARGET_NAME} ${OpenMP_LIBRARIES})
|
||||
target_link_libraries(${NAME}_test ${OpenMP_LIBRARIES})
|
||||
endif()
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES
|
||||
set_target_properties(${NAME}_test PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}")
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}"
|
||||
INCLUDE_DIRECTORIES "${TEST_INC}")
|
||||
if(${DO_ADD_TEST})
|
||||
add_test(NAME ${TARGET_NAME} COMMAND ${TESTS_OUTPUT_DIR}/${TARGET_NAME} WORKING_DIRECTORY $<TARGET_FILE_DIR:blender>)
|
||||
add_test(NAME ${NAME}_test COMMAND ${TESTS_OUTPUT_DIR}/${NAME}_test WORKING_DIRECTORY $<TARGET_FILE_DIR:blender>)
|
||||
|
||||
# Don't fail tests on leaks since these often happen in external libraries
|
||||
# that we can't fix.
|
||||
set_tests_properties(${TARGET_NAME} PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
|
||||
set_tests_properties(${NAME}_test PROPERTIES ENVIRONMENT LSAN_OPTIONS=exitcode=0)
|
||||
endif()
|
||||
unset(TEST_INC)
|
||||
unset(TEST_INC_SYS)
|
||||
unset(TARGET_NAME)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
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()
|
||||
|
@@ -1,55 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# "make test" for all platforms, running automated tests.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import make_utils
|
||||
from make_utils import call
|
||||
|
||||
# Parse arguments
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--ctest-command", default="ctest")
|
||||
parser.add_argument("--cmake-command", default="cmake")
|
||||
parser.add_argument("--svn-command", default="svn")
|
||||
parser.add_argument("--git-command", default="git")
|
||||
parser.add_argument("build_directory")
|
||||
return parser.parse_args()
|
||||
|
||||
args = parse_arguments()
|
||||
git_command = args.git_command
|
||||
svn_command = args.svn_command
|
||||
ctest_command = args.ctest_command
|
||||
cmake_command = args.cmake_command
|
||||
build_dir = args.build_directory
|
||||
|
||||
if shutil.which(ctest_command) is None:
|
||||
sys.stderr.write("ctest not found, can't run tests\n")
|
||||
sys.exit(1)
|
||||
|
||||
# Test if we are building a specific release version.
|
||||
release_version = make_utils.git_branch_release_version(git_command)
|
||||
lib_tests_dirpath = os.path.join('..', 'lib', "tests")
|
||||
|
||||
if not os.path.exists(lib_tests_dirpath):
|
||||
print("Tests files not found, downloading...")
|
||||
|
||||
if shutil.which(svn_command) is None:
|
||||
sys.stderr.write("svn not found, can't checkout test files\n")
|
||||
sys.exit(1)
|
||||
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version) + "/tests"
|
||||
call([svn_command, "checkout", svn_url, lib_tests_dirpath])
|
||||
|
||||
# Run cmake again to detect tests files.
|
||||
os.chdir(build_dir)
|
||||
call([cmake_command, "."])
|
||||
|
||||
# Run tests
|
||||
os.chdir(build_dir)
|
||||
call([ctest_command, ".", "--output-on-failure"])
|
@@ -1,107 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# "make update" for all platforms, updating svn libraries and tests and Blender
|
||||
# git repository and submodules.
|
||||
#
|
||||
# For release branches, this will check out the appropriate branches of
|
||||
# submodules and libraries.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import make_utils
|
||||
from make_utils import call
|
||||
|
||||
# Parse arguments
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--only-code", action="store_true")
|
||||
parser.add_argument("--svn-command", default="svn")
|
||||
parser.add_argument("--git-command", default="git")
|
||||
return parser.parse_args()
|
||||
|
||||
args = parse_arguments()
|
||||
only_code = args.only_code
|
||||
git_command = args.git_command
|
||||
svn_command = args.svn_command
|
||||
svn_non_interactive = [args.svn_command, '--non-interactive']
|
||||
|
||||
def print_stage(text):
|
||||
print("")
|
||||
print(text)
|
||||
print("")
|
||||
|
||||
# Test if we are building a specific release version.
|
||||
release_version = make_utils.git_branch_release_version(git_command)
|
||||
|
||||
# Setup for precompiled libraries and tests from svn.
|
||||
if not only_code:
|
||||
lib_dirpath = os.path.join('..', 'lib')
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version)
|
||||
|
||||
# Checkout precompiled libraries
|
||||
if sys.platform == 'darwin':
|
||||
lib_platform = "darwin"
|
||||
elif sys.platform == 'win32':
|
||||
# Windows checkout is usually handled by bat scripts since python3 to run
|
||||
# this script is bundled as part of the precompiled libraries. However it
|
||||
# is used by the buildbot.
|
||||
lib_platform = "win64_vc14"
|
||||
else:
|
||||
# No precompiled libraries for Linux.
|
||||
lib_platform = None
|
||||
|
||||
if lib_platform:
|
||||
lib_platform_dirpath = os.path.join(lib_dirpath, lib_platform)
|
||||
|
||||
if not os.path.exists(lib_platform_dirpath):
|
||||
print_stage("Checking out Precompiled Libraries")
|
||||
|
||||
if shutil.which(svn_command) is None:
|
||||
sys.stderr.write("svn not found, can't checkout libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
svn_url_platform = svn_url + lib_platform
|
||||
call(svn_non_interactive + ["checkout", svn_url_platform, lib_platform_dirpath])
|
||||
|
||||
# Update precompiled libraries and tests
|
||||
print_stage("Updating Precompiled Libraries and Tests")
|
||||
|
||||
if os.path.isdir(lib_dirpath):
|
||||
for dirname in os.listdir(lib_dirpath):
|
||||
if dirname == ".svn":
|
||||
continue
|
||||
|
||||
dirpath = os.path.join(lib_dirpath, dirname)
|
||||
svn_dirpath = os.path.join(dirpath, ".svn")
|
||||
svn_root_dirpath = os.path.join(lib_dirpath, ".svn")
|
||||
|
||||
if os.path.isdir(dirpath) and \
|
||||
(os.path.exists(svn_dirpath) or os.path.exists(svn_root_dirpath)):
|
||||
if shutil.which(svn_command) is None:
|
||||
sys.stderr.write("svn not found, can't update libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
call(svn_non_interactive + ["cleanup", dirpath])
|
||||
call(svn_non_interactive + ["switch", svn_url + dirname, dirpath])
|
||||
call(svn_non_interactive + ["update", dirpath])
|
||||
|
||||
# Update blender repository and submodules.
|
||||
print_stage("Updating Blender Git Repository and Submodules")
|
||||
|
||||
if shutil.which(git_command) is None:
|
||||
sys.stderr.write("git not found, can't update code\n")
|
||||
sys.exit(1)
|
||||
|
||||
call([git_command, "pull", "--rebase"])
|
||||
call([git_command, "submodule", "update", "--init", "--recursive"])
|
||||
|
||||
if not release_version:
|
||||
# Update submodules to latest master if not building a specific release.
|
||||
# In that case submodules are set to a specific revision, which is checked
|
||||
# out by running "git submodule update".
|
||||
call([git_command, "submodule", "foreach", "git", "checkout", "master"])
|
||||
call([git_command, "submodule", "foreach", "git", "pull", "--rebase", "origin", "master"])
|
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Utility functions for make update and make tests.
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def call(cmd):
|
||||
print(" ".join(cmd))
|
||||
|
||||
# Flush to ensure correct order output on Windows.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
retcode = subprocess.call(cmd)
|
||||
if retcode != 0:
|
||||
sys.exit(retcode)
|
||||
|
||||
def git_branch_release_version(git_command):
|
||||
# Test if we are building a specific release version.
|
||||
try:
|
||||
branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
|
||||
except subprocess.CalledProcessError as e:
|
||||
sys.stderr.write("Failed to get Blender git branch\n")
|
||||
sys.exit(1)
|
||||
|
||||
branch = branch.strip().decode('utf8')
|
||||
release_version = re.search("^blender-v(.*)-release$", branch)
|
||||
if release_version:
|
||||
release_version = release_version.group(1)
|
||||
return release_version
|
||||
|
||||
def svn_libraries_base_url(release_version):
|
||||
if release_version:
|
||||
svn_branch = "tags/blender-" + release_version + "-release"
|
||||
else:
|
||||
svn_branch = "trunk"
|
||||
return "https://svn.blender.org/svnroot/bf-blender/" + svn_branch + "/lib/"
|
@@ -39,15 +39,6 @@ if NOT EXIST %BUILD_VS_LIBDIR% (
|
||||
)
|
||||
)
|
||||
)
|
||||
) else (
|
||||
if NOT EXIST %PYTHON% (
|
||||
if not "%SVN%"=="" (
|
||||
echo.
|
||||
echo Python not found in external libraries, updating to latest version
|
||||
echo.
|
||||
"%SVN%" update %BUILD_VS_LIBDIR%
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if NOT EXIST %BUILD_VS_LIBDIR% (
|
||||
|
@@ -2,12 +2,10 @@ REM find all dependencies and set the corresponding environment variables.
|
||||
for %%X in (svn.exe) do (set SVN=%%~$PATH:X)
|
||||
for %%X in (cmake.exe) do (set CMAKE=%%~$PATH:X)
|
||||
for %%X in (git.exe) do (set GIT=%%~$PATH:X)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc14\python\37\bin\python.exe
|
||||
if NOT "%verbose%" == "" (
|
||||
echo svn : "%SVN%"
|
||||
echo cmake : "%CMAKE%"
|
||||
echo git : "%GIT%"
|
||||
echo python : "%PYTHON%"
|
||||
echo svn : "%SVN%"
|
||||
echo cmake : "%CMAKE%"
|
||||
echo git : "%GIT%"
|
||||
)
|
||||
if "%CMAKE%" == "" (
|
||||
echo Cmake not found in path, required for building, exiting...
|
||||
|
@@ -9,7 +9,7 @@ exit /b 1
|
||||
:detect_done
|
||||
echo found clang-format in %CF_PATH%
|
||||
|
||||
if EXIST %PYTHON% (
|
||||
if EXIST %BLENDER_DIR%\..\lib\win64_vc14\python\37\bin\python.exe (
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc14\python\37\bin\python.exe
|
||||
goto detect_python_done
|
||||
)
|
||||
@@ -25,7 +25,6 @@ set FORMAT_PATHS=%BLENDER_DIR%\source\tools\utils_maintenance\clang_format_paths
|
||||
REM The formatting script expects clang-format to be in the current PATH.
|
||||
set PATH=%CF_PATH%;%PATH%
|
||||
|
||||
REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
|
||||
%PYTHON% -B %FORMAT_PATHS% %FORMAT_ARGS%
|
||||
%PYTHON% %FORMAT_PATHS% %FORMAT_ARGS%
|
||||
|
||||
:EOF
|
||||
|
@@ -82,10 +82,12 @@ if NOT "%1" == "" (
|
||||
REM Non-Build Commands
|
||||
) else if "%1" == "update" (
|
||||
SET BUILD_UPDATE=1
|
||||
set BUILD_UPDATE_ARGS=
|
||||
set BUILD_UPDATE_SVN=1
|
||||
set BUILD_UPDATE_GIT=1
|
||||
) else if "%1" == "code_update" (
|
||||
SET BUILD_UPDATE=1
|
||||
set BUILD_UPDATE_ARGS="--only-code"
|
||||
set BUILD_UPDATE_SVN=0
|
||||
set BUILD_UPDATE_GIT=1
|
||||
) else if "%1" == "ninja" (
|
||||
SET BUILD_WITH_NINJA=1
|
||||
) else if "%1" == "clean" (
|
||||
@@ -106,4 +108,4 @@ if NOT "%1" == "" (
|
||||
:EOF
|
||||
exit /b 0
|
||||
:ERR
|
||||
exit /b 1
|
||||
exit /b 1
|
@@ -1,13 +1,18 @@
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
if "%BUILD_UPDATE_SVN%" == "1" (
|
||||
if "%SVN%" == "" (
|
||||
echo svn not found, cannot update libraries
|
||||
goto UPDATE_GIT
|
||||
)
|
||||
"%SVN%" up "%BLENDER_DIR%/../lib/*"
|
||||
)
|
||||
:UPDATE_GIT
|
||||
|
||||
echo python not found in lib folder
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
|
||||
REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
|
||||
%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_update.py --git-command "%GIT%" --svn-command "%SVN%" %BUILD_UPDATE_ARGS%
|
||||
|
||||
if "%BUILD_UPDATE_GIT%" == "1" (
|
||||
if "%GIT%" == "" (
|
||||
echo Git not found, cannot update code
|
||||
goto EOF
|
||||
)
|
||||
"%GIT%" pull --rebase
|
||||
"%GIT%" submodule foreach git pull --rebase origin master
|
||||
)
|
||||
:EOF
|
||||
|
@@ -76,3 +76,7 @@ endif()
|
||||
if(WITH_OPENVDB)
|
||||
add_subdirectory(openvdb)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENXR)
|
||||
add_subdirectory(vamr)
|
||||
endif()
|
||||
|
@@ -232,7 +232,7 @@ void Session::run_gpu()
|
||||
}
|
||||
|
||||
/* Don't go in pause mode when image was rendered with preview kernels
|
||||
* When feature kernels become available the session will be reset. */
|
||||
* When feature kernels become available the session will be resetted. */
|
||||
else if (no_tiles && kernel_state == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) {
|
||||
time_sleep(0.1);
|
||||
}
|
||||
|
@@ -364,7 +364,7 @@ void avcodec_free_frame(AVFrame **frame)
|
||||
# define avio_size url_fsize
|
||||
#endif
|
||||
|
||||
/* There are some version in between, which have avio_... functions but no
|
||||
/* there are some version inbetween, which have avio_... functions but no
|
||||
* AVIO_FLAG_... */
|
||||
#ifndef AVIO_FLAG_WRITE
|
||||
# define AVIO_FLAG_WRITE URL_WRONLY
|
||||
|
@@ -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
|
||||
@@ -477,7 +486,7 @@ extern GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle);
|
||||
|
||||
/**
|
||||
* Returns the timer callback.
|
||||
* \param timertaskhandle The handle to the timer-task.
|
||||
* \param timertaskhandle The handle to the timertask
|
||||
* \return The timer callback.
|
||||
*/
|
||||
extern GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle);
|
||||
@@ -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.
|
||||
@@ -402,7 +408,7 @@ class GHOST_ISystem {
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
/**
|
||||
* Sets 3D mouse deadzone
|
||||
* \param deadzone: Dead-zone of the 3D mouse (both for rotation and pan) relative to full range
|
||||
* \param deadzone: Deadzone of the 3D mouse (both for rotation and pan) relative to full range
|
||||
*/
|
||||
virtual void setNDOFDeadZone(float deadzone) = 0;
|
||||
#endif
|
||||
|
@@ -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__ */
|
14
make.bat
14
make.bat
@@ -26,6 +26,12 @@ if "%SHOW_HELP%" == "1" (
|
||||
goto EOF
|
||||
)
|
||||
|
||||
if "%BUILD_UPDATE%" == "1" (
|
||||
call "%BLENDER_DIR%\build_files\windows\update_sources.cmd"
|
||||
goto EOF
|
||||
)
|
||||
|
||||
|
||||
if "%FORMAT%" == "1" (
|
||||
call "%BLENDER_DIR%\build_files\windows\format.cmd"
|
||||
goto EOF
|
||||
@@ -48,14 +54,6 @@ if "%BUILD_VS_YEAR%" == "" (
|
||||
)
|
||||
)
|
||||
|
||||
if "%BUILD_UPDATE%" == "1" (
|
||||
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
|
||||
if errorlevel 1 goto EOF
|
||||
|
||||
call "%BLENDER_DIR%\build_files\windows\update_sources.cmd"
|
||||
goto EOF
|
||||
)
|
||||
|
||||
call "%BLENDER_DIR%\build_files\windows\set_build_dir.cmd"
|
||||
|
||||
echo Building blender with VS%BUILD_VS_YEAR% for %BUILD_ARCH% in %BUILD_DIR%
|
||||
|
Binary file not shown.
@@ -54,11 +54,6 @@ while [[ $# -gt 0 ]]; do
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--background-image)
|
||||
_background_image="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
echo "Usage:"
|
||||
echo " $(basename "$0") --source DIR --dmg IMAGENAME "
|
||||
|
Submodule release/datafiles/locale updated: 6a6b84fd50...61cb42387d
Binary file not shown.
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.4 KiB |
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 543 KiB After Width: | Height: | Size: 562 KiB |
48
release/datafiles/prvicons_update.py
Normal file → Executable file
48
release/datafiles/prvicons_update.py
Normal file → Executable file
@@ -1,25 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script updates icons from the SVG file
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
BASEDIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
inkscape_path = 'inkscape'
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
inkscape_app_path = '/Applications/Inkscape.app/Contents/Resources/script'
|
||||
if os.path.exists(inkscape_app_path):
|
||||
inkscape_path = inkscape_app_path
|
||||
|
||||
cmd = (
|
||||
inkscape_path,
|
||||
os.path.join(BASEDIR, "prvicons.svg"),
|
||||
"--export-width=1536",
|
||||
"--export-height=256",
|
||||
"--without-gui",
|
||||
"--export-png=" + os.path.join(BASEDIR, "prvicons.png"),
|
||||
)
|
||||
subprocess.check_call(cmd)
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script updates icons from the SVG file
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
BASEDIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
inkscape_path = 'inkscape'
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
inkscape_app_path = '/Applications/Inkscape.app/Contents/Resources/script'
|
||||
if os.path.exists(inkscape_app_path):
|
||||
inkscape_path = inkscape_app_path
|
||||
|
||||
cmd = (
|
||||
inkscape_path,
|
||||
os.path.join(BASEDIR, "prvicons.svg"),
|
||||
"--without-gui",
|
||||
"--export-png=" + os.path.join(BASEDIR, "prvicons.png"),
|
||||
)
|
||||
subprocess.check_call(cmd)
|
||||
|
@@ -370,7 +370,7 @@ const bTheme U_theme_default = {
|
||||
.paint_curve_handle = RGBA(0x7fff7f7f),
|
||||
},
|
||||
.space_file = {
|
||||
.back = RGBA(0x33333300),
|
||||
.back = RGBA(0x35353500),
|
||||
.title = RGBA(0xffffffff),
|
||||
.text = RGBA(0xe6e6e6ff),
|
||||
.text_hi = RGBA(0xffffffff),
|
||||
@@ -381,14 +381,13 @@ const bTheme U_theme_default = {
|
||||
.tab_inactive = RGBA(0x2b2b2bff),
|
||||
.tab_back = RGBA(0x232323ff),
|
||||
.tab_outline = RGBA(0x232323ff),
|
||||
.button = RGBA(0x4b4b4bff),
|
||||
.button = RGBA(0x424242ff),
|
||||
.button_title = RGBA(0xffffffff),
|
||||
.button_text = RGBA(0xe5e5e5ff),
|
||||
.button_text_hi = RGBA(0xffffffff),
|
||||
.execution_buts = RGBA(0x444444ff),
|
||||
.panelcolors = {
|
||||
.header = RGBA(0x4b4b4bff),
|
||||
.back = RGBA(0x404040ff),
|
||||
.header = RGBA(0x424242cc),
|
||||
.back = RGBA(0x333333b3),
|
||||
.sub_back = RGBA(0x0000003e),
|
||||
},
|
||||
.hilite = RGBA(0x4f76b3ff),
|
||||
|
Submodule release/scripts/addons updated: 8d11c9e828...fe627477c2
Submodule release/scripts/addons_contrib updated: 2769f4b5f5...8b5ea4d118
@@ -409,7 +409,6 @@ def km_window(params):
|
||||
items.extend([
|
||||
("wm.doc_view_manual_ui_context", {"type": 'F1', "value": 'PRESS'}, None),
|
||||
op_panel("TOPBAR_PT_name", {"type": 'F2', "value": 'PRESS'}, [("keep_open", False)]),
|
||||
("wm.batch_rename", {"type": 'F2', "value": 'PRESS', "alt": True}, None),
|
||||
("wm.search_menu", {"type": 'F3', "value": 'PRESS'}, None),
|
||||
op_menu("TOPBAR_MT_file_context_menu", {"type": 'F4', "value": 'PRESS'}),
|
||||
])
|
||||
@@ -1771,11 +1770,6 @@ def km_file_browser(_params):
|
||||
)
|
||||
|
||||
items.extend([
|
||||
*_template_space_region_type_toggle(
|
||||
toolbar_key={"type": 'T', "value": 'PRESS'},
|
||||
),
|
||||
("screen.region_toggle", {"type": 'N', "value": 'PRESS'},
|
||||
{"properties": [("region_type", 'TOOL_PROPS')]}),
|
||||
("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None),
|
||||
("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None),
|
||||
("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None),
|
||||
@@ -1787,6 +1781,7 @@ def km_file_browser(_params):
|
||||
{"properties": [("data_path", 'space_data.params.show_hidden')]}),
|
||||
("file.directory_new", {"type": 'I', "value": 'PRESS'}, None),
|
||||
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
|
||||
("file.bookmark_toggle", {"type": 'T', "value": 'PRESS'}, None),
|
||||
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
|
||||
])
|
||||
|
||||
@@ -1805,13 +1800,17 @@ def km_file_browser_main(params):
|
||||
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
|
||||
{"properties": [("need_active", True)]}),
|
||||
("file.refresh", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
|
||||
{"properties": [("open", False)]}),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True},
|
||||
{"properties": [("extend", True), ("fill", True)]}),
|
||||
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK'},
|
||||
{"properties": [("open", False)]}),
|
||||
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("extend", True), ("open", False)]}),
|
||||
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK', "alt": True},
|
||||
{"properties": [("extend", True), ("fill", True), ("open", False)]}),
|
||||
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'},
|
||||
{"properties": [("direction", 'UP')]}),
|
||||
("file.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True},
|
||||
@@ -1843,11 +1842,8 @@ def km_file_browser_main(params):
|
||||
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
|
||||
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True},
|
||||
{"properties": [("mode", 'ADD')]}),
|
||||
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True},
|
||||
{"properties": [("mode", 'SUB')]}),
|
||||
("file.rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
|
||||
("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
|
||||
("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
|
||||
op_menu("FILEBROWSER_MT_context_menu", params.context_menu_event),
|
||||
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
|
||||
{"properties": [("increment", 1)]}),
|
||||
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
|
||||
|
@@ -1196,11 +1196,10 @@ def km_file_browser_main(params):
|
||||
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
|
||||
{"properties": [("need_active", True)]}),
|
||||
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
|
||||
{"properties": [("open", False)]}),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True,},
|
||||
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True},
|
||||
{"properties": [("extend", True), ("fill", True)]}),
|
||||
("file.select", {"type": 'RIGHTMOUSE', "value": 'CLICK'},
|
||||
{"properties": [("open", False)]}),
|
||||
@@ -1240,8 +1239,6 @@ def km_file_browser_main(params):
|
||||
("file.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True},
|
||||
{"properties": [("mode", 'ADD')]}),
|
||||
("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
|
||||
("file.sort_column_ui_context", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None),
|
||||
op_menu("FILEBROWSER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
|
||||
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS'},
|
||||
{"properties": [("increment", 1)]}),
|
||||
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True},
|
||||
|
@@ -25,7 +25,6 @@ from bpy.types import (
|
||||
)
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
CollectionProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
IntProperty,
|
||||
@@ -1175,7 +1174,6 @@ rna_vector_subtype_items = (
|
||||
('QUATERNION', "Quaternion Rotation", "Quaternion rotation (affects NLA blending)"),
|
||||
)
|
||||
|
||||
|
||||
class WM_OT_properties_edit(Operator):
|
||||
bl_idname = "wm.properties_edit"
|
||||
bl_label = "Edit Property"
|
||||
@@ -1765,423 +1763,6 @@ class WM_OT_toolbar(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class BatchRenameAction(bpy.types.PropertyGroup):
|
||||
# category: StringProperty()
|
||||
type: EnumProperty(
|
||||
name="Operation",
|
||||
items=(
|
||||
('REPLACE', "Find/Replace", "Replace text in the name"),
|
||||
('SET', "Set Name", "Set a new name or prefix/suffix the existing one"),
|
||||
('STRIP', "Strip Characters", "Strip leading/trailing text from the name"),
|
||||
('CASE', "Change Case", "Change case of each name"),
|
||||
),
|
||||
)
|
||||
|
||||
# We could split these into sub-properties, however it's not so important.
|
||||
|
||||
# type: 'SET'.
|
||||
set_name: StringProperty(name="Name")
|
||||
set_method: EnumProperty(
|
||||
name="Method",
|
||||
items=(
|
||||
('NEW', "New", ""),
|
||||
('PREFIX', "Prefix", ""),
|
||||
('SUFFIX', "Suffix", ""),
|
||||
),
|
||||
default='SUFFIX',
|
||||
)
|
||||
|
||||
# type: 'STRIP'.
|
||||
strip_chars: EnumProperty(
|
||||
name="Strip Characters",
|
||||
options={'ENUM_FLAG'},
|
||||
items=(
|
||||
('SPACE', "Spaces", ""),
|
||||
('DIGIT', "Digits", ""),
|
||||
('PUNCT', "Punctuation", ""),
|
||||
),
|
||||
)
|
||||
|
||||
# type: 'STRIP'.
|
||||
strip_part: EnumProperty(
|
||||
name="Strip Part",
|
||||
options={'ENUM_FLAG'},
|
||||
items=(
|
||||
('START', "Start", ""),
|
||||
('END', "End", ""),
|
||||
),
|
||||
)
|
||||
|
||||
# type: 'REPLACE'.
|
||||
replace_src: StringProperty(name="Find")
|
||||
replace_dst: StringProperty(name="Replace")
|
||||
replace_match_case: BoolProperty(name="Case Sensitive")
|
||||
replace_regex: BoolProperty(
|
||||
name="Regular Expression",
|
||||
description="Use regular expressions to match text in the 'Find' field"
|
||||
)
|
||||
|
||||
# type: 'CASE'.
|
||||
case_method: EnumProperty(
|
||||
name="Case",
|
||||
items=(
|
||||
('UPPER', "Upper Case", ""),
|
||||
('LOWER', "Lower Case", ""),
|
||||
('TITLE', "Title Caps", ""),
|
||||
),
|
||||
)
|
||||
|
||||
# Weak, add/remove as properties.
|
||||
op_add: BoolProperty()
|
||||
op_remove: BoolProperty()
|
||||
|
||||
|
||||
class WM_OT_batch_rename(Operator):
|
||||
bl_idname = "wm.batch_rename"
|
||||
bl_label = "Batch Rename"
|
||||
|
||||
bl_options = {'UNDO', 'INTERNAL'}
|
||||
|
||||
data_type: EnumProperty(
|
||||
name="Type",
|
||||
items=(
|
||||
('OBJECT', "Objects", ""),
|
||||
('MATERIAL', "Materials", ""),
|
||||
None,
|
||||
# Enum identifiers are compared with 'object.type'.
|
||||
('MESH', "Meshes", ""),
|
||||
('CURVE', "Curves", ""),
|
||||
('META', "Meta Balls", ""),
|
||||
('ARMATURE', "Armatures", ""),
|
||||
('LATTICE', "Lattices", ""),
|
||||
('GPENCIL', "Grease Pencils", ""),
|
||||
('CAMERA', "Cameras", ""),
|
||||
('SPEAKER', "Speakers", ""),
|
||||
('LIGHT_PROBE', "Light Probes", ""),
|
||||
None,
|
||||
('BONE', "Bones", ""),
|
||||
('NODE', "Nodes", ""),
|
||||
('SEQUENCE_STRIP', "Sequence Strips", ""),
|
||||
),
|
||||
description="Type of data to rename",
|
||||
)
|
||||
|
||||
data_source: EnumProperty(
|
||||
name="Source",
|
||||
items=(
|
||||
('SELECT', "Selected", ""),
|
||||
('ALL', "All", ""),
|
||||
),
|
||||
)
|
||||
|
||||
actions: CollectionProperty(type=BatchRenameAction)
|
||||
|
||||
@staticmethod
|
||||
def _data_from_context(context, data_type, only_selected, check_context=False):
|
||||
|
||||
mode = context.mode
|
||||
scene = context.scene
|
||||
space = context.space_data
|
||||
space_type = None if (space is None) else space.type
|
||||
|
||||
data = None
|
||||
if space_type == 'SEQUENCE_EDITOR':
|
||||
data_type_test = 'SEQUENCE_STRIP'
|
||||
if check_context:
|
||||
return data_type_test
|
||||
if data_type == data_type_test:
|
||||
data = (
|
||||
# TODO, we don't have access to seqbasep, this won't work when inside metas.
|
||||
[seq for seq in context.scene.sequence_editor.sequences_all if seq.select]
|
||||
if only_selected else
|
||||
context.scene.sequence_editor.sequences_all,
|
||||
"name",
|
||||
"Strip(s)",
|
||||
)
|
||||
elif space_type == 'NODE_EDITOR':
|
||||
data_type_test = 'NODE'
|
||||
if check_context:
|
||||
return data_type_test
|
||||
if data_type == data_type_test:
|
||||
data = (
|
||||
context.selected_nodes
|
||||
if only_selected else
|
||||
list(space.node_tree.nodes),
|
||||
"name",
|
||||
"Node(s)",
|
||||
)
|
||||
else:
|
||||
if mode == 'POSE' or (mode == 'WEIGHT_PAINT' and context.pose_object):
|
||||
data_type_test = 'BONE'
|
||||
if check_context:
|
||||
return data_type_test
|
||||
if data_type == data_type_test:
|
||||
data = (
|
||||
[pchan.bone for pchan in context.selected_pose_bones]
|
||||
if only_selected else
|
||||
[pchan.bone for ob in context.objects_in_mode_unique_data for pbone in ob.pose.bones],
|
||||
"name",
|
||||
"Bone(s)",
|
||||
)
|
||||
elif mode == 'EDIT_ARMATURE':
|
||||
data_type_test = 'BONE'
|
||||
if check_context:
|
||||
return data_type_test
|
||||
if data_type == data_type_test:
|
||||
data = (
|
||||
context.selected_editable_bones
|
||||
if only_selected else
|
||||
[ebone for ob in context.objects_in_mode_unique_data for ebone in ob.data.edit_bones],
|
||||
"name",
|
||||
"Edit Bone(s)",
|
||||
)
|
||||
|
||||
if check_context:
|
||||
return 'OBJECT'
|
||||
|
||||
object_data_type_attrs_map = {
|
||||
'MESH': ("meshes", "Mesh(es)"),
|
||||
'CURVE': ("curves", "Curve(s)"),
|
||||
'META': ("metaballs", "MetaBall(s)"),
|
||||
'ARMATURE': ("armatures", "Armature(s)"),
|
||||
'LATTICE': ("lattices", "Lattice(s)"),
|
||||
'GPENCIL': ("grease_pencils", "Grease Pencil(s)"),
|
||||
'CAMERA': ("cameras", "Camera(s)"),
|
||||
'SPEAKER': ("speakers", "Speaker(s)"),
|
||||
'LIGHT_PROBE': ("light_probes", "LightProbe(s)"),
|
||||
}
|
||||
|
||||
# Finish with space types.
|
||||
if data is None:
|
||||
|
||||
if data_type == 'OBJECT':
|
||||
data = (
|
||||
context.selected_editable_objects
|
||||
if only_selected else
|
||||
[id for id in bpy.data.objects if id.library is None],
|
||||
"name",
|
||||
"Object(s)",
|
||||
)
|
||||
elif data_type == 'MATERIAL':
|
||||
data = (
|
||||
tuple(set(
|
||||
slot.material
|
||||
for ob in context.selected_objects
|
||||
for slot in ob.material_slots
|
||||
if slot.material is not None
|
||||
))
|
||||
if only_selected else
|
||||
[id for id in bpy.data.materials if id.library is None],
|
||||
"name",
|
||||
"Material(s)",
|
||||
)
|
||||
elif data_type in object_data_type_attrs_map.keys():
|
||||
attr, descr = object_data_type_attrs_map[data_type]
|
||||
data = (
|
||||
tuple(set(
|
||||
id
|
||||
for ob in context.selected_objects
|
||||
if ob.type == data_type
|
||||
for id in (ob.data,)
|
||||
if id is not None and id.library is None
|
||||
))
|
||||
if only_selected else
|
||||
[id for id in getattr(bpy.data, attr) if id.library is None],
|
||||
"name",
|
||||
descr,
|
||||
)
|
||||
|
||||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def _apply_actions(actions, name):
|
||||
import string
|
||||
import re
|
||||
|
||||
for action in actions:
|
||||
ty = action.type
|
||||
if ty == 'SET':
|
||||
text = action.set_name
|
||||
method = action.set_method
|
||||
if method == 'NEW':
|
||||
name = text
|
||||
elif method == 'PREFIX':
|
||||
name = text + name
|
||||
elif method == 'SUFFIX':
|
||||
name = name + text
|
||||
else:
|
||||
assert(0)
|
||||
|
||||
elif ty == 'STRIP':
|
||||
chars = action.strip_chars
|
||||
chars_strip = (
|
||||
"{:s}{:s}{:s}"
|
||||
).format(
|
||||
string.punctuation if 'PUNCT' in chars else "",
|
||||
string.digits if 'DIGIT' in chars else "",
|
||||
" " if 'SPACE' in chars else "",
|
||||
)
|
||||
part = action.strip_part
|
||||
if 'START' in part:
|
||||
name = name.lstrip(chars_strip)
|
||||
if 'END' in part:
|
||||
name = name.rstrip(chars_strip)
|
||||
|
||||
elif ty == 'REPLACE':
|
||||
if action.replace_regex:
|
||||
replace_src = action.replace_src
|
||||
else:
|
||||
replace_src = re.escape(action.replace_src)
|
||||
name = re.sub(
|
||||
replace_src,
|
||||
re.escape(action.replace_dst),
|
||||
name,
|
||||
flags=(
|
||||
0 if action.replace_match_case else
|
||||
re.IGNORECASE
|
||||
),
|
||||
)
|
||||
elif ty == 'CASE':
|
||||
method = action.case_method
|
||||
if method == 'UPPER':
|
||||
name = name.upper()
|
||||
elif method == 'LOWER':
|
||||
name = name.lower()
|
||||
elif method == 'TITLE':
|
||||
name = name.title()
|
||||
else:
|
||||
assert(0)
|
||||
else:
|
||||
assert(0)
|
||||
return name
|
||||
|
||||
def _data_update(self, context):
|
||||
only_selected = self.data_source == 'SELECT'
|
||||
|
||||
self._data = self._data_from_context(context, self.data_type, only_selected)
|
||||
if self._data is None:
|
||||
self.data_type = self._data_from_context(context, None, False, check_context=True)
|
||||
self._data = self._data_from_context(context, self.data_type, only_selected)
|
||||
|
||||
self._data_source_prev = self.data_source
|
||||
self._data_type_prev = self.data_type
|
||||
|
||||
def draw(self, context):
|
||||
import re
|
||||
|
||||
layout = self.layout
|
||||
|
||||
split = layout.split(factor=0.5)
|
||||
split.label(text="Data Type:")
|
||||
split.prop(self, "data_type", text="")
|
||||
|
||||
split = layout.split(factor=0.5)
|
||||
split.label(text="Rename {:d} {:s}:".format(len(self._data[0]), self._data[2]))
|
||||
split.row().prop(self, "data_source", expand=True)
|
||||
|
||||
for action in self.actions:
|
||||
box = layout.box()
|
||||
|
||||
row = box.row(align=True)
|
||||
row.prop(action, "type", text="")
|
||||
row.prop(action, "op_add", text="", icon='ADD')
|
||||
row.prop(action, "op_remove", text="", icon='REMOVE')
|
||||
|
||||
ty = action.type
|
||||
if ty == 'SET':
|
||||
box.prop(action, "set_method")
|
||||
box.prop(action, "set_name")
|
||||
elif ty == 'STRIP':
|
||||
box.row().prop(action, "strip_chars")
|
||||
box.row().prop(action, "strip_part")
|
||||
elif ty == 'REPLACE':
|
||||
|
||||
row = box.row()
|
||||
re_error = None
|
||||
if action.replace_regex:
|
||||
try:
|
||||
re.compile(action.replace_src)
|
||||
except Exception as ex:
|
||||
row.alert = True
|
||||
re_error = str(ex)
|
||||
row.prop(action, "replace_src")
|
||||
if re_error is not None:
|
||||
box.label(text=re_error)
|
||||
|
||||
box.row().prop(action, "replace_dst")
|
||||
row = box.row()
|
||||
row.prop(action, "replace_match_case")
|
||||
row.prop(action, "replace_regex")
|
||||
elif ty == 'CASE':
|
||||
box.row().prop(action, "case_method", expand=True)
|
||||
|
||||
def check(self, context):
|
||||
changed = False
|
||||
for i, action in enumerate(self.actions):
|
||||
if action.op_add:
|
||||
action.op_add = False
|
||||
self.actions.add()
|
||||
if i + 2 != len(self.actions):
|
||||
self.actions.move(len(self.actions) - 1, i + 1)
|
||||
changed = True
|
||||
break
|
||||
if action.op_remove:
|
||||
action.op_remove = False
|
||||
if len(self.actions) > 1:
|
||||
self.actions.remove(i)
|
||||
changed = True
|
||||
break
|
||||
|
||||
if (
|
||||
(self._data_source_prev != self.data_source) or
|
||||
(self._data_type_prev != self.data_type)
|
||||
):
|
||||
self._data_update(context)
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
def execute(self, context):
|
||||
import re
|
||||
|
||||
seq, attr, descr = self._data
|
||||
|
||||
actions = self.actions
|
||||
|
||||
# Sanitize actions.
|
||||
for action in actions:
|
||||
if action.replace_regex:
|
||||
try:
|
||||
re.compile(action.replace_src)
|
||||
except Exception as ex:
|
||||
self.report({'ERROR'}, "Invalid regular expression: " + str(ex))
|
||||
return {'CANCELLED'}
|
||||
|
||||
total_len = 0
|
||||
change_len = 0
|
||||
for item in seq:
|
||||
name_src = getattr(item, attr)
|
||||
name_dst = self._apply_actions(actions, name_src)
|
||||
if name_src != name_dst:
|
||||
setattr(item, attr, name_dst)
|
||||
change_len += 1
|
||||
total_len += 1
|
||||
|
||||
self.report({'INFO'}, "Renamed {:d} of {:d} {:s}".format(total_len, change_len, descr))
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
|
||||
self._data_update(context)
|
||||
|
||||
if not self.actions:
|
||||
self.actions.add()
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self, width=400)
|
||||
|
||||
|
||||
class WM_MT_splash(Menu):
|
||||
bl_label = "Splash"
|
||||
|
||||
@@ -2398,7 +1979,5 @@ classes = (
|
||||
WM_OT_tool_set_by_id,
|
||||
WM_OT_tool_set_by_index,
|
||||
WM_OT_toolbar,
|
||||
BatchRenameAction,
|
||||
WM_OT_batch_rename,
|
||||
WM_MT_splash,
|
||||
)
|
||||
|
@@ -370,8 +370,6 @@ class ConstraintButtonsPanel:
|
||||
def COPY_ROTATION(self, _context, layout, con):
|
||||
self.target_template(layout, con)
|
||||
|
||||
layout.prop(con, "euler_order", text="Order")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
@@ -687,9 +685,6 @@ class ConstraintButtonsPanel:
|
||||
col.row().label(text="Source:")
|
||||
col.row().prop(con, "map_from", expand=True)
|
||||
|
||||
if con.map_from == 'ROTATION':
|
||||
layout.prop(con, "from_rotation_mode", text="Mode")
|
||||
|
||||
split = layout.split()
|
||||
ext = "" if con.map_from == 'LOCATION' else "_rot" if con.map_from == 'ROTATION' else "_scale"
|
||||
|
||||
@@ -732,9 +727,6 @@ class ConstraintButtonsPanel:
|
||||
col.label(text="Destination:")
|
||||
col.row().prop(con, "map_to", expand=True)
|
||||
|
||||
if con.map_to == 'ROTATION':
|
||||
layout.prop(con, "to_euler_order", text="Order")
|
||||
|
||||
split = layout.split()
|
||||
ext = "" if con.map_to == 'LOCATION' else "_rot" if con.map_to == 'ROTATION' else "_scale"
|
||||
|
||||
|
@@ -60,7 +60,6 @@ class DATA_PT_empty(DataButtonsPanel, Panel):
|
||||
col.row().prop(ob, "empty_image_side", text="Side", expand=True)
|
||||
col.prop(ob, "show_empty_image_orthographic", text="Display Orthographic")
|
||||
col.prop(ob, "show_empty_image_perspective", text="Display Perspective")
|
||||
col.prop(ob, "show_empty_image_only_axis_aligned")
|
||||
|
||||
|
||||
class DATA_PT_empty_image(DataButtonsPanel, Panel):
|
||||
|
@@ -2012,19 +2012,15 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
|
||||
col.prop(md, "factor")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(md, "opacity_mode", text="Mode")
|
||||
row.prop(md, "create_materials")
|
||||
row.prop(md, "modify_color")
|
||||
|
||||
if md.opacity_mode == 'MATERIAL':
|
||||
row = layout.row()
|
||||
row.prop(md, "create_materials")
|
||||
row.prop(md, "modify_color", text="Change")
|
||||
else:
|
||||
col = layout.column()
|
||||
col.separator()
|
||||
col.label(text="Vertex Group:")
|
||||
row = col.row(align=True)
|
||||
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
|
||||
row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
|
||||
col = layout.column()
|
||||
col.separator()
|
||||
col.label(text="Vertex Group:")
|
||||
row = col.row(align=True)
|
||||
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
|
||||
row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
|
||||
|
||||
col = layout.column()
|
||||
col.separator()
|
||||
|
@@ -892,8 +892,7 @@ class GreasePencilMaterialsPanel:
|
||||
if is_view3d and brush is not None:
|
||||
gp_settings = brush.gpencil_settings
|
||||
if gp_settings.use_material_pin is False:
|
||||
if ob.active_material_index > 0:
|
||||
ma = ob.material_slots[ob.active_material_index].material
|
||||
ma = ob.material_slots[ob.active_material_index].material
|
||||
else:
|
||||
ma = gp_settings.material
|
||||
|
||||
|
@@ -1196,7 +1196,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
|
||||
row = layout.row()
|
||||
row.prop(rule, "use_line")
|
||||
sub = row.row()
|
||||
sub.active = rule.use_line
|
||||
sub.active = rule.line
|
||||
sub.prop(rule, "queue_count")
|
||||
elif rule.type == 'AVERAGE_SPEED':
|
||||
row.prop(rule, "speed", slider=True)
|
||||
|
@@ -34,131 +34,58 @@ class FILEBROWSER_HT_header(Header):
|
||||
|
||||
layout.menu("FILEBROWSER_MT_view")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("file.previous", text="", icon='BACK')
|
||||
row.operator("file.next", text="", icon='FORWARD')
|
||||
row.operator("file.parent", text="", icon='FILE_PARENT')
|
||||
row.operator("file.refresh", text="", icon='FILE_REFRESH')
|
||||
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
layout.operator("file.directory_new", icon='NEWFOLDER', text="")
|
||||
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
|
||||
# can be None when save/reload with a file selector open
|
||||
if params:
|
||||
is_lib_browser = params.use_library_browsing
|
||||
|
||||
layout.prop(params, "display_type", expand=True, text="")
|
||||
layout.prop(params, "sort_method", expand=True, text="")
|
||||
layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN')
|
||||
|
||||
layout.separator_spacer()
|
||||
|
||||
layout.template_running_jobs()
|
||||
|
||||
if params:
|
||||
layout.prop(params, "use_filter", text="", icon='FILTER')
|
||||
|
||||
class FILEBROWSER_PT_display(Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Display"
|
||||
row = layout.row(align=True)
|
||||
row.active = params.use_filter
|
||||
row.prop(params, "use_filter_folder", text="")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# can be None when save/reload with a file selector open
|
||||
return context.space_data.params is not None
|
||||
if params.filter_glob:
|
||||
# if st.active_operator and hasattr(st.active_operator, "filter_glob"):
|
||||
# row.prop(params, "filter_glob", text="")
|
||||
row.label(text=params.filter_glob)
|
||||
else:
|
||||
row.prop(params, "use_filter_blender", text="")
|
||||
row.prop(params, "use_filter_backup", text="")
|
||||
row.prop(params, "use_filter_image", text="")
|
||||
row.prop(params, "use_filter_movie", text="")
|
||||
row.prop(params, "use_filter_script", text="")
|
||||
row.prop(params, "use_filter_font", text="")
|
||||
row.prop(params, "use_filter_sound", text="")
|
||||
row.prop(params, "use_filter_text", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
if is_lib_browser:
|
||||
row.prop(params, "use_filter_blendid", text="")
|
||||
if params.use_filter_blendid:
|
||||
row.separator()
|
||||
row.prop(params, "filter_id_category", text="")
|
||||
|
||||
space = context.space_data
|
||||
params = space.params
|
||||
is_lib_browser = params.use_library_browsing
|
||||
|
||||
layout.label(text="Display as")
|
||||
layout.column().prop(params, "display_type", expand=True)
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
if params.display_type == 'THUMBNAIL':
|
||||
layout.prop(params, "display_size", text="Size")
|
||||
else:
|
||||
layout.prop(params, "show_details_size", text="Size")
|
||||
layout.prop(params, "show_details_datetime", text="Date")
|
||||
|
||||
layout.prop(params, "recursion_level", text="Recursions")
|
||||
|
||||
layout.use_property_split = False
|
||||
layout.separator()
|
||||
|
||||
layout.label(text="Sort by")
|
||||
layout.column().prop(params, "sort_method", expand=True)
|
||||
layout.prop(params, "use_sort_invert")
|
||||
|
||||
|
||||
class FILEBROWSER_PT_filter(Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Filter"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# can be None when save/reload with a file selector open
|
||||
return context.space_data.params is not None
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
space = context.space_data
|
||||
params = space.params
|
||||
is_lib_browser = params.use_library_browsing
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(params, "use_filter", text="", toggle=0)
|
||||
row.label(text="Filter")
|
||||
|
||||
col = layout.column()
|
||||
col.active = params.use_filter
|
||||
|
||||
row = col.row()
|
||||
row.label(icon='FILE_FOLDER')
|
||||
row.prop(params, "use_filter_folder", text="Folders", toggle=0)
|
||||
|
||||
if params.filter_glob:
|
||||
col.label(text=params.filter_glob)
|
||||
else:
|
||||
row = col.row()
|
||||
row.label(icon='FILE_BLEND')
|
||||
row.prop(params, "use_filter_blender",
|
||||
text=".blend Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_BACKUP')
|
||||
row.prop(params, "use_filter_backup",
|
||||
text="Backup .blend Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_IMAGE')
|
||||
row.prop(params, "use_filter_image", text="Image Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_MOVIE')
|
||||
row.prop(params, "use_filter_movie", text="Movie Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_SCRIPT')
|
||||
row.prop(params, "use_filter_script",
|
||||
text="Script Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_FONT')
|
||||
row.prop(params, "use_filter_font", text="Font Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_SOUND')
|
||||
row.prop(params, "use_filter_sound", text="Sound Files", toggle=0)
|
||||
row = col.row()
|
||||
row.label(icon='FILE_TEXT')
|
||||
row.prop(params, "use_filter_text", text="Text Files", toggle=0)
|
||||
|
||||
col.separator()
|
||||
|
||||
if is_lib_browser:
|
||||
row = col.row()
|
||||
row.label(icon='BLANK1') # Indentation
|
||||
row.prop(params, "use_filter_blendid",
|
||||
text="Blender IDs", toggle=0)
|
||||
if params.use_filter_blendid:
|
||||
row = col.row()
|
||||
row.label(icon='BLANK1') # Indentation
|
||||
row.prop(params, "filter_id_category", text="")
|
||||
|
||||
col.separator()
|
||||
|
||||
layout.prop(params, "show_hidden")
|
||||
|
||||
|
||||
def panel_poll_is_upper_region(region):
|
||||
# The upper region is left-aligned, the lower is split into it then.
|
||||
return region.alignment == 'LEFT'
|
||||
row.separator()
|
||||
row.prop(params, "filter_search", text="", icon='VIEWZOOM')
|
||||
|
||||
|
||||
class FILEBROWSER_UL_dir(UIList):
|
||||
@@ -192,13 +119,10 @@ class FILEBROWSER_UL_dir(UIList):
|
||||
class FILEBROWSER_PT_bookmarks_volumes(Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'TOOLS'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_category = "Bookmarks"
|
||||
bl_label = "Volumes"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return panel_poll_is_upper_region(context.region)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
space = context.space_data
|
||||
@@ -217,7 +141,7 @@ class FILEBROWSER_PT_bookmarks_system(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region)
|
||||
return not context.preferences.filepaths.hide_system_bookmarks
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -237,10 +161,8 @@ class FILEBROWSER_MT_bookmarks_context_menu(Menu):
|
||||
layout.operator("file.bookmark_cleanup", icon='X', text="Cleanup")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("file.bookmark_move", icon='TRIA_UP_BAR',
|
||||
text="Move To Top").direction = 'TOP'
|
||||
layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR',
|
||||
text="Move To Bottom").direction = 'BOTTOM'
|
||||
layout.operator("file.bookmark_move", icon='TRIA_UP_BAR', text="Move To Top").direction = 'TOP'
|
||||
layout.operator("file.bookmark_move", icon='TRIA_DOWN_BAR', text="Move To Bottom").direction = 'BOTTOM'
|
||||
|
||||
|
||||
class FILEBROWSER_PT_bookmarks_favorites(Panel):
|
||||
@@ -249,10 +171,6 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
|
||||
bl_category = "Bookmarks"
|
||||
bl_label = "Favorites"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return panel_poll_is_upper_region(context.region)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
space = context.space_data
|
||||
@@ -267,15 +185,12 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
|
||||
col = row.column(align=True)
|
||||
col.operator("file.bookmark_add", icon='ADD', text="")
|
||||
col.operator("file.bookmark_delete", icon='REMOVE', text="")
|
||||
col.menu("FILEBROWSER_MT_bookmarks_context_menu",
|
||||
icon='DOWNARROW_HLT', text="")
|
||||
col.menu("FILEBROWSER_MT_bookmarks_context_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
if num_rows > 1:
|
||||
col.separator()
|
||||
col.operator("file.bookmark_move", icon='TRIA_UP',
|
||||
text="").direction = 'UP'
|
||||
col.operator("file.bookmark_move", icon='TRIA_DOWN',
|
||||
text="").direction = 'DOWN'
|
||||
col.operator("file.bookmark_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("file.bookmark_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
else:
|
||||
layout.operator("file.bookmark_add", icon='ADD')
|
||||
|
||||
@@ -288,7 +203,7 @@ class FILEBROWSER_PT_bookmarks_recents(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region)
|
||||
return not context.preferences.filepaths.hide_recent_locations
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -312,7 +227,7 @@ class FILEBROWSER_PT_advanced_filter(Panel):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
# only useful in append/link (library) context currently...
|
||||
return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region)
|
||||
return context.space_data.params.use_library_browsing
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -327,133 +242,6 @@ class FILEBROWSER_PT_advanced_filter(Panel):
|
||||
col.prop(params, "filter_id")
|
||||
|
||||
|
||||
class FILEBROWSER_PT_options_toggle(Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'TOOLS'
|
||||
bl_label = "Options Toggle"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
sfile = context.space_data
|
||||
return context.region.alignment == 'BOTTOM' and sfile.active_operator
|
||||
|
||||
def is_option_region_visible(self, context):
|
||||
for region in context.area.regions:
|
||||
if region.type == 'TOOL_PROPS' and region.width <= 1:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
label = "Hide Options" if self.is_option_region_visible(
|
||||
context) else "Options"
|
||||
|
||||
layout.scale_x = 1.3
|
||||
layout.scale_y = 1.3
|
||||
|
||||
layout.operator("screen.region_toggle",
|
||||
text=label).region_type = 'TOOL_PROPS'
|
||||
|
||||
|
||||
class FILEBROWSER_PT_directory_path(Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "Directory Path"
|
||||
bl_category = "Attributes"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
||||
def is_header_visible(self, context):
|
||||
for region in context.area.regions:
|
||||
if region.type == 'HEADER' and region.height <= 1:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
space = context.space_data
|
||||
params = space.params
|
||||
|
||||
layout.scale_x = 1.3
|
||||
layout.scale_y = 1.3
|
||||
|
||||
row = layout.row()
|
||||
|
||||
subrow = row.row(align=True)
|
||||
subrow.operator("file.previous", text="", icon='BACK')
|
||||
subrow.operator("file.next", text="", icon='FORWARD')
|
||||
subrow.operator("file.parent", text="", icon='FILE_PARENT')
|
||||
subrow.operator("file.refresh", text="", icon='FILE_REFRESH')
|
||||
|
||||
row.operator("file.directory_new", icon='NEWFOLDER', text="")
|
||||
|
||||
subrow = row.row()
|
||||
subrow.prop(params, "directory", text="")
|
||||
|
||||
subrow = row.row()
|
||||
subrow.scale_x = 0.5
|
||||
subrow.prop(params, "filter_search", text="", icon='VIEWZOOM')
|
||||
|
||||
# Uses prop_with_popover() as popover() only adds the triangle icon in headers.
|
||||
row.prop_with_popover(
|
||||
params,
|
||||
"display_type",
|
||||
panel="FILEBROWSER_PT_display",
|
||||
text="",
|
||||
icon_only=True,
|
||||
)
|
||||
row.prop_with_popover(
|
||||
params,
|
||||
"display_type",
|
||||
panel="FILEBROWSER_PT_filter",
|
||||
text="",
|
||||
icon='FILTER',
|
||||
icon_only=True,
|
||||
)
|
||||
|
||||
|
||||
class FILEBROWSER_PT_file_operation(Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'EXECUTE'
|
||||
bl_label = "Execute File Operation"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.space_data.active_operator
|
||||
|
||||
def draw(self, context):
|
||||
import sys
|
||||
|
||||
layout = self.layout
|
||||
space = context.space_data
|
||||
params = space.params
|
||||
|
||||
layout.scale_x = 1.3
|
||||
layout.scale_y = 1.3
|
||||
|
||||
row = layout.row()
|
||||
sub = row.row()
|
||||
sub.prop(params, "filename", text="")
|
||||
sub = row.row()
|
||||
sub.ui_units_x = 5
|
||||
|
||||
# subsub = sub.row(align=True)
|
||||
# subsub.operator("file.filenum", text="", icon='ADD').increment = 1
|
||||
# subsub.operator("file.filenum", text="", icon='REMOVE').increment = -1
|
||||
|
||||
# organize buttons according to the OS standard
|
||||
if sys.platform != "win":
|
||||
sub.operator("FILE_OT_cancel", text="Cancel")
|
||||
subsub = sub.row()
|
||||
subsub.active_default = True
|
||||
subsub.operator("FILE_OT_execute", text=params.title)
|
||||
if sys.platform == "win":
|
||||
sub.operator("FILE_OT_cancel", text="Cancel")
|
||||
|
||||
|
||||
class FILEBROWSER_MT_view(Menu):
|
||||
bl_label = "View"
|
||||
|
||||
@@ -462,7 +250,7 @@ class FILEBROWSER_MT_view(Menu):
|
||||
st = context.space_data
|
||||
params = st.params
|
||||
|
||||
layout.prop(st, "show_region_toolbar", text="Source List")
|
||||
layout.prop(st, "show_region_toolbar")
|
||||
layout.prop(st, "show_region_ui", text="File Path")
|
||||
|
||||
layout.separator()
|
||||
@@ -475,46 +263,8 @@ class FILEBROWSER_MT_view(Menu):
|
||||
layout.menu("INFO_MT_area")
|
||||
|
||||
|
||||
class FILEBROWSER_MT_context_menu(Menu):
|
||||
bl_label = "Files Context Menu"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
st = context.space_data
|
||||
params = st.params
|
||||
|
||||
layout.operator("file.previous", text="Back")
|
||||
layout.operator("file.next", text="Forward")
|
||||
layout.operator("file.parent", text="Go to Parent")
|
||||
layout.operator("file.refresh", text="Refresh")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("file.filenum", text="Increase Number",
|
||||
icon='ADD').increment = 1
|
||||
layout.operator("file.filenum", text="Decrease Number",
|
||||
icon='REMOVE').increment = -1
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("file.rename", text="Rename")
|
||||
# layout.operator("file.delete")
|
||||
layout.operator("file.directory_new", text="New Folder")
|
||||
layout.operator("file.bookmark_add", text="Add Bookmark")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.prop_menu_enum(params, "display_type")
|
||||
if params.display_type == 'THUMBNAIL':
|
||||
layout.prop_menu_enum(params, "display_size")
|
||||
layout.prop_menu_enum(params, "recursion_level", text="Recursions")
|
||||
layout.prop_menu_enum(params, "sort_method")
|
||||
|
||||
|
||||
classes = (
|
||||
FILEBROWSER_HT_header,
|
||||
FILEBROWSER_PT_display,
|
||||
FILEBROWSER_PT_filter,
|
||||
FILEBROWSER_UL_dir,
|
||||
FILEBROWSER_PT_bookmarks_volumes,
|
||||
FILEBROWSER_PT_bookmarks_system,
|
||||
@@ -522,11 +272,7 @@ classes = (
|
||||
FILEBROWSER_PT_bookmarks_favorites,
|
||||
FILEBROWSER_PT_bookmarks_recents,
|
||||
FILEBROWSER_PT_advanced_filter,
|
||||
FILEBROWSER_PT_directory_path,
|
||||
FILEBROWSER_PT_file_operation,
|
||||
FILEBROWSER_PT_options_toggle,
|
||||
FILEBROWSER_MT_view,
|
||||
FILEBROWSER_MT_context_menu,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
@@ -1467,7 +1467,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text="End")
|
||||
split = split.split(factor=0.8 + max_factor, align=True)
|
||||
split.label(text="{:>14}".format(smpte_from_frame(frame_final_end)))
|
||||
split.label(text="{:>14}".format(smpte_from_frame(frame_final_end) + ":"))
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text=str(frame_final_end) + " ")
|
||||
|
||||
@@ -1511,7 +1511,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
|
||||
split.label(text="Playhead")
|
||||
split = split.split(factor=0.8 + max_factor, align=True)
|
||||
playhead = frame_current - frame_final_start
|
||||
split.label(text="{:>14}".format(smpte_from_frame(playhead)))
|
||||
split.label(text="{:>14}".format(smpte_from_frame(playhead) + ":"))
|
||||
split.alignment = 'RIGHT'
|
||||
split.label(text=str(playhead) + " ")
|
||||
|
||||
|
@@ -349,7 +349,7 @@ class TOPBAR_MT_app_about(Menu):
|
||||
layout.separator()
|
||||
|
||||
layout.operator("wm.url_open_preset", text="Blender Website", icon='URL').type = 'BLENDER'
|
||||
layout.operator("wm.url_open_preset", text="Credits", icon='URL').type = 'CREDITS'
|
||||
layout.operator("wm.url_open", text="Credits", icon='URL').type = 'CREDITS'
|
||||
|
||||
layout.separator()
|
||||
|
||||
@@ -505,8 +505,6 @@ class TOPBAR_MT_edit(Menu):
|
||||
props.name = "TOPBAR_PT_name"
|
||||
props.keep_open = False
|
||||
|
||||
layout.operator("wm.batch_rename")
|
||||
|
||||
layout.separator()
|
||||
|
||||
# Should move elsewhere (impacts outliner & 3D view).
|
||||
|
@@ -2333,7 +2333,6 @@ class VIEW3D_MT_object_context_menu(Menu):
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.convert", text="Convert to Mesh").target = 'MESH'
|
||||
layout.operator("object.convert", text="Convert to Grease Pencil").target = 'GPENCIL'
|
||||
layout.operator_menu_enum("object.origin_set", text="Set Origin", property="type")
|
||||
|
||||
layout.separator()
|
||||
@@ -6372,7 +6371,7 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
|
||||
col.separator()
|
||||
|
||||
# Layer and Materials operators
|
||||
col.menu("GPENCIL_MT_move_to_layer")
|
||||
col.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
|
||||
col.menu("VIEW3D_MT_assign_material")
|
||||
col.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes")
|
||||
|
||||
|
@@ -364,11 +364,6 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
|
||||
if not self.is_popover:
|
||||
brush_basic_sculpt_settings(col, context, brush)
|
||||
|
||||
# normal_radius_factor
|
||||
col.separator()
|
||||
row = col.row()
|
||||
row.prop(brush, "normal_radius_factor", slider=True)
|
||||
|
||||
# topology_rake_factor
|
||||
if (
|
||||
capabilities.has_topology_rake and
|
||||
|
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": { }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user