Merge branch '86Box:master' into nec-v20

This commit is contained in:
Jasmine Iwanek
2022-05-03 17:17:48 -04:00
committed by GitHub
31 changed files with 2518 additions and 100 deletions

View File

@@ -8,6 +8,15 @@
#
# Recipe file for appimage-builder.
#
# build.sh processes conditional comments based on CMakeCache
# options at the end of each line. For example, a line ending in:
#
# # if QT:BOOL=ON
#
# will be removed from the dynamically-generated copy of this
# file if "QT" is not a boolean option set to ON, either through
# a -D definition or the option's default value in CMakeLists.
#
#
# Authors: RichardG, <richardg867@gmail.com>
#
@@ -18,7 +27,7 @@ version: 1
AppDir:
path: ./archive_tmp
app_info:
id: !ENV 'net.${project_lower}.${project}'
id: !ENV '${project_id}'
name: !ENV '${project}'
icon: !ENV '${project_icon}'
version: !ENV '${project_version}'
@@ -34,29 +43,31 @@ AppDir:
- sourceline: 'deb http://deb.debian.org/debian bullseye-updates main'
key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xac530d520f2f3269f5e98313a48449044aad5c5d'
include:
- libevdev2
- libedit2 # if (CLI:BOOL=ON|QT:BOOL=OFF)
- libevdev2 # if QT:BOOL=ON
- libfluidsynth2
- libfreetype6
- libgbm1
- libgl1
- libgles2
- libglvnd0
- libglx0
- libgbm1 # if QT:BOOL=ON
- libgl1 # if QT:BOOL=ON
- libgles2 # if QT:BOOL=ON
- libglvnd0 # if QT:BOOL=ON
- libglx0 # if QT:BOOL=ON
- libgs9
- libpng16-16
- libqt5core5a
- libqt5gui5
- libqt5widgets5
- libslirp0
- libsndio7.0
- libwayland-client0
- libx11-6
- libx11-xcb1
- libxcb1
- libxcb-render0
- libxcb-shape0
- libxcb-shm0
- libxcb-xfixes0
- libqt5core5a # if QT:BOOL=ON
- libqt5gui5 # if QT:BOOL=ON
- libqt5widgets5 # if QT:BOOL=ON
- libsixel1 # if CLI:BOOL=ON
- libslirp0 # if SLIRP_EXTERNAL:BOOL=ON
- libsndio7.0 # if OPENAL:BOOL=ON
- libwayland-client0 # if QT:BOOL=ON
- libx11-6 # if QT:BOOL=ON
- libx11-xcb1 # if QT:BOOL=ON
- libxcb1 # if QT:BOOL=ON
- libxcb-render0 # if QT:BOOL=ON
- libxcb-shape0 # if QT:BOOL=ON
- libxcb-shm0 # if QT:BOOL=ON
- libxcb-xfixes0 # if QT:BOOL=ON
- zlib1g
files:
exclude:
@@ -69,8 +80,11 @@ AppDir:
- usr/lib/cmake
- usr/lib/pkgconfig
- usr/s[a-gi-zA-Z]*
- usr/share/[a-hj-zA-Z]*
- usr/share/[a-hj-ln-zA-Z]*
- usr/share/i[a-bd-zA-Z]*
- usr/share/m[a-df-zA-Z]*
- usr/share/metainfo/*.metainfo.xml
- var
AppImage:
arch: !ENV '${arch_appimage}'
file_name: '-n' # nasty hack to disable metainfo validation

8
.ci/Jenkinsfile vendored
View File

@@ -25,7 +25,7 @@ def buildBranch = env.JOB_BASE_NAME.contains('-') ? 1 : 0
def osArchs = [
'Windows': ['32', '64'],
'Linux': ['x86', 'x86_64', 'arm32', 'arm64'],
'macOS': ['x86_64']
'macOS': ['x86_64+arm64']
]
def osFlags = [
@@ -45,7 +45,8 @@ def archNames = [
def archNamesMac = [
'x86_64': 'Intel',
'arm64': 'Apple Silicon'
'arm64': 'Apple Silicon',
'x86_64+arm64': 'Universal (Intel and Apple Silicon)'
]
def dynarecNames = [
@@ -60,7 +61,8 @@ def dynarecArchs = [
'64': ['ODR', 'NDR'],
'x86_64': ['ODR', 'NDR'],
'arm32': ['NDR'],
'arm64': ['NDR']
'arm64': ['NDR'],
'x86_64+arm64': ['ODR', 'NDR']
]
def dynarecFlags = [

View File

@@ -20,6 +20,7 @@
# to produce Jenkins-like builds on your local machine by following these notes:
#
# - Run build.sh without parameters to see its usage
# - Any boolean CMake definitions (-D ...=ON/OFF) must be ON or OFF to ensure correct behavior
# - For Windows (MSYS MinGW) builds:
# - Packaging requires 7-Zip on Program Files
# - Packaging the Ghostscript DLL requires 32-bit and/or 64-bit Ghostscript on Program Files
@@ -36,7 +37,9 @@
# build_arch x86_64 (or arm64)
# universal_archs (blank)
# ui_interactive no
# macosx_deployment_target 10.13
# macosx_deployment_target 10.13 (for x86_64, or 11.0 for arm64)
# - For universal building on Apple Silicon hardware, install native MacPorts on the default
# /opt/local and Intel MacPorts on /opt/intel, then tell build.sh to build for "x86_64+arm64"
# - port is called through sudo to manage dependencies; make sure it is configured
# as NOPASSWD in /etc/sudoers if you're doing unattended builds
#
@@ -93,13 +96,13 @@ make_tar() {
# Set common variables.
project=86Box
project_lower=86box
cwd=$(pwd)
# Parse arguments.
package_name=
arch=
tarball_name=
skip_archive=0
strip=0
cmake_flags=
while [ $# -gt 0 ]
@@ -113,6 +116,11 @@ do
shift
;;
-n)
shift
skip_archive=1
;;
-s)
shift
tarball_name="$1"
@@ -211,9 +219,10 @@ then
# Call build with the correct MSYSTEM.
echo [-] Switching to MSYSTEM [$msys]
cd "$cwd"
strip_arg=
[ $strip -ne 0 ] && strip_arg="-t "
CHERE_INVOKING=yes MSYSTEM="$msys" bash -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$strip_arg""$cmake_flags"
args=
[ $strip -ne 0 ] && args="-t $args"
[ $skip_archive -ne 0 ] && args="-n $args"
CHERE_INVOKING=yes MSYSTEM="$msys" bash -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$args""$cmake_flags"
exit $?
fi
else
@@ -330,15 +339,184 @@ then
# macOS lacks nproc, but sysctl can do the same job.
alias nproc='sysctl -n hw.logicalcpu'
# Handle universal build.
if echo "$arch" | grep -q '+'
then
# Create temporary directory for merging app bundles.
rm -rf archive_tmp_universal
mkdir archive_tmp_universal
# Build for each architecture.
merge_src=
for arch_universal in $(echo "$arch" | tr '+' ' ')
do
# Run build for the architecture.
args=
[ $strip -ne 0 ] && args="-t $args"
case $arch_universal in # workaround: force new dynarec on for ARM
arm32 | arm64) cmake_flags_extra="-D NEW_DYNAREC=ON";;
*) cmake_flags_extra=;;
esac
zsh -lc 'exec "'"$0"'" -n -b "universal part" "'"$arch_universal"'" '"$args""$cmake_flags"' '"$cmake_flags_extra"
status=$?
if [ $status -eq 0 ]
then
# Move app bundle to the temporary directory.
app_bundle_name="archive_tmp/$(ls archive_tmp | grep '.app$')"
mv "$app_bundle_name" "archive_tmp_universal/$arch_universal.app"
status=$?
# Merge app bundles.
if [ -z "$merge_src" ]
then
# This is the first bundle, nothing to merge with.
merge_src="$arch_universal"
else
# Merge previous bundle with this one.
merge_dest="$merge_src+$arch_universal"
echo [-] Merging app bundles [$merge_src] and [$arch_universal] into [$merge_dest]
# Merge directory structures.
(cd "archive_tmp_universal/$merge_src.app" && find . -type d && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type d && cd ../..) | sort > universal_listing.txt
cat universal_listing.txt | uniq | while IFS= read line
do
echo "> Directory: $line"
mkdir -p "archive_tmp_universal/$merge_dest.app/$line"
done
# Create merged file listing.
(cd "archive_tmp_universal/$merge_src.app" && find . -type f && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type f && cd ../..) | sort > universal_listing.txt
# Copy files that only exist on one bundle.
cat universal_listing.txt | uniq -u | while IFS= read line
do
if [ -e "archive_tmp_universal/$merge_src.app/$line" ]
then
file_src="$merge_src"
else
file_src="$arch_universal"
fi
echo "> Only on [$file_src]: $line"
cp -p "archive_tmp_universal/$file_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line"
done
# Copy or lipo files that exist on both bundles.
cat universal_listing.txt | uniq -d | while IFS= read line
do
if cmp -s "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$arch_universal.app/$line"
then
echo "> Identical: $line"
cp -p "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line"
elif lipo -create -output "archive_tmp_universal/$merge_dest.app/$line" "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$arch_universal.app/$line" 2> /dev/null
then
echo "> Merged: $line"
else
echo "> Copied from [$merge_src]: $line"
cp -p "archive_tmp_universal/$merge_src.app/$line" "archive_tmp_universal/$merge_dest.app/$line"
fi
done
# Merge symlinks.
(cd "archive_tmp_universal/$merge_src.app" && find . -type l && cd "../../archive_tmp_universal/$arch_universal.app" && find . -type l && cd ../..) | sort > universal_listing.txt
cat universal_listing.txt | uniq | while IFS= read line
do
# Get symlink destinations.
other_link_dest=
if [ -e "archive_tmp_universal/$merge_src.app/$line" ]
then
file_src="$merge_src"
other_link_path="archive_tmp_universal/$arch_universal.app/$line"
if [ -L "$other_link_path" ]
then
other_link_dest="$(readlink "$other_link_path")"
elif [ -e "$other_link_path" ]
then
other_link_dest='[not a symlink]'
fi
else
file_src="$arch_universal"
fi
link_dest="$(readlink "archive_tmp_universal/$file_src.app/$line")"
# Warn if destinations differ.
if [ -n "$other_link_dest" -a "$link_dest" != "$other_link_dest" ]
then
echo "> Symlink: $line => WARNING: different targets"
echo ">> Using: [$merge_src] $link_dest"
echo ">> Other: [$arch_universal] $other_link_dest"
else
echo "> Symlink: $line => $link_dest"
fi
ln -s "$link_dest" "archive_tmp_universal/$merge_dest.app/$line"
done
# Merge a subsequent bundle with this one.
merge_src="$merge_dest"
fi
fi
if [ $status -ne 0 ]
then
echo [!] Aborting universal build: [$arch_universal] failed with status [$status]
exit $status
fi
done
# Rename final app bundle.
rm -rf archive_tmp
mkdir archive_tmp
mv "archive_tmp_universal/$merge_src.app" "$app_bundle_name"
# Sign final app bundle.
arch -"$(uname -m)" codesign --force --deep -s - "$app_bundle_name"
# Create zip.
echo [-] Creating artifact archive
cd archive_tmp
zip --symlinks -r "$cwd/$package_name.zip" .
status=$?
# Check if the archival succeeded.
if [ $status -ne 0 ]
then
echo [!] Artifact archive creation failed with status [$status]
exit 7
fi
# All good.
echo [-] Universal build of [$package_name] for [$arch] with flags [$cmake_flags] successful
exit 0
fi
# Switch into the correct architecture if required.
case $arch in
x86_64) arch_mac="i386";;
*) arch_mac="$arch";;
esac
if [ "$(arch)" != "$arch" -a "$(arch)" != "$arch_mac" ]
then
# Call build with the correct architecture.
echo [-] Switching to architecture [$arch]
cd "$cwd"
args=
[ $strip -ne 0 ] && args="-t $args"
[ $skip_archive -ne 0 ] && args="-n $args"
arch -"$arch" zsh -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$args""$cmake_flags"
exit $?
fi
echo [-] Using architecture [$(arch)]
# Locate the MacPorts prefix.
macports="/opt/local"
[ -e "/opt/$arch/bin/port" ] && macports="/opt/$arch"
[ "$arch" = "x86_64" -a -e "/opt/intel/bin/port" ] && macports="/opt/intel"
export PATH="$macports/bin:$macports/sbin:$PATH"
# Install dependencies.
echo [-] Installing dependencies through MacPorts
sudo $macports/bin/port selfupdate
sudo $macports/bin/port install $(cat .ci/dependencies_macports.txt)
sudo "$macports/bin/port" selfupdate
sudo "$macports/bin/port" install $(cat .ci/dependencies_macports.txt)
# Point CMake to the toolchain file.
[ -e "cmake/$toolchain.cmake" ] && cmake_flags_extra="$cmake_flags_extra -D \"CMAKE_TOOLCHAIN_FILE=cmake/$toolchain.cmake\""
@@ -355,7 +533,7 @@ else
esac
# Establish general dependencies.
pkgs="cmake ninja-build pkg-config git wget p7zip-full wayland-protocols tar gzip file"
pkgs="cmake ninja-build pkg-config git wget p7zip-full wayland-protocols tar gzip file appstream"
if [ "$(dpkg --print-architecture)" = "$arch_deb" ]
then
pkgs="$pkgs build-essential"
@@ -563,8 +741,8 @@ then
unzip -j discord_game_sdk.zip "lib/$arch_discord/discord_game_sdk.dylib" -d "archive_tmp/"*".app/Contents/Frameworks"
[ ! -e "archive_tmp/"*".app/Contents/Frameworks/discord_game_sdk.dylib" ] && echo [!] No Discord Game SDK for architecture [$arch_discord]
# Sign app bundle.
codesign --force --deep -s - "archive_tmp/"*".app"
# Sign app bundle, unless we're in an universal build.
[ $skip_archive -eq 0 ] && codesign --force --deep -s - "archive_tmp/"*".app"
fi
else
cwd_root=$(pwd)
@@ -606,6 +784,10 @@ else
sdl_ss=ON
fi
# Build SDL2 with video systems (and some dependencies) only if the SDL interface is used.
sdl_ui=OFF
grep -qiE "^QT:BOOL=ON" build/CMakeCache.txt || sdl_ui=ON
# Build rtmidi without JACK support to remove the dependency on libjack.
prefix="$cache_dir/rtmidi-4.0.0"
if [ -d "$prefix" ]
@@ -626,15 +808,25 @@ else
wget -qO - https://www.libsdl.org/release/SDL2-2.0.20.tar.gz | tar zxf - -C "$cache_dir" || rm -rf "$prefix"
fi
rm -rf "$cache_dir/sdlbuild"
cmake -G Ninja -D SDL_DISKAUDIO=OFF -D SDL_DIRECTFB_SHARED=OFF -D SDL_OPENGL=OFF -D SDL_OPENGLES=OFF -D SDL_OSS=OFF -D SDL_ALSA=$sdl_ss \
-D SDL_ALSA_SHARED=$sdl_ss -D SDL_JACK=$sdl_ss -D SDL_JACK_SHARED=$sdl_ss -D SDL_ESD=OFF -D SDL_ESD_SHARED=OFF -D SDL_PIPEWIRE=$sdl_ss \
cmake -G Ninja -D SDL_SHARED=ON -D SDL_STATIC=OFF \
\
-D SDL_AUDIO=$sdl_ss -D SDL_DUMMYAUDIO=$sdl_ss -D SDL_DISKAUDIO=OFF -D SDL_OSS=OFF -D SDL_ALSA=$sdl_ss -D SDL_ALSA_SHARED=$sdl_ss \
-D SDL_JACK=$sdl_ss -D SDL_JACK_SHARED=$sdl_ss -D SDL_ESD=OFF -D SDL_ESD_SHARED=OFF -D SDL_PIPEWIRE=$sdl_ss \
-D SDL_PIPEWIRE_SHARED=$sdl_ss -D SDL_PULSEAUDIO=$sdl_ss -D SDL_PULSEAUDIO_SHARED=$sdl_ss -D SDL_ARTS=OFF -D SDL_ARTS_SHARED=OFF \
-D SDL_NAS=$sdl_ss -D SDL_NAS_SHARED=$sdl_ss -D SDL_SNDIO=$sdl_ss -D SDL_SNDIO_SHARED=$sdl_ss -D SDL_FUSIONSOUND=OFF \
-D SDL_FUSIONSOUND_SHARED=OFF -D SDL_LIBSAMPLERATE=$sdl_ss -D SDL_LIBSAMPLERATE_SHARED=$sdl_ss -D SDL_X11=OFF -D SDL_X11_SHARED=OFF \
-D SDL_WAYLAND=OFF -D SDL_WAYLAND_SHARED=OFF -D SDL_WAYLAND_LIBDECOR=OFF -D SDL_WAYLAND_LIBDECOR_SHARED=OFF -D SDL_WAYLAND_QT_TOUCH=OFF \
-D SDL_RPI=OFF -D SDL_VIVANTE=OFF -D SDL_VULKAN=OFF -D SDL_KMSDRM=OFF -D SDL_KMSDRM_SHARED=OFF -D SDL_OFFSCREEN=OFF \
-D SDL_HIDAPI_JOYSTICK=ON -D SDL_VIRTUAL_JOYSTICK=ON -D SDL_SHARED=ON -D SDL_STATIC=OFF -S "$prefix" -B "$cache_dir/sdlbuild" \
-D "CMAKE_TOOLCHAIN_FILE=$cwd_root/toolchain.cmake" -D "CMAKE_INSTALL_PREFIX=$cwd_root/archive_tmp/usr" || exit 99
-D SDL_FUSIONSOUND_SHARED=OFF -D SDL_LIBSAMPLERATE=$sdl_ss -D SDL_LIBSAMPLERATE_SHARED=$sdl_ss \
\
-D SDL_VIDEO=$sdl_ui -D SDL_X11=$sdl_ui -D SDL_X11_SHARED=$sdl_ui -D SDL_WAYLAND=$sdl_ui -D SDL_WAYLAND_SHARED=$sdl_ui \
-D SDL_WAYLAND_LIBDECOR=$sdl_ui -D SDL_WAYLAND_LIBDECOR_SHARED=$sdl_ui -D SDL_WAYLAND_QT_TOUCH=OFF -D SDL_RPI=OFF -D SDL_VIVANTE=OFF \
-D SDL_VULKAN=OFF -D SDL_KMSDRM=$sdl_ui -D SDL_KMSDRM_SHARED=$sdl_ui -D SDL_OFFSCREEN=$sdl_ui -D SDL_RENDER=$sdl_ui \
\
-D SDL_JOYSTICK=ON -D SDL_HIDAPI_JOYSTICK=ON -D SDL_VIRTUAL_JOYSTICK=ON \
\
-D SDL_ATOMIC=OFF -D SDL_EVENTS=ON -D SDL_HAPTIC=OFF -D SDL_POWER=OFF -D SDL_THREADS=ON -D SDL_TIMERS=ON -D SDL_FILE=OFF \
-D SDL_LOADSO=ON -D SDL_CPUINFO=ON -D SDL_FILESYSTEM=$sdl_ui -D SDL_DLOPEN=OFF -D SDL_SENSOR=OFF -D SDL_LOCALE=OFF \
\
-D "CMAKE_TOOLCHAIN_FILE=$cwd_root/toolchain.cmake" -D "CMAKE_INSTALL_PREFIX=$cwd_root/archive_tmp/usr" \
-S "$prefix" -B "$cache_dir/sdlbuild" || exit 99
cmake --build "$cache_dir/sdlbuild" -j$(nproc) || exit 99
cmake --install "$cache_dir/sdlbuild" || exit 99
@@ -653,11 +845,17 @@ else
echo $pkg $version >> archive_tmp/README
done
# Archive metadata.
project_id=$(ls src/unix/assets/*.*.xml | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+\.[^\.]+$)')
metainfo_base=archive_tmp/usr/share/metainfo
mkdir -p "$metainfo_base"
cp -p "src/unix/assets/$project_id."*".xml" "$metainfo_base/$project_id.appdata.xml"
# Archive icons.
icon_base=archive_tmp/usr/share/icons
mkdir -p "$icon_base"
cp -rp src/unix/assets/[0-9]*x[0-9]* "$icon_base/"
icon_name=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)')
project_icon=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)')
# Archive executable, while also stripping it if requested.
mkdir -p archive_tmp/usr/local/bin
@@ -678,6 +876,13 @@ then
exit 6
fi
# Stop if artifact archive creation was disabled.
if [ $skip_archive -ne 0 ]
then
echo [-] Skipping artifact archive creation
exit 0
fi
# Produce artifact archive.
echo [-] Creating artifact archive
if is_windows
@@ -688,9 +893,9 @@ then
status=$?
elif is_mac
then
# Create zip. (TODO: dmg)
# Create zip.
cd archive_tmp
zip -r "$cwd/$package_name.zip" .
zip --symlinks -r "$cwd/$package_name.zip" .
status=$?
else
# Determine AppImage runtime architecture.
@@ -702,22 +907,46 @@ else
esac
# Get version for AppImage metadata.
project_version=$(grep -oP '#define\s+EMU_VERSION\s+"\K([^"]+)' "build/src/include/$project_lower/version.h" 2> /dev/null)
project_version=$(grep -oP '#define\s+EMU_VERSION\s+"\K([^"]+)' "build/src/include/"*"/version.h" 2> /dev/null)
[ -z "$project_version" ] && project_version=unknown
build_num=$(grep -oP '#define\s+EMU_BUILD_NUM\s+\K([0-9]+)' "build/src/include/$project_lower/version.h" 2> /dev/null)
build_num=$(grep -oP '#define\s+EMU_BUILD_NUM\s+\K([0-9]+)' "build/src/include/"*"/version.h" 2> /dev/null)
[ -n "$build_num" -a "$build_num" != "0" ] && project_version="$project_version-b$build_num"
# Generate modified AppImage metadata to suit build requirements.
cat << EOF > AppImageBuilder-generated.yml
# This file is generated automatically by .ci/build.sh and will be
# overwritten if edited. Please edit .ci/AppImageBuilder.yml instead.
EOF
while IFS= read line
do
# Skip blank or comment lines.
echo "$line" | grep -qE '^(#|$)' && continue
# Parse "# if OPTION VALUE" condition lines.
condition=$(echo "$line" | grep -oP '# if \K(.+)')
if [ -n "$condition" ]
then
# Skip line if the condition is not matched.
grep -qiE "^$condition" build/CMakeCache.txt || continue
fi
# Copy line.
echo "$line" >> AppImageBuilder-generated.yml
done < .ci/AppImageBuilder.yml
# Download appimage-builder if necessary.
[ ! -e "appimage-builder.AppImage" ] && wget -qO appimage-builder.AppImage \
https://github.com/AppImageCrafters/appimage-builder/releases/download/v0.9.2/appimage-builder-0.9.2-35e3eab-x86_64.AppImage
chmod u+x appimage-builder.AppImage
# Remove any dangling AppImages which may interfere with the renaming process.
rm -rf "$project-"*".AppImage"
# Symlink global cache directory.
rm -rf appimage-builder-cache "$project-"*".AppImage" # also remove any dangling AppImages which may interfere with the renaming process
mkdir -p "$cache_dir/appimage-builder-cache"
ln -s "$cache_dir/appimage-builder-cache" appimage-builder-cache
# Run appimage-builder in extract-and-run mode for Docker compatibility.
project="$project" project_lower="$project_lower" project_version="$project_version" project_icon="$icon_name" arch_deb="$arch_deb" \
arch_appimage="$arch_appimage" APPIMAGE_EXTRACT_AND_RUN=1 ./appimage-builder.AppImage --recipe .ci/AppImageBuilder.yml
project="$project" project_id="$project_id" project_version="$project_version" project_icon="$project_icon" arch_deb="$arch_deb" \
arch_appimage="$arch_appimage" APPIMAGE_EXTRACT_AND_RUN=1 ./appimage-builder.AppImage --recipe AppImageBuilder-generated.yml
status=$?
# Rename AppImage to the final name if the build succeeded.
@@ -727,7 +956,6 @@ else
status=$?
fi
fi
cd ..
# Check if the archival succeeded.
if [ $status -ne 0 ]

View File

@@ -1,10 +1,10 @@
cmake@3.22.3_0
pkgconfig@0.29.2_0
ninja@1.10.2_4
freetype@2.11.1_0
libsdl2@2.0.20_0
libpng@1.6.37_0
openal-soft@1.21.1_0
rtmidi@5.0.0_0
qt5@5.15.3_0
cmake
pkgconfig
ninja
freetype
libsdl2
libpng
openal-soft
rtmidi
qt5
wget

8
.gitignore vendored
View File

@@ -1,8 +1,8 @@
# CMake
/CMakeUserPresets.json
/CMakeCache.txt
/build
CMakeUserPresets.json
CMakeCache.txt
CMakeFiles
/build
Makefile
*.a
/src/*.exe
@@ -26,9 +26,11 @@ Makefile
# Build scripts
/archive_tmp
/archive_tmp_universal
/static2dll.*
/pacman.txt
/deps.txt
/universal_listing.txt
/VERSION
*.zip
*.tar

View File

@@ -35,7 +35,7 @@ if(MUNT_EXTERNAL)
endif()
project(86Box
VERSION 3.4.1
VERSION 3.5
DESCRIPTION "Emulator of x86-based systems"
HOMEPAGE_URL "https://86box.net"
LANGUAGES C CXX)
@@ -188,6 +188,7 @@ endif()
if(NOT CMAKE_PROJECT_VERSION_PATCH)
set(CMAKE_PROJECT_VERSION_PATCH 0)
endif()
set(EMU_VERSION_EX "3.50")
if(NOT EMU_BUILD_NUM)
set(EMU_BUILD_NUM 0)
endif()

71
bumpversion.sh Normal file
View File

@@ -0,0 +1,71 @@
#!/bin/sh
#
# 86Box A hypervisor and IBM PC system emulator that specializes in
# running old operating systems and software designed for IBM
# PC systems and compatibles from 1981 through fairly recent
# system designs based on the PCI bus.
#
# This file is part of the 86Box distribution.
#
# Convenience script for changing the emulator's version.
#
#
# Authors: RichardG, <richardg867@gmail.com>
#
# Copyright 2022 RichardG.
#
# Parse arguments.
newversion="$1"
if [ -z "$(echo $newversion | grep '\.')" ]
then
echo '[!] Usage: bumpversion.sh x.y[.z]'
exit 1
fi
shift
# Extract version components.
newversion_maj=$(echo $newversion | cut -d. -f1)
newversion_min=$(echo $newversion | cut -d. -f2)
newversion_patch=$(echo $newversion | cut -d. -f3)
[ -z "$newversion_patch" ] && newversion_patch=0
base36() {
if [ $1 -lt 10 ]
then
echo $1
else
printf '%b' $(printf '\\%03o' $((55 + $1)))
fi
}
newversion_maj_base36=$(base36 $newversion_maj)
newversion_min_base36=$(base36 $newversion_min)
newversion_patch_base36=$(base36 $newversion_patch)
# Switch to the repository root directory.
cd "$(dirname "$0")"
# Patch files.
patch_file() {
# Stop if the file doesn't exist.
[ ! -e "$1" ] && return
# Patch file.
if sed -i -r -e "$3" "$1"
then
echo "[-] Patched $2 on $1"
else
echo "[!] Patching $2 on $1 failed"
fi
}
patch_file CMakeLists.txt VERSION 's/^(\s*VERSION ).+/\1'"$newversion"'/'
patch_file CMakeLists.txt EMU_VERSION_EX 's/(\s*set\(EMU_VERSION_EX\s+")[^"]+/\1'"$newversion_maj_base36.$newversion_min_base36$newversion_patch_base36"'/'
patch_file src/include_make/*/version.h EMU_VERSION 's/(#\s*define\s+EMU_VERSION\s+")[^"]+/\1'"$newversion"'/'
patch_file src/include_make/*/version.h EMU_VERSION_EX 's/(#\s*define\s+EMU_VERSION_EX\s+")[^"]+/\1'"$newversion_maj_base36.$newversion_min_base36$newversion_patch_base36"'/'
patch_file src/include_make/*/version.h EMU_VERSION_MAJ 's/(#\s*define\s+EMU_VERSION_MAJ\s+)[0-9]+/\1'"$newversion_maj"'/'
patch_file src/include_make/*/version.h EMU_VERSION_MIN 's/(#\s*define\s+EMU_VERSION_MIN\s+)[0-9]+/\1'"$newversion_min"'/'
patch_file src/include_make/*/version.h EMU_VERSION_PATCH 's/(#\s*define\s+EMU_VERSION_PATCH\s+)[0-9]+/\1'"$newversion_patch"'/'
patch_file src/include_make/*/version.h COPYRIGHT_YEAR 's/(#\s*define\s+COPYRIGHT_YEAR\s+)[0-9]+/\1'"$(date +%Y)"'/'
patch_file src/include_make/*/version.h EMU_DOCS_URL 's/(#\s*define\s+EMU_DOCS_URL\s+"https:\/\/[^\/]+\/en\/v)[^\/]+/\1'"$newversion_maj.$newversion_min"'/'
patch_file src/unix/assets/*.spec Version 's/(Version:\s+)[0-9].+/\1'"$newversion"'/'
patch_file src/unix/assets/*.metainfo.xml release 's/(<release version=")[^"]+(" date=")[^"]+/\1'"$newversion"'\2'"$(date +%Y-%m-%d)"'/'

View File

@@ -97,6 +97,13 @@
#include <86box/version.h>
#include <86box/gdbstub.h>
// Disable c99-designator to avoid the warnings about int ng
#ifdef __clang__
#if __has_warning("-Wunused-but-set-variable")
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#endif
#endif
/* Stuff that used to be globally declared in plat.h but is now extern there
and declared here instead. */
@@ -507,7 +514,7 @@ usage:
rom_add_path(rpath);
} else if (!strcasecmp(argv[c], "--config") ||
!strcasecmp(argv[c], "-C")) {
if ((c+1) == argc) goto usage;
if ((c+1) == argc || plat_dir_check(argv[c + 1])) goto usage;
cfg = argv[++c];
} else if (!strcasecmp(argv[c], "--vmname") ||

View File

@@ -89,7 +89,9 @@ discord_update_activity(int paused)
*(paren - 1) = '\0';
#pragma GCC diagnostic push
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wformat-truncation"
#endif
if (strlen(vm_name) < 100)
{
snprintf(activity.details, sizeof(activity.details), "Running \"%s\"", vm_name);

View File

@@ -22,7 +22,7 @@
#define EMU_VERSION "@CMAKE_PROJECT_VERSION@"
#define EMU_VERSION_W LSTR(EMU_VERSION)
#define EMU_VERSION_EX "@CMAKE_PROJECT_VERSION_MAJOR@.@CMAKE_PROJECT_VERSION_MINOR@@CMAKE_PROJECT_VERSION_PATCH@"
#define EMU_VERSION_EX "@EMU_VERSION_EX@"
#define EMU_VERSION_MAJ @CMAKE_PROJECT_VERSION_MAJOR@
#define EMU_VERSION_MIN @CMAKE_PROJECT_VERSION_MINOR@
#define EMU_VERSION_PATCH @CMAKE_PROJECT_VERSION_PATCH@

View File

@@ -20,12 +20,12 @@
#define EMU_NAME "86Box"
#define EMU_NAME_W LSTR(EMU_NAME)
#define EMU_VERSION "3.4"
#define EMU_VERSION "3.5"
#define EMU_VERSION_W LSTR(EMU_VERSION)
#define EMU_VERSION_EX "3.41"
#define EMU_VERSION_EX "3.50"
#define EMU_VERSION_MAJ 3
#define EMU_VERSION_MIN 4
#define EMU_VERSION_PATCH 1
#define EMU_VERSION_MIN 5
#define EMU_VERSION_PATCH 0
#define EMU_BUILD_NUM 0
@@ -40,7 +40,7 @@
#define EMU_ROMS_URL "https://github.com/86Box/roms/releases/latest"
#define EMU_ROMS_URL_W LSTR(EMU_ROMS_URL)
#ifdef RELEASE_BUILD
# define EMU_DOCS_URL "https://86box.readthedocs.io/en/v3.4/"
# define EMU_DOCS_URL "https://86box.readthedocs.io/en/v3.5/"
#else
# define EMU_DOCS_URL "https://86box.readthedocs.io"
#endif

View File

@@ -145,6 +145,12 @@ add_library(ui STATIC
qt_unixmanagerfilter.cpp
qt_unixmanagerfilter.hpp
qt_vulkanwindowrenderer.hpp
qt_vulkanwindowrenderer.cpp
qt_vulkanrenderer.hpp
qt_vulkanrenderer.cpp
../qt_resources.qrc
)

View File

@@ -47,6 +47,8 @@ plat_vidapi(char* api) {
return 2;
} else if (!strcasecmp(api, "qt_opengl3")) {
return 3;
} else if (!strcasecmp(api, "qt_vulkan")) {
return 4;
}
return 0;
@@ -68,6 +70,9 @@ char* plat_vidapi_name(int api) {
case 3:
name = "qt_opengl3";
break;
case 4:
name = "qt_vulkan";
break;
default:
fatal("Unknown renderer: %i\n", api);
break;

View File

@@ -150,6 +150,7 @@ void HardwareRenderer::paintGL() {
texcoords.push_back(QVector2D((float)source.x() / 2048.f, (float)(source.y() + source.height()) / 2048.f));
texcoords.push_back(QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y() + source.height()) / 2048.f));
texcoords.push_back(QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y()) / 2048.f));
m_vbo[PROGRAM_VERTEX_ATTRIBUTE].bind(); m_vbo[PROGRAM_VERTEX_ATTRIBUTE].write(0, verts.data(), sizeof(QVector2D) * 4); m_vbo[PROGRAM_VERTEX_ATTRIBUTE].release();
m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].bind(); m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].write(0, texcoords.data(), sizeof(QVector2D) * 4); m_vbo[PROGRAM_TEXCOORD_ATTRIBUTE].release();

View File

@@ -276,9 +276,15 @@ MainWindow::MainWindow(QWidget *parent) :
vid_api = 0;
ui->actionHardware_Renderer_OpenGL->setVisible(false);
ui->actionHardware_Renderer_OpenGL_ES->setVisible(false);
ui->actionVulkan->setVisible(false);
ui->actionOpenGL_3_0_Core->setVisible(false);
}
#if !QT_CONFIG(vulkan)
if (vid_api == 4) vid_api = 0;
ui->actionVulkan->setVisible(false);
#endif
QActionGroup* actGroup = nullptr;
actGroup = new QActionGroup(this);
@@ -286,6 +292,7 @@ MainWindow::MainWindow(QWidget *parent) :
actGroup->addAction(ui->actionHardware_Renderer_OpenGL);
actGroup->addAction(ui->actionHardware_Renderer_OpenGL_ES);
actGroup->addAction(ui->actionOpenGL_3_0_Core);
actGroup->addAction(ui->actionVulkan);
actGroup->setExclusive(true);
connect(actGroup, &QActionGroup::triggered, [this](QAction* action) {
@@ -304,6 +311,9 @@ MainWindow::MainWindow(QWidget *parent) :
case 3:
ui->stackedWidget->switchRenderer(RendererStack::Renderer::OpenGL3);
break;
case 4:
ui->stackedWidget->switchRenderer(RendererStack::Renderer::Vulkan);
break;
}
});
@@ -509,8 +519,11 @@ void MainWindow::closeEvent(QCloseEvent *event) {
}
qt_nvr_save();
config_save();
if (ui->stackedWidget->mouse_exit_func)
ui->stackedWidget->mouse_exit_func();
ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software);
event->accept();
}
@@ -1440,6 +1453,10 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
{
if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen))
{
// Windows keys in Qt have one-to-one mapping.
if (event->key() == Qt::Key_Super_L || event->key() == Qt::Key_Super_R) {
keyboard_input(1, event->key() == Qt::Key_Super_L ? 0x15B : 0x15C);
} else
#ifdef Q_OS_MACOS
processMacKeyboardInput(true, event);
#else
@@ -1467,6 +1484,9 @@ void MainWindow::keyReleaseEvent(QKeyEvent* event)
if (!send_keyboard_input)
return;
if (event->key() == Qt::Key_Super_L || event->key() == Qt::Key_Super_R) {
keyboard_input(0, event->key() == Qt::Key_Super_L ? 0x15B : 0x15C);
} else
#ifdef Q_OS_MACOS
processMacKeyboardInput(false, event);
#else

View File

@@ -54,7 +54,7 @@
<x>0</x>
<y>0</y>
<width>724</width>
<height>22</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuAction">
@@ -102,6 +102,7 @@
<addaction name="actionHardware_Renderer_OpenGL"/>
<addaction name="actionHardware_Renderer_OpenGL_ES"/>
<addaction name="actionOpenGL_3_0_Core"/>
<addaction name="actionVulkan"/>
</widget>
<widget class="QMenu" name="menuWindow_scale_factor">
<property name="title">
@@ -726,6 +727,17 @@
<string>Renderer options...</string>
</property>
</action>
<action name="actionVulkan">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Vulkan</string>
</property>
<property name="vid_api" stdset="0">
<number>4</number>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@@ -20,6 +20,8 @@ public:
void onResize(int width, int height);
virtual void finalize() { }
virtual uint32_t getBytesPerRow() { return 2048 * 4; }
virtual std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() = 0;
/* Does renderer implement options dialog */

View File

@@ -24,13 +24,17 @@
#include "qt_hardwarerenderer.hpp"
#include "qt_openglrenderer.hpp"
#include "qt_softwarerenderer.hpp"
#include "qt_vulkanwindowrenderer.hpp"
#include "qt_mainwindow.hpp"
#include "qt_util.hpp"
#include "evdev_mouse.hpp"
#include <stdexcept>
#include <QScreen>
#include <QMessageBox>
#ifdef __APPLE__
# include <CoreGraphics/CoreGraphics.h>
@@ -55,10 +59,8 @@ RendererStack::RendererStack(QWidget *parent)
if (!mouse_type || (mouse_type[0] == '\0') || !stricmp(mouse_type, "auto")) {
if (QApplication::platformName().contains("wayland"))
strcpy(auto_mouse_type, "wayland");
else if (QApplication::platformName() == "eglfs")
else if (QApplication::platformName() == "eglfs" || QApplication::platformName() == "xcb")
strcpy(auto_mouse_type, "evdev");
else if (QApplication::platformName() == "xcb")
strcpy(auto_mouse_type, "xinput2");
else
auto_mouse_type[0] = '\0';
mouse_type = auto_mouse_type;
@@ -70,22 +72,14 @@ RendererStack::RendererStack(QWidget *parent)
this->mouse_poll_func = wl_mouse_poll;
this->mouse_capture_func = wl_mouse_capture;
this->mouse_uncapture_func = wl_mouse_uncapture;
} else
}
# endif
# ifdef EVDEV_INPUT
if (!stricmp(mouse_type, "evdev")) {
evdev_init();
this->mouse_poll_func = evdev_mouse_poll;
} else
# endif
if (!stricmp(mouse_type, "xinput2")) {
extern void xinput2_init();
extern void xinput2_poll();
extern void xinput2_exit();
xinput2_init();
this->mouse_poll_func = xinput2_poll;
this->mouse_exit_func = xinput2_exit;
}
# endif
#endif
#ifdef __APPLE__
this->mouse_poll_func = macos_poll_mouse;
@@ -241,6 +235,7 @@ void
RendererStack::createRenderer(Renderer renderer)
{
switch (renderer) {
default:
case Renderer::Software:
{
auto sw = new SoftwareRenderer(this);
@@ -278,13 +273,13 @@ RendererStack::createRenderer(Renderer renderer)
rendererWindow = hw;
connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection);
connect(hw, &OpenGLRenderer::initialized, [=]() {
/* Buffers are awailable only after initialization. */
/* Buffers are available only after initialization. */
imagebufs = rendererWindow->getBuffers();
endblit();
emit rendererChanged();
});
connect(hw, &OpenGLRenderer::errorInitializing, [=]() {
/* Renderer could initialize, fallback to software. */
/* Renderer not could initialize, fallback to software. */
imagebufs = {};
endblit();
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
@@ -292,8 +287,46 @@ RendererStack::createRenderer(Renderer renderer)
current.reset(this->createWindowContainer(hw, this));
break;
}
#if QT_CONFIG(vulkan)
case Renderer::Vulkan:
{
this->createWinId();
VulkanWindowRenderer *hw = nullptr;
try {
hw = new VulkanWindowRenderer(this);
} catch(std::runtime_error& e) {
auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", e.what() + QString("\nFalling back to software rendering."), QMessageBox::Ok);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->show();
imagebufs = {};
endblit();
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
current.reset(nullptr);
break;
};
rendererWindow = hw;
connect(this, &RendererStack::blitToRenderer, hw, &VulkanWindowRenderer::onBlit, Qt::QueuedConnection);
connect(hw, &VulkanWindowRenderer::rendererInitialized, [=]() {
/* Buffers are available only after initialization. */
imagebufs = rendererWindow->getBuffers();
endblit();
emit rendererChanged();
});
connect(hw, &VulkanWindowRenderer::errorInitializing, [=]() {
/* Renderer could not initialize, fallback to software. */
auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", QString("Failed to initialize Vulkan renderer.\nFalling back to software rendering."), QMessageBox::Ok);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->show();
imagebufs = {};
endblit();
QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); });
});
current.reset(this->createWindowContainer(hw, this));
break;
}
#endif
}
if (current.get() == nullptr) return;
current->setFocusPolicy(Qt::NoFocus);
current->setFocusProxy(this);
addWidget(current.get());
@@ -302,7 +335,7 @@ RendererStack::createRenderer(Renderer renderer)
currentBuf = 0;
if (renderer != Renderer::OpenGL3) {
if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) {
imagebufs = rendererWindow->getBuffers();
endblit();
emit rendererChanged();
@@ -323,7 +356,7 @@ RendererStack::blit(int x, int y, int w, int h)
sh = this->h = h;
uint8_t *imagebits = std::get<uint8_t *>(imagebufs[currentBuf]);
for (int y1 = y; y1 < (y + h); y1++) {
auto scanline = imagebits + (y1 * (2048) * 4) + (x * 4);
auto scanline = imagebits + (y1 * rendererWindow->getBytesPerRow()) + (x * 4);
video_copy(scanline, &(buffer32->line[y1][x]), w * 4);
}

View File

@@ -44,7 +44,8 @@ public:
Software,
OpenGL,
OpenGLES,
OpenGL3
OpenGL3,
Vulkan
};
void switchRenderer(Renderer renderer);

View File

@@ -43,6 +43,8 @@ extern "C"
#include <QDebug>
#include <QMessageBox>
#include <QCheckBox>
#include <QApplication>
#include <QStyle>
class SettingsModel : public QAbstractListModel {
public:
@@ -103,7 +105,6 @@ Settings::Settings(QWidget *parent) :
ui(new Ui::Settings)
{
ui->setupUi(this);
ui->listView->setModel(new SettingsModel(this));
Harddrives::busTrackClass = new SettingsBusTracking;
@@ -131,8 +132,6 @@ Settings::Settings(QWidget *parent) :
ui->stackedWidget->addWidget(otherRemovable);
ui->stackedWidget->addWidget(otherPeripherals);
ui->listView->setFixedWidth(ui->listView->sizeHintForColumn(0) + 5);
connect(machine, &SettingsMachine::currentMachineChanged, display, &SettingsDisplay::onCurrentMachineChanged);
connect(machine, &SettingsMachine::currentMachineChanged, input, &SettingsInput::onCurrentMachineChanged);
connect(machine, &SettingsMachine::currentMachineChanged, sound, &SettingsSound::onCurrentMachineChanged);
@@ -144,6 +143,8 @@ Settings::Settings(QWidget *parent) :
ui->stackedWidget->setCurrentIndex(current.row());
});
ui->listView->setMaximumWidth(ui->listView->sizeHintForColumn(0) + qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent));
Settings::settings = this;
}

View File

@@ -30,7 +30,11 @@
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,3">
<item>
<widget class="QListView" name="listView"/>
<widget class="QListView" name="listView">
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">

1007
src/qt/qt_vulkanrenderer.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
#pragma once
/****************************************************************************
**
** Copyright (C) 2022 Cacodemon345
** Copyright (C) 2017 The Qt Company Ltd.
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
****************************************************************************/
#include <QVulkanWindow>
#include <QImage>
#if QT_CONFIG(vulkan)
#include "qt_vulkanwindowrenderer.hpp"
class VulkanRenderer2 : public QVulkanWindowRenderer
{
public:
void* mappedPtr = nullptr;
size_t imagePitch = 2048 * 4;
VulkanRenderer2(QVulkanWindow *w);
void initResources() override;
void initSwapChainResources() override;
void releaseSwapChainResources() override;
void releaseResources() override;
void startNextFrame() override;
private:
VkShaderModule createShader(const QString &name);
bool createTexture();
bool createTextureImage(const QSize &size, VkImage *image, VkDeviceMemory *mem,
VkImageTiling tiling, VkImageUsageFlags usage, uint32_t memIndex);
bool writeLinearImage(const QImage &img, VkImage image, VkDeviceMemory memory);
void ensureTexture();
void updateSamplers();
QVulkanWindow *m_window;
QVulkanDeviceFunctions *m_devFuncs;
VkDeviceMemory m_bufMem = VK_NULL_HANDLE;
VkBuffer m_buf = VK_NULL_HANDLE;
VkDescriptorBufferInfo m_uniformBufInfo[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
VkDescriptorPool m_descPool = VK_NULL_HANDLE;
VkDescriptorSetLayout m_descSetLayout = VK_NULL_HANDLE;
VkDescriptorSet m_descSet[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
VkPipelineCache m_pipelineCache = VK_NULL_HANDLE;
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE;
VkSampler m_sampler = VK_NULL_HANDLE;
VkSampler m_linearSampler = VK_NULL_HANDLE;
VkImage m_texImage = VK_NULL_HANDLE;
VkDeviceMemory m_texMem = VK_NULL_HANDLE;
bool m_texLayoutPending = false;
VkImageView m_texView = VK_NULL_HANDLE;
VkImage m_texStaging = VK_NULL_HANDLE;
VkDeviceMemory m_texStagingMem = VK_NULL_HANDLE;
bool m_texStagingPending = false;
bool m_texStagingTransferLayout = false;
QSize m_texSize;
VkFormat m_texFormat;
QMatrix4x4 m_proj;
float m_rotation = 0.0f;
};
#endif

View File

@@ -0,0 +1,853 @@
#include "qt_vulkanwindowrenderer.hpp"
#include <QVulkanWindowRenderer>
#include <QVulkanDeviceFunctions>
#include <QMessageBox>
#include <QWindow>
#if QT_CONFIG(vulkan)
#include <array>
#include <stdexcept>
#include "qt_mainwindow.hpp"
#include "qt_vulkanrenderer.hpp"
extern "C"
{
#include <86box/86box.h>
#include <86box/video.h>
}
#if 0
extern MainWindow* main_window;
/*
#version 450
layout(location = 0) out vec2 v_texcoord;
mat4 mvp = mat4(
vec4(1.0, 0, 0, 0),
vec4(0, 1.0, 0, 0),
vec4(0, 0, 1.0, 0),
vec4(0, 0, 0, 1.0)
);
// Y coordinate in Vulkan viewport space is flipped as compared to OpenGL.
vec4 vertCoords[4] = vec4[](
vec4(-1.0, -1.0, 0, 1),
vec4(1.0, -1.0, 0, 1),
vec4(-1.0, 1.0, 0, 1),
vec4(1.0, 1.0, 0, 1)
);
layout(push_constant) uniform texCoordBuf {
vec2 texCoords[4];
} texCoordUniform;
out gl_PerVertex { vec4 gl_Position; };
void main()
{
v_texcoord = texCoordUniform.texCoords[gl_VertexIndex];
gl_Position = mvp * vertCoords[gl_VertexIndex];
}
*/
// Compiled with glslangValidator -V
static const uint8_t vertShaderCode[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x08, 0x00,
0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x6d, 0x76, 0x70, 0x00, 0x05, 0x00, 0x05, 0x00, 0x16, 0x00, 0x00, 0x00,
0x76, 0x65, 0x72, 0x74, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x73, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x74, 0x65,
0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64,
0x42, 0x75, 0x66, 0x00, 0x06, 0x00, 0x06, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64,
0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x23, 0x00, 0x00, 0x00,
0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x55, 0x6e, 0x69, 0x66,
0x6f, 0x72, 0x6d, 0x00, 0x05, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00,
0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x00, 0x05, 0x00, 0x03, 0x00, 0x2e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x27, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00,
0x07, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00,
0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x15, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf,
0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00,
0x07, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x03, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2b, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x35, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00,
0x2a, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00,
0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x2e, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x36, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
0x38, 0x00, 0x01, 0x00
};
/*
#version 440
layout(location = 0) in vec2 v_texcoord;
layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D tex;
void main()
{
fragColor = texture(tex, v_texcoord);
}
*/
static const uint8_t fragShaderCode[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x08, 0x00,
0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
0x02, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x00, 0x05, 0x00, 0x05, 0x00,
0x11, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f,
0x72, 0x64, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3f, 0x15, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x3d, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
0x38, 0x00, 0x01, 0x00
};
class VulkanRendererEmu : public QVulkanWindowRenderer
{
VulkanWindowRenderer* m_window{nullptr};
QVulkanDeviceFunctions* m_devFuncs{nullptr};
VmaAllocator allocator{nullptr};
VmaAllocation allocation{nullptr};
VkImage image{nullptr};
VkImageView imageView{nullptr};
VkPipeline pipeline{nullptr};
VkPipelineLayout pipelineLayout{nullptr};
VkDescriptorSetLayout descLayout{nullptr};
VkDescriptorPool descPool{nullptr};
VkDescriptorSet descSet{nullptr};
VkSampler sampler{nullptr}, nearestSampler{nullptr};
bool imageLayoutTransitioned{false};
int cur_video_filter_method = -1;
private:
void updateOptions() {
VkResult res;
if (cur_video_filter_method == video_filter_method) return;
if (!descPool) {
VkDescriptorPoolSize descSize{};
descSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descSize.descriptorCount = 2;
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &descSize;
poolInfo.maxSets = 2;
if ((res = m_devFuncs->vkCreateDescriptorPool(m_window->device(), &poolInfo, nullptr, &descPool)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create descriptor pool. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &descLayout;
if ((res = m_devFuncs->vkAllocateDescriptorSets(m_window->device(), &allocInfo, &descSet)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create descriptor set. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}}
VkDescriptorImageInfo imageDescInfo{};
imageDescInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageDescInfo.imageView = imageView;
imageDescInfo.sampler = video_filter_method == 0 ? nearestSampler : sampler;
VkWriteDescriptorSet descWrite{};
descWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descWrite.dstSet = descSet;
descWrite.dstBinding = 1;
descWrite.dstArrayElement = 0;
descWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descWrite.descriptorCount = 1;
descWrite.pImageInfo = &imageDescInfo;
m_devFuncs->vkUpdateDescriptorSets(m_window->device(), 1, &descWrite, 0, nullptr);
cur_video_filter_method = video_filter_method;
}
public:
void* mappedPtr = nullptr;
uint32_t imagePitch{2048 * 4};
VulkanRendererEmu(VulkanWindowRenderer *w) : m_window(w), m_devFuncs(nullptr) { }
void initResources() override
{
VmaAllocatorCreateInfo info{};
info.instance = m_window->vulkanInstance()->vkInstance();
info.device = m_window->device();
info.physicalDevice = m_window->physicalDevice();
VmaVulkanFunctions funcs{};
funcs.vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)m_window->vulkanInstance()->getInstanceProcAddr("vkGetInstanceProcAddr");
funcs.vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)m_window->vulkanInstance()->getInstanceProcAddr("vkGetDeviceProcAddr");
info.pVulkanFunctions = &funcs;
if (vmaCreateAllocator(&info, &allocator) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create Vulkan allocator. Switch to another renderer");
return;
}
m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
VkResult res;
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
imageInfo.extent.width = imageInfo.extent.height = 2048;
imageInfo.extent.depth = imageInfo.arrayLayers = imageInfo.mipLevels = 1;
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
VmaAllocationInfo allocatedInfo{};
VmaAllocationCreateInfo allocInfo{};
allocInfo.pUserData = allocInfo.pool = nullptr;
allocInfo.requiredFlags = allocInfo.preferredFlags = 0;
allocInfo.usage = VmaMemoryUsage::VMA_MEMORY_USAGE_AUTO;
allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
VMA_ALLOCATION_CREATE_MAPPED_BIT;
if ((res = vmaCreateImage(allocator, &imageInfo, &allocInfo, &image, &allocation, &allocatedInfo)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create Vulkan image. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
};
VkImageViewCreateInfo imageViewInfo{};
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
imageViewInfo.image = image;
imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewInfo.subresourceRange.baseMipLevel = 0;
imageViewInfo.subresourceRange.levelCount = 1;
imageViewInfo.subresourceRange.baseArrayLayer = 0;
imageViewInfo.subresourceRange.layerCount = 1;
imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
if ((res = m_devFuncs->vkCreateImageView(m_window->device(), &imageViewInfo, nullptr, &imageView)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create Vulkan image view. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
// Begin Pipeline creation.
{
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 0;
vertexInputInfo.pVertexBindingDescriptions = nullptr;
vertexInputInfo.vertexAttributeDescriptionCount = 0;
vertexInputInfo.pVertexAttributeDescriptions = nullptr;
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
inputAssembly.primitiveRestartEnable = VK_FALSE;
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = {2048, 2048};
VkViewport viewport{};
viewport.x = m_window->destination.x();
viewport.y = m_window->destination.y();
viewport.width = (float)m_window->destination.width();
viewport.height = (float)m_window->destination.height();
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f;
rasterizer.depthBiasClamp = 0.0f;
rasterizer.depthBiasSlopeFactor = 0.0f;
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampling.minSampleShading = 1.0f;
multisampling.pSampleMask = nullptr;
multisampling.alphaToCoverageEnable = VK_FALSE;
multisampling.alphaToOneEnable = VK_FALSE;
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo colorBlending{};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;
VkDynamicState dynState = VK_DYNAMIC_STATE_VIEWPORT;
VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = 1;
dynamicState.pDynamicStates = &dynState;
VkPushConstantRange range{};
range.offset = 0;
range.size = sizeof(float) * 8;
range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
// Sampler binding start.
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorCount = 1;
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &samplerLayoutBinding;
if ((res = m_devFuncs->vkCreateDescriptorSetLayout(m_window->device(), &layoutInfo, nullptr, &descLayout))) {
QMessageBox::critical(main_window, "86Box", "Could not create descriptor set layout. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
// Sampler binding end.
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &descLayout;
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &range;
if ((res = m_devFuncs->vkCreatePipelineLayout(m_window->device(), &pipelineLayoutInfo, nullptr, &pipelineLayout)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create pipeline layout. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
// Shader loading start.
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = sizeof(vertShaderCode);
createInfo.pCode = (uint32_t*)vertShaderCode;
VkShaderModule vertModule{nullptr}, fragModule{nullptr};
if ((res = m_devFuncs->vkCreateShaderModule(m_window->device(), &createInfo, nullptr, &vertModule)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create vertex shader. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
createInfo.codeSize = sizeof(fragShaderCode);
createInfo.pCode = (uint32_t*)fragShaderCode;
if ((res = m_devFuncs->vkCreateShaderModule(m_window->device(), &createInfo, nullptr, &fragModule)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create fragment shader. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShaderStageInfo.module = vertModule;
vertShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo fragShaderStageInfo{vertShaderStageInfo};
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragModule;
VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
// Shader loading end.
VkPipelineDepthStencilStateCreateInfo depthInfo{};
depthInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthInfo.pNext = nullptr;
depthInfo.depthTestEnable = VK_TRUE;
depthInfo.depthWriteEnable = VK_TRUE;
depthInfo.depthBoundsTestEnable = VK_FALSE;
depthInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthInfo.stencilTestEnable = VK_FALSE;
depthInfo.maxDepthBounds = 1.0f;
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthInfo;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = &dynamicState;
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = m_window->defaultRenderPass();
pipelineInfo.subpass = 0;
if ((res = m_devFuncs->vkCreateGraphicsPipelines(m_window->device(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline)) != VK_SUCCESS) {
m_devFuncs->vkDestroyShaderModule(m_window->device(), vertModule, nullptr);
m_devFuncs->vkDestroyShaderModule(m_window->device(), fragModule, nullptr);
QMessageBox::critical(main_window, "86Box", "Could not create graphics pipeline. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
m_devFuncs->vkDestroyShaderModule(m_window->device(), vertModule, nullptr);
m_devFuncs->vkDestroyShaderModule(m_window->device(), fragModule, nullptr);
}
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0;
if ((res = m_devFuncs->vkCreateSampler(m_window->device(), &samplerInfo, nullptr, &sampler)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create linear image sampler. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
samplerInfo.magFilter = samplerInfo.minFilter = VK_FILTER_NEAREST;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
if ((res = m_devFuncs->vkCreateSampler(m_window->device(), &samplerInfo, nullptr, &nearestSampler)) != VK_SUCCESS) {
QMessageBox::critical(main_window, "86Box", "Could not create nearest image sampler. Switch to another renderer. " + Vulkan_GetResultString(res));
return;
}
updateOptions();
VkImageSubresource resource{};
resource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resource.arrayLayer = 0;
resource.mipLevel = 0;
VkSubresourceLayout layout{};
m_devFuncs->vkGetImageSubresourceLayout(m_window->device(), image, &resource, &layout);
imagePitch = layout.rowPitch;
mappedPtr = (uint8_t*)allocatedInfo.pMappedData + layout.offset;
emit m_window->rendererInitialized();
}
void releaseResources() override
{
if (pipeline) m_devFuncs->vkDestroyPipeline(m_window->device(), pipeline, nullptr);
if (pipelineLayout) m_devFuncs->vkDestroyPipelineLayout(m_window->device(), pipelineLayout, nullptr);
if (descSet) m_devFuncs->vkDestroyDescriptorPool(m_window->device(), descPool, nullptr);
if (descLayout) m_devFuncs->vkDestroyDescriptorSetLayout(m_window->device(), descLayout, nullptr);
if (imageView) m_devFuncs->vkDestroyImageView(m_window->device(), imageView, nullptr);
if (image) vmaDestroyImage(allocator, image, allocation);
if (sampler) m_devFuncs->vkDestroySampler(m_window->device(), sampler, nullptr);
if (nearestSampler) m_devFuncs->vkDestroySampler(m_window->device(), nearestSampler, nullptr);
image = nullptr;
pipeline = nullptr;
pipelineLayout = nullptr;
imageView = nullptr;
descLayout = nullptr;
descPool = nullptr;
descSet = nullptr;
sampler = nullptr;
vmaDestroyAllocator(allocator);
allocator = nullptr;
}
QString Vulkan_GetResultString(VkResult result)
{
switch ((int)result) {
case VK_SUCCESS:
return "VK_SUCCESS";
case VK_NOT_READY:
return "VK_NOT_READY";
case VK_TIMEOUT:
return "VK_TIMEOUT";
case VK_EVENT_SET:
return "VK_EVENT_SET";
case VK_EVENT_RESET:
return "VK_EVENT_RESET";
case VK_INCOMPLETE:
return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST:
return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED:
return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS:
return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_FRAGMENTED_POOL:
return "VK_ERROR_FRAGMENTED_POOL";
case VK_ERROR_UNKNOWN:
return "VK_ERROR_UNKNOWN";
case VK_ERROR_OUT_OF_POOL_MEMORY:
return "VK_ERROR_OUT_OF_POOL_MEMORY";
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
case VK_ERROR_FRAGMENTATION:
return "VK_ERROR_FRAGMENTATION";
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:
return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
case VK_ERROR_SURFACE_LOST_KHR:
return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR:
return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR:
return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV:
return "VK_ERROR_INVALID_SHADER_NV";
#if VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162
case VK_ERROR_INCOMPATIBLE_VERSION_KHR:
return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
#endif
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
case VK_ERROR_NOT_PERMITTED_EXT:
return "VK_ERROR_NOT_PERMITTED_EXT";
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
case VK_THREAD_IDLE_KHR:
return "VK_THREAD_IDLE_KHR";
case VK_THREAD_DONE_KHR:
return "VK_THREAD_DONE_KHR";
case VK_OPERATION_DEFERRED_KHR:
return "VK_OPERATION_DEFERRED_KHR";
case VK_OPERATION_NOT_DEFERRED_KHR:
return "VK_OPERATION_NOT_DEFERRED_KHR";
case VK_PIPELINE_COMPILE_REQUIRED_EXT:
return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
default:
break;
}
if (result < 0) {
return "VK_ERROR_<Unknown>";
}
return "VK_<Unknown>";
}
void startNextFrame() override
{
m_devFuncs->vkDeviceWaitIdle(m_window->device());
VkClearValue values[2];
auto cmdBufs = m_window->currentCommandBuffer();
memset(values, 0, sizeof(values));
values[0].depthStencil = { 1, 0 };
values[1].depthStencil = { 1, 0 };
VkRenderPassBeginInfo info{};
VkSubpassDependency deps{};
info.pClearValues = values;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.framebuffer = m_window->currentFramebuffer();
info.renderArea = VkRect2D{{0, 0}, {(uint32_t)m_window->swapChainImageSize().width(), (uint32_t)m_window->swapChainImageSize().height()}};
info.clearValueCount = 2;
info.renderPass = m_window->defaultRenderPass();
updateOptions();
if (!imageLayoutTransitioned) {
VkPipelineStageFlags srcflags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_HOST_BIT, dstflags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = image;
barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
m_devFuncs->vkCmdPipelineBarrier(cmdBufs, srcflags, dstflags, 0, 0, nullptr, 0, nullptr, 1, &barrier);
imageLayoutTransitioned = true;
}
vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
VkViewport viewport{};
viewport.x = m_window->destination.x();
viewport.y = m_window->destination.y();
viewport.width = (float)m_window->destination.width();
viewport.height = (float)m_window->destination.height();
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
m_devFuncs->vkCmdSetViewport(cmdBufs, 0, 1, &viewport);
m_devFuncs->vkCmdBeginRenderPass(m_window->currentCommandBuffer(), &info, VK_SUBPASS_CONTENTS_INLINE);
m_devFuncs->vkCmdBindPipeline(cmdBufs, VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
m_devFuncs->vkCmdBindDescriptorSets(cmdBufs, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descSet, 0, nullptr);
std::array<QVector2D, 4> texcoords;
auto source = m_window->source;
texcoords[0] = (QVector2D((float)source.x() / 2048.f, (float)(source.y()) / 2048.f));
texcoords[2] = (QVector2D((float)source.x() / 2048.f, (float)(source.y() + source.height()) / 2048.f));
texcoords[1] = (QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y()) / 2048.f));
texcoords[3] = (QVector2D((float)(source.x() + source.width()) / 2048.f, (float)(source.y() + source.height()) / 2048.f));
m_devFuncs->vkCmdPushConstants(cmdBufs, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(QVector2D) * 4, texcoords.data());
m_devFuncs->vkCmdDraw(cmdBufs, 4, 1, 0, 0);
m_devFuncs->vkCmdEndRenderPass(cmdBufs);
m_window->frameReady();
m_devFuncs->vkDeviceWaitIdle(m_window->device());
}
};
#endif
VulkanWindowRenderer::VulkanWindowRenderer(QWidget* parent)
: QVulkanWindow(parent->windowHandle())
{
parentWidget = parent;
instance.setLayers(QByteArrayList() << "VK_LAYER_KHRONOS_validation");
instance.setExtensions(QByteArrayList() << "VK_EXT_debug_report");
instance.setApiVersion(QVersionNumber(1, 0));
if (!instance.create()) {
throw std::runtime_error("Could not create Vulkan instance");
}
uint32_t physicalDevices = 0;
instance.functions()->vkEnumeratePhysicalDevices(instance.vkInstance(), &physicalDevices, nullptr);
if (physicalDevices == 0) {
throw std::runtime_error("No physical devices available.");
}
qDebug() << instance.layers();
setVulkanInstance(&instance);
setPhysicalDeviceIndex(0);
setPreferredColorFormats({VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_A8B8G8R8_UNORM_PACK32});
setFlags(Flag::PersistentResources);
buf_usage = std::vector<std::atomic_flag>(1);
buf_usage[0].clear();
}
QVulkanWindowRenderer* VulkanWindowRenderer::createRenderer()
{
renderer = new VulkanRenderer2(this);
return renderer;
}
void VulkanWindowRenderer::resizeEvent(QResizeEvent *event) {
onResize(width(), height());
QVulkanWindow::resizeEvent(event);
}
bool VulkanWindowRenderer::event(QEvent *event)
{
bool res = false;
if (!eventDelegate(event, res)) return QVulkanWindow::event(event);
return res;
}
void VulkanWindowRenderer::onBlit(int buf_idx, int x, int y, int w, int h)
{
source.setRect(x, y, w, h);
if (isExposed()) requestUpdate();
buf_usage[0].clear();
}
uint32_t VulkanWindowRenderer::getBytesPerRow()
{
return renderer->imagePitch;
}
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> VulkanWindowRenderer::getBuffers()
{
return std::vector{std::make_tuple((uint8_t*)renderer->mappedPtr, &this->buf_usage[0])};
}
#endif

View File

@@ -0,0 +1,39 @@
#ifndef VULKANWINDOWRENDERER_HPP
#define VULKANWINDOWRENDERER_HPP
#include <QVulkanWindow>
#if QT_CONFIG(vulkan)
#include "qt_renderercommon.hpp"
#include "qt_vulkanrenderer.hpp"
class VulkanRenderer2;
class VulkanWindowRenderer : public QVulkanWindow, public RendererCommon
{
Q_OBJECT
public:
VulkanWindowRenderer(QWidget* parent);
public slots:
void onBlit(int buf_idx, int x, int y, int w, int h);
signals:
void rendererInitialized();
void errorInitializing();
protected:
virtual std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() override;
void resizeEvent(QResizeEvent*) override;
bool event(QEvent*) override;
uint32_t getBytesPerRow() override;
private:
QVulkanInstance instance;
QVulkanWindowRenderer* createRenderer() override;
friend class VulkanRendererEmu;
friend class VulkanRenderer2;
VulkanRenderer2* renderer;
};
#endif
#endif // VULKANWINDOWRENDERER_HPP

BIN
src/qt/texture_frag.spv Normal file

Binary file not shown.

BIN
src/qt/texture_vert.spv Normal file

Binary file not shown.

View File

@@ -57,4 +57,8 @@
<file>win/icons/send_cae.ico</file>
<file>win/icons/settings.ico</file>
</qresource>
<qresource prefix="/">
<file alias="/texture_vert.spv">qt/texture_vert.spv</file>
<file alias="/texture_frag.spv">qt/texture_frag.spv</file>
</qresource>
</RCC>

View File

@@ -36,6 +36,13 @@ extern "C"
#include <86box/midi_rtmidi.h>
#include <86box/config.h>
// Disable c99-designator to avoid the warnings in rtmidi_*_device
#ifdef __clang__
#if __has_warning("-Wc99-designator")
#pragma clang diagnostic ignored "-Wc99-designator"
#endif
#endif
static RtMidiOut * midiout = nullptr;
static RtMidiIn * midiin = nullptr;
static int midi_out_id = 0, midi_in_id = 0;

View File

@@ -15,7 +15,7 @@
%global romver 20220319
Name: 86Box
Version: 3.4
Version: 3.5
Release: 1%{?dist}
Summary: Classic PC emulator
License: GPLv2+
@@ -27,6 +27,7 @@ Source1: https://github.com/86Box/roms/archive/refs/tags/%{romver}.tar.gz
BuildRequires: cmake
BuildRequires: desktop-file-utils
BuildRequires: extra-cmake-modules
BuildRequires: freetype-devel
BuildRequires: gcc-c++
BuildRequires: libFAudio-devel
BuildRequires: libappstream-glib
@@ -84,7 +85,7 @@ Collection of ROMs for use with 86Box.
# install icons
for i in 48 64 72 96 128 192 256 512; do
mkdir -p $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/${i}x${i}/apps
cp src/unix/assets/${i}x${i}/net.86box.86Box.png $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/${i}x${i}/apps/net.86box.86Box.png
cp src/unix/assets/${i}x${i}/net.86box.86Box.png $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/${i}x${i}/apps
done
# install desktop file
@@ -119,5 +120,5 @@ popd
%{_bindir}/roms
%changelog
* Sat Mar 19 2022 Robert de Rooy <robert.de.rooy[AT]gmail.com> 3.3-1
- Initial RPM release
* Fri Apr 22 2022 Robert de Rooy <robert.de.rooy[AT]gmail.com> 3.4.1-1
- Bump release

View File

@@ -10,7 +10,7 @@
</categories>
<launchable type="desktop-id">net.86box.86Box.desktop</launchable>
<releases>
<release version="3.3" date="2022-03-19"/>
<release version="3.5" date="2022-04-26"/>
</releases>
<content_rating type="oars-1.1" />
<description>