mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
138510106c | ||
|
|
948460cad7 | ||
|
|
3df8217a02 | ||
|
|
ec6726e85c | ||
|
|
348d86648f | ||
|
|
592c9b2776 | ||
|
|
5d156672e8 | ||
|
|
2f86622a68 | ||
|
|
a40b226e00 | ||
|
|
521f2fb707 | ||
|
|
a129d22a57 | ||
|
|
d4e14d2b05 | ||
|
|
dfa7774c4c | ||
|
|
c3182aedd9 | ||
|
|
f41f7b63e8 | ||
|
|
c143950dd1 | ||
|
|
4e991d603a |
+38
-14
@@ -22,34 +22,36 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: "recursive"
|
submodules: "recursive"
|
||||||
|
|
||||||
- name: Setup release mode parameters (for deploy)
|
- name: Setup release mode parameters (for deploy)
|
||||||
if: ${{ inputs.deploymode == 'release' }}
|
if: ${{ inputs.deploymode == 'release' }}
|
||||||
run: |
|
run: |
|
||||||
echo "BUILD_MODE=release" >> $GITHUB_ENV
|
echo "BUILD_MODE=release" >> $GITHUB_ENV
|
||||||
echo "BUILD_FLAGS=" >> $GITHUB_ENV
|
echo "BUILD_FLAGS=" >> $GITHUB_ENV
|
||||||
echo "Build mode is release"
|
echo "Build mode is release"
|
||||||
|
|
||||||
- name: Setup debug mode parameters (for continous build)
|
- name: Setup debug mode parameters (for continous build)
|
||||||
if: ${{ inputs.deploymode != 'release' }}
|
if: ${{ inputs.deploymode != 'release' }}
|
||||||
run: |
|
run: |
|
||||||
echo "BUILD_MODE=debug" >> $GITHUB_ENV
|
echo "BUILD_MODE=debug" >> $GITHUB_ENV
|
||||||
echo "BUILD_FLAGS=" >> $GITHUB_ENV
|
echo "BUILD_FLAGS=" >> $GITHUB_ENV
|
||||||
echo "Build mode is debug"
|
echo "Build mode is debug"
|
||||||
|
|
||||||
- name: Setup version for experimental
|
- name: Setup version for experimental
|
||||||
if: ${{ inputs.experimentalversion != '' }}
|
if: ${{ inputs.experimentalversion != '' }}
|
||||||
run: |
|
run: |
|
||||||
echo "[INFO] Experimental version ${{ inputs.experimentalversion }}"
|
echo "[INFO] Experimental version ${{ inputs.experimentalversion }}"
|
||||||
echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEXPERIMENTAL_VERSION=${{ inputs.experimentalversion }}" >> $GITHUB_ENV
|
echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEXPERIMENTAL_VERSION=${{ inputs.experimentalversion }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: "Install system dependencies"
|
- name: "Install system dependencies"
|
||||||
run: |
|
run: |
|
||||||
sudo apt update -qq
|
sudo apt update -qq
|
||||||
sudo apt install -y ninja-build cmake libgtk-3-dev libsecret-1-dev libgcrypt20-dev libsystemd-dev freeglut3-dev clang-12 nasm
|
sudo apt install -y clang-12 cmake freeglut3-dev libgcrypt20-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build
|
||||||
|
|
||||||
- name: "Bootstrap vcpkg"
|
- name: "Bootstrap vcpkg"
|
||||||
run: |
|
run: |
|
||||||
bash ./dependencies/vcpkg/bootstrap-vcpkg.sh
|
bash ./dependencies/vcpkg/bootstrap-vcpkg.sh
|
||||||
|
|
||||||
- name: 'Setup NuGet Credentials for vcpkg'
|
- name: 'Setup NuGet Credentials for vcpkg'
|
||||||
shell: 'bash'
|
shell: 'bash'
|
||||||
run: |
|
run: |
|
||||||
@@ -66,15 +68,12 @@ jobs:
|
|||||||
|
|
||||||
- name: "cmake"
|
- name: "cmake"
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
cmake -S . -B build ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DPORTABLE=OFF -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja
|
||||||
cd build
|
|
||||||
cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja
|
|
||||||
|
|
||||||
- name: "Build Cemu"
|
- name: "Build Cemu"
|
||||||
run: |
|
run: |
|
||||||
cd build
|
cmake --build build
|
||||||
ninja
|
|
||||||
|
|
||||||
- name: Prepare artifact
|
- name: Prepare artifact
|
||||||
if: ${{ inputs.deploymode == 'release' }}
|
if: ${{ inputs.deploymode == 'release' }}
|
||||||
run: mv bin/Cemu_release bin/Cemu
|
run: mv bin/Cemu_release bin/Cemu
|
||||||
@@ -85,8 +84,33 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: cemu-bin-linux-x64
|
name: cemu-bin-linux-x64
|
||||||
path: ./bin/Cemu
|
path: ./bin/Cemu
|
||||||
|
|
||||||
|
build-appimage:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
needs: build-ubuntu
|
||||||
|
steps:
|
||||||
|
- name: Checkout Upstream Repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: cemu-bin-linux-x64
|
||||||
|
path: bin
|
||||||
|
|
||||||
|
- name: "Install system dependencies"
|
||||||
|
run: |
|
||||||
|
sudo apt update -qq
|
||||||
|
sudo apt install -y clang-12 cmake freeglut3-dev libgcrypt20-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build
|
||||||
|
|
||||||
|
- name: "Build AppImage"
|
||||||
|
run: dist/linux/appimage.sh
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: cemu-appimage-x64
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
@@ -239,4 +263,4 @@ jobs:
|
|||||||
if: ${{ inputs.deploymode == 'release' }}
|
if: ${{ inputs.deploymode == 'release' }}
|
||||||
with:
|
with:
|
||||||
name: cemu-bin-macos-x64
|
name: cemu-bin-macos-x64
|
||||||
path: ./bin/Cemu.dmg
|
path: ./bin/Cemu.dmg
|
||||||
|
|||||||
@@ -13,13 +13,18 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs: call-release-build
|
needs: call-release-build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: cemu-bin-linux-x64
|
name: cemu-bin-linux-x64
|
||||||
path: cemu-bin-linux-x64
|
path: cemu-bin-linux-x64
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: cemu-appimage-x64
|
||||||
|
path: cemu-appimage-x64
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: cemu-bin-windows-x64
|
name: cemu-bin-windows-x64
|
||||||
@@ -53,7 +58,14 @@ jobs:
|
|||||||
mv cemu-bin-windows-x64/Cemu.exe ./${{ env.CEMU_FOLDER_NAME }}/Cemu.exe
|
mv cemu-bin-windows-x64/Cemu.exe ./${{ env.CEMU_FOLDER_NAME }}/Cemu.exe
|
||||||
zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }}
|
zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }}
|
||||||
rm -r ./${{ env.CEMU_FOLDER_NAME }}
|
rm -r ./${{ env.CEMU_FOLDER_NAME }}
|
||||||
|
|
||||||
|
- name: Create appimage
|
||||||
|
run: |
|
||||||
|
VERSION=${{ env.CEMU_VERSION }}
|
||||||
|
echo "Cemu Version is $VERSION"
|
||||||
|
ls cemu-appimage-x64
|
||||||
|
mv cemu-appimage-x64/Cemu-*-x86_64.AppImage upload/Cemu-$VERSION-x86_64.AppImage
|
||||||
|
|
||||||
- name: Create release from linux-bin
|
- name: Create release from linux-bin
|
||||||
run: |
|
run: |
|
||||||
ls ./
|
ls ./
|
||||||
|
|||||||
@@ -15,13 +15,18 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
needs: call-release-build
|
needs: call-release-build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: cemu-bin-linux-x64
|
name: cemu-bin-linux-x64
|
||||||
path: cemu-bin-linux-x64
|
path: cemu-bin-linux-x64
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: cemu-appimage-x64
|
||||||
|
path: cemu-appimage-x64
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: cemu-bin-windows-x64
|
name: cemu-bin-windows-x64
|
||||||
@@ -44,11 +49,7 @@ jobs:
|
|||||||
echo "Cemu CI version: $(./getversion)"
|
echo "Cemu CI version: $(./getversion)"
|
||||||
echo "CEMU_FOLDER_NAME=Cemu_$(./getversion)" >> $GITHUB_ENV
|
echo "CEMU_FOLDER_NAME=Cemu_$(./getversion)" >> $GITHUB_ENV
|
||||||
echo "CEMU_VERSION=$(./getversion)" >> $GITHUB_ENV
|
echo "CEMU_VERSION=$(./getversion)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Create appimage
|
|
||||||
run: |
|
|
||||||
echo "to do"
|
|
||||||
|
|
||||||
- name: Create release from windows-bin
|
- name: Create release from windows-bin
|
||||||
run: |
|
run: |
|
||||||
ls ./
|
ls ./
|
||||||
@@ -57,6 +58,13 @@ jobs:
|
|||||||
mv cemu-bin-windows-x64/Cemu.exe ./${{ env.CEMU_FOLDER_NAME }}/Cemu.exe
|
mv cemu-bin-windows-x64/Cemu.exe ./${{ env.CEMU_FOLDER_NAME }}/Cemu.exe
|
||||||
zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }}
|
zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }}
|
||||||
rm -r ./${{ env.CEMU_FOLDER_NAME }}
|
rm -r ./${{ env.CEMU_FOLDER_NAME }}
|
||||||
|
|
||||||
|
- name: Create appimage
|
||||||
|
run: |
|
||||||
|
VERSION=${{ env.CEMU_VERSION }}
|
||||||
|
echo "Cemu Version is $VERSION"
|
||||||
|
ls cemu-appimage-x64
|
||||||
|
mv cemu-appimage-x64/Cemu-*-x86_64.AppImage upload/Cemu-$VERSION-x86_64.AppImage
|
||||||
|
|
||||||
- name: Create release from ubuntu-bin
|
- name: Create release from ubuntu-bin
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required
|
|||||||
### Installing dependencies
|
### Installing dependencies
|
||||||
|
|
||||||
#### For Ubuntu and derivatives:
|
#### For Ubuntu and derivatives:
|
||||||
`sudo apt install -y git curl cmake ninja-build nasm libgtk-3-dev libsecret-1-dev libgcrypt20-dev libsystemd-dev freeglut3-dev libpulse-dev`
|
`sudo apt install -y cmake curl freeglut3-dev git libgcrypt20-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build`
|
||||||
|
|
||||||
*Additionally, for Ubuntu 22.04 only:*
|
*Additionally, for Ubuntu 22.04 only:*
|
||||||
- `sudo apt install -y clang-12`
|
- `sudo apt install -y clang-12`
|
||||||
@@ -33,10 +33,10 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required
|
|||||||
`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`
|
`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`
|
||||||
|
|
||||||
#### For Arch and derivatives:
|
#### For Arch and derivatives:
|
||||||
`sudo pacman -S --needed git cmake llvm clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse`
|
`sudo pacman -S --needed base-devel clang cmake freeglut git gtk3 libgcrypt libpulse libsecret linux-headers llvm nasm ninja systemd unzip zip`
|
||||||
|
|
||||||
#### For Fedora and derivatives:
|
#### For Fedora and derivatives:
|
||||||
`sudo dnf install git cmake clang ninja-build nasm kernel-headers gtk3-devel libsecret-devel libgcrypt-devel systemd-devel freeglut-devel perl-core zlib-devel cubeb-devel`
|
`sudo dnf install clang cmake cubeb-devel freeglut-devel git gtk3-devel kernel-headers libgcrypt-devel libsecret-devel nasm ninja-build perl-core systemd-devel zlib-devel`
|
||||||
|
|
||||||
### Build Cemu using cmake and clang
|
### Build Cemu using cmake and clang
|
||||||
1. `git clone --recursive https://github.com/cemu-project/Cemu`
|
1. `git clone --recursive https://github.com/cemu-project/Cemu`
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -z "${GITHUB_WORKSPACE}" ]; then
|
||||||
|
export GITHUB_WORKSPACE="."
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -sSfLO "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||||
|
chmod a+x linuxdeploy*.AppImage
|
||||||
|
curl -sSfL https://github.com$(curl https://github.com/probonopd/go-appimage/releases/expanded_assets/continuous | grep "mkappimage-.*-x86_64.AppImage" | head -n 1 | cut -d '"' -f 2) -o mkappimage.AppImage
|
||||||
|
chmod a+x mkappimage.AppImage
|
||||||
|
curl -sSfLO "https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh"
|
||||||
|
chmod a+x linuxdeploy-plugin-gtk.sh
|
||||||
|
|
||||||
|
if [[ ! -e /usr/lib/x86_64-linux-gnu ]]; then
|
||||||
|
sed -i 's#lib\/x86_64-linux-gnu#lib64#g' linuxdeploy-plugin-gtk.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p AppDir/usr/
|
||||||
|
cp dist/linux/{info.cemu.Cemu.desktop,info.cemu.Cemu.png} AppDir/
|
||||||
|
|
||||||
|
mkdir -p AppDir/usr/share/applications
|
||||||
|
mkdir -p AppDir/usr/share/icons/hicolor/scalable/apps
|
||||||
|
mkdir -p AppDir/usr/lib
|
||||||
|
|
||||||
|
cp -r bin AppDir/usr/
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/{libsepol.so.1,libffi.so.7,libpcre.so.3,libGLU.so.1} AppDir/usr/lib
|
||||||
|
|
||||||
|
chmod +x AppDir/usr/bin/Cemu
|
||||||
|
#chmod +x AppDir/AppRun
|
||||||
|
|
||||||
|
export UPD_INFO="gh-releases-zsync|cemu-project|Cemu|ci|Cemu.AppImage.zsync"
|
||||||
|
./linuxdeploy-x86_64.AppImage --appimage-extract-and-run\
|
||||||
|
--appdir="$GITHUB_WORKSPACE"/AppDir/ \
|
||||||
|
-d "$GITHUB_WORKSPACE"/AppDir/info.cemu.Cemu.desktop \
|
||||||
|
-i "$GITHUB_WORKSPACE"/AppDir/info.cemu.Cemu.png \
|
||||||
|
-e "$GITHUB_WORKSPACE"/AppDir/usr/bin/Cemu \
|
||||||
|
--plugin gtk
|
||||||
|
|
||||||
|
GITVERSION=$(git rev-parse --short HEAD)
|
||||||
|
echo $GITVERSION
|
||||||
|
if [[ -z ${GITVERSION} ]]; then
|
||||||
|
GITVERSION=experimental
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Cemu Version Cemu-${GITVERSION}"
|
||||||
|
rm AppDir/usr/lib/libwayland-client.so.0
|
||||||
|
VERSION=${GITVERSION} ./mkappimage.AppImage --appimage-extract-and-run "$GITHUB_WORKSPACE"/AppDir
|
||||||
|
|
||||||
|
mkdir -p "$GITHUB_WORKSPACE"/artifacts/
|
||||||
|
mv Cemu-${GITVERSION}-x86_64.AppImage "$GITHUB_WORKSPACE"/artifacts/
|
||||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -178,6 +178,8 @@ add_library(CemuCafe
|
|||||||
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
|
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
|
||||||
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
|
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
|
||||||
HW/Latte/Renderer/Vulkan/RendererShaderVk.h
|
HW/Latte/Renderer/Vulkan/RendererShaderVk.h
|
||||||
|
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp
|
||||||
|
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h
|
||||||
HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp
|
HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp
|
||||||
HW/Latte/Renderer/Vulkan/VKRBase.h
|
HW/Latte/Renderer/Vulkan/VKRBase.h
|
||||||
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
|
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
|
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
|
||||||
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
|
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
|
||||||
#include "audio/IAudioAPI.h"
|
#include "audio/IAudioAPI.h"
|
||||||
|
#include "audio/IAudioInputAPI.h"
|
||||||
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
|
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
|
||||||
|
|
||||||
#include "config/ActiveSettings.h"
|
#include "config/ActiveSettings.h"
|
||||||
@@ -402,6 +403,7 @@ void cemu_initForGame()
|
|||||||
GraphicPack2::ActivateForCurrentTitle();
|
GraphicPack2::ActivateForCurrentTitle();
|
||||||
// print audio log
|
// print audio log
|
||||||
IAudioAPI::PrintLogging();
|
IAudioAPI::PrintLogging();
|
||||||
|
IAudioInputAPI::PrintLogging();
|
||||||
// everything initialized
|
// everything initialized
|
||||||
forceLog_printf("------- Run title -------");
|
forceLog_printf("------- Run title -------");
|
||||||
// wait till GPU thread is initialized
|
// wait till GPU thread is initialized
|
||||||
|
|||||||
@@ -352,14 +352,19 @@ void OpenGLRenderer::NotifyLatteCommandProcessorIdle()
|
|||||||
glFlush();
|
glFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::EnableVSync(int state)
|
void OpenGLRenderer::UpdateVSyncState()
|
||||||
{
|
{
|
||||||
|
int configValue = GetConfig().vsync.GetValue();
|
||||||
|
if(m_activeVSyncState != configValue)
|
||||||
|
{
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
if(wglSwapIntervalEXT)
|
if(wglSwapIntervalEXT)
|
||||||
wglSwapIntervalEXT(state); // 1 = enabled, 0 = disabled
|
wglSwapIntervalEXT(configValue); // 1 = enabled, 0 = disabled
|
||||||
#else
|
#else
|
||||||
cemuLog_log(LogType::Force, "OpenGL vsync not implemented");
|
cemuLog_log(LogType::Force, "OpenGL vsync not implemented");
|
||||||
#endif
|
#endif
|
||||||
|
m_activeVSyncState = configValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRunningInWine();
|
bool IsRunningInWine();
|
||||||
@@ -438,6 +443,7 @@ void OpenGLRenderer::EnableDebugMode()
|
|||||||
void OpenGLRenderer::SwapBuffers(bool swapTV, bool swapDRC)
|
void OpenGLRenderer::SwapBuffers(bool swapTV, bool swapDRC)
|
||||||
{
|
{
|
||||||
GLCanvas_SwapBuffers(swapTV, swapDRC);
|
GLCanvas_SwapBuffers(swapTV, swapDRC);
|
||||||
|
UpdateVSyncState();
|
||||||
|
|
||||||
if (swapTV)
|
if (swapTV)
|
||||||
cleanupAfterFrame();
|
cleanupAfterFrame();
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
void Flush(bool waitIdle = false) override;
|
void Flush(bool waitIdle = false) override;
|
||||||
void NotifyLatteCommandProcessorIdle() override;
|
void NotifyLatteCommandProcessorIdle() override;
|
||||||
|
|
||||||
void EnableVSync(int state) override;
|
void UpdateVSyncState();
|
||||||
|
|
||||||
void EnableDebugMode() override;
|
void EnableDebugMode() override;
|
||||||
void SwapBuffers(bool swapTV = true, bool swapDRC = true) override;
|
void SwapBuffers(bool swapTV = true, bool swapDRC = true) override;
|
||||||
@@ -168,6 +168,7 @@ private:
|
|||||||
GLuint m_defaultFramebufferId;
|
GLuint m_defaultFramebufferId;
|
||||||
GLuint m_pipeline = 0;
|
GLuint m_pipeline = 0;
|
||||||
|
|
||||||
|
int m_activeVSyncState{};
|
||||||
bool m_isPadViewContext{};
|
bool m_isPadViewContext{};
|
||||||
|
|
||||||
// rendertarget viewport
|
// rendertarget viewport
|
||||||
@@ -282,4 +283,4 @@ private:
|
|||||||
std::vector<bufferCacheReleaseQueueEntry_t> bufferCacheEntries;
|
std::vector<bufferCacheReleaseQueueEntry_t> bufferCacheEntries;
|
||||||
}m_destructionQueues;
|
}m_destructionQueues;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ public:
|
|||||||
virtual bool GetVRAMInfo(int& usageInMB, int& totalInMB) const;
|
virtual bool GetVRAMInfo(int& usageInMB, int& totalInMB) const;
|
||||||
|
|
||||||
virtual void EnableDebugMode() {}
|
virtual void EnableDebugMode() {}
|
||||||
virtual void EnableVSync(int state) = 0;
|
|
||||||
|
|
||||||
virtual void ClearColorbuffer(bool padView) = 0;
|
virtual void ClearColorbuffer(bool padView) = 0;
|
||||||
virtual void DrawEmptyFrame(bool mainWindow) = 0;
|
virtual void DrawEmptyFrame(bool mainWindow) = 0;
|
||||||
@@ -176,4 +175,4 @@ protected:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<Renderer> g_renderer;
|
extern std::unique_ptr<Renderer> g_renderer;
|
||||||
|
|||||||
@@ -0,0 +1,367 @@
|
|||||||
|
#include "SwapchainInfoVk.h"
|
||||||
|
|
||||||
|
#include "config/CemuConfig.h"
|
||||||
|
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||||
|
#include "Cafe/HW/Latte/Core/LatteTiming.h"
|
||||||
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||||
|
|
||||||
|
void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDevice)
|
||||||
|
{
|
||||||
|
m_physicalDevice = physicalDevice;
|
||||||
|
m_logicalDevice = logicalDevice;
|
||||||
|
const auto details = QuerySwapchainSupport(surface, physicalDevice);
|
||||||
|
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
|
||||||
|
swapchainExtent = ChooseSwapExtent(details.capabilities, getSize());
|
||||||
|
|
||||||
|
// calculate number of swapchain presentation images
|
||||||
|
uint32_t image_count = details.capabilities.minImageCount + 1;
|
||||||
|
if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount)
|
||||||
|
image_count = details.capabilities.maxImageCount;
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, swapchainExtent);
|
||||||
|
create_info.oldSwapchain = nullptr;
|
||||||
|
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
|
VkResult result = vkCreateSwapchainKHR(logicalDevice, &create_info, nullptr, &swapchain);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Error attempting to create a swapchain");
|
||||||
|
|
||||||
|
sizeOutOfDate = false;
|
||||||
|
|
||||||
|
result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, nullptr);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Error attempting to retrieve the count of swapchain images");
|
||||||
|
|
||||||
|
|
||||||
|
m_swapchainImages.resize(image_count);
|
||||||
|
result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, m_swapchainImages.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Error attempting to retrieve swapchain images");
|
||||||
|
// create default renderpass
|
||||||
|
VkAttachmentDescription colorAttachment = {};
|
||||||
|
colorAttachment.format = m_surfaceFormat.format;
|
||||||
|
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
|
VkAttachmentReference colorAttachmentRef = {};
|
||||||
|
colorAttachmentRef.attachment = 0;
|
||||||
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
VkSubpassDescription subpass = {};
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = &colorAttachmentRef;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo renderPassInfo = {};
|
||||||
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderPassInfo.attachmentCount = 1;
|
||||||
|
renderPassInfo.pAttachments = &colorAttachment;
|
||||||
|
renderPassInfo.subpassCount = 1;
|
||||||
|
renderPassInfo.pSubpasses = &subpass;
|
||||||
|
result = vkCreateRenderPass(logicalDevice, &renderPassInfo, nullptr, &m_swapchainRenderPass);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Failed to create renderpass for swapchain");
|
||||||
|
|
||||||
|
// create swapchain image views
|
||||||
|
m_swapchainImageViews.resize(m_swapchainImages.size());
|
||||||
|
for (sint32 i = 0; i < m_swapchainImages.size(); i++)
|
||||||
|
{
|
||||||
|
VkImageViewCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.image = m_swapchainImages[i];
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
createInfo.format = m_surfaceFormat.format;
|
||||||
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
createInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
createInfo.subresourceRange.levelCount = 1;
|
||||||
|
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
createInfo.subresourceRange.layerCount = 1;
|
||||||
|
result = vkCreateImageView(logicalDevice, &createInfo, nullptr, &m_swapchainImageViews[i]);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Failed to create imageviews for swapchain");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create swapchain framebuffers
|
||||||
|
m_swapchainFramebuffers.resize(m_swapchainImages.size());
|
||||||
|
for (size_t i = 0; i < m_swapchainImages.size(); i++)
|
||||||
|
{
|
||||||
|
VkImageView attachments[1];
|
||||||
|
attachments[0] = m_swapchainImageViews[i];
|
||||||
|
// create framebuffer
|
||||||
|
VkFramebufferCreateInfo framebufferInfo = {};
|
||||||
|
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
framebufferInfo.renderPass = m_swapchainRenderPass;
|
||||||
|
framebufferInfo.attachmentCount = 1;
|
||||||
|
framebufferInfo.pAttachments = attachments;
|
||||||
|
framebufferInfo.width = swapchainExtent.width;
|
||||||
|
framebufferInfo.height = swapchainExtent.height;
|
||||||
|
framebufferInfo.layers = 1;
|
||||||
|
result = vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &m_swapchainFramebuffers[i]);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Failed to create framebuffer for swapchain");
|
||||||
|
}
|
||||||
|
m_swapchainPresentSemaphores.resize(m_swapchainImages.size());
|
||||||
|
// create present semaphore
|
||||||
|
VkSemaphoreCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
for (auto& semaphore : m_swapchainPresentSemaphores){
|
||||||
|
if (vkCreateSemaphore(logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Failed to create semaphore for swapchain present");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_acquireSemaphores.resize(m_swapchainImages.size());
|
||||||
|
for (auto& semaphore : m_acquireSemaphores)
|
||||||
|
{
|
||||||
|
VkSemaphoreCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
if (vkCreateSemaphore(logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Failed to create semaphore for swapchain acquire");
|
||||||
|
}
|
||||||
|
m_acquireIndex = 0;
|
||||||
|
|
||||||
|
VkFenceCreateInfo fenceInfo = {};
|
||||||
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
result = vkCreateFence(logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
UnrecoverableError("Failed to create fence for swapchain");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainInfoVk::Cleanup()
|
||||||
|
{
|
||||||
|
m_swapchainImages.clear();
|
||||||
|
|
||||||
|
for (auto& sem: m_swapchainPresentSemaphores)
|
||||||
|
vkDestroySemaphore(m_logicalDevice, sem, nullptr);
|
||||||
|
m_swapchainPresentSemaphores.clear();
|
||||||
|
|
||||||
|
for (auto& itr: m_acquireSemaphores)
|
||||||
|
vkDestroySemaphore(m_logicalDevice, itr, nullptr);
|
||||||
|
m_acquireSemaphores.clear();
|
||||||
|
|
||||||
|
if (m_swapchainRenderPass)
|
||||||
|
{
|
||||||
|
vkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr);
|
||||||
|
m_swapchainRenderPass = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& imageView : m_swapchainImageViews)
|
||||||
|
vkDestroyImageView(m_logicalDevice, imageView, nullptr);
|
||||||
|
m_swapchainImageViews.clear();
|
||||||
|
|
||||||
|
for (auto& framebuffer : m_swapchainFramebuffers)
|
||||||
|
vkDestroyFramebuffer(m_logicalDevice, framebuffer, nullptr);
|
||||||
|
m_swapchainFramebuffers.clear();
|
||||||
|
|
||||||
|
|
||||||
|
if (m_imageAvailableFence)
|
||||||
|
{
|
||||||
|
vkDestroyFence(m_logicalDevice, m_imageAvailableFence, nullptr);
|
||||||
|
m_imageAvailableFence = nullptr;
|
||||||
|
}
|
||||||
|
if (swapchain)
|
||||||
|
{
|
||||||
|
vkDestroySwapchainKHR(m_logicalDevice, swapchain, nullptr);
|
||||||
|
swapchain = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwapchainInfoVk::IsValid() const
|
||||||
|
{
|
||||||
|
return swapchain && m_imageAvailableFence;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapchainInfoVk::UnrecoverableError(const char* errMsg)
|
||||||
|
{
|
||||||
|
forceLog_printf("Unrecoverable error in Vulkan swapchain");
|
||||||
|
forceLog_printf("Msg: %s", errMsg);
|
||||||
|
throw std::runtime_error(errMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapchainInfoVk::QueueFamilyIndices SwapchainInfoVk::FindQueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device)
|
||||||
|
{
|
||||||
|
uint32_t queueFamilyCount = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
||||||
|
|
||||||
|
QueueFamilyIndices indices;
|
||||||
|
for (int i = 0; i < (int)queueFamilies.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& queueFamily = queueFamilies[i];
|
||||||
|
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||||
|
indices.graphicsFamily = i;
|
||||||
|
|
||||||
|
VkBool32 presentSupport = false;
|
||||||
|
const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error(fmt::format("Error while attempting to check if a surface supports presentation: {}", result));
|
||||||
|
|
||||||
|
if (queueFamily.queueCount > 0 && presentSupport)
|
||||||
|
indices.presentFamily = i;
|
||||||
|
|
||||||
|
if (indices.IsComplete())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device)
|
||||||
|
{
|
||||||
|
SwapchainSupportDetails details;
|
||||||
|
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
if (result != VK_ERROR_SURFACE_LOST_KHR)
|
||||||
|
forceLog_printf("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed. Error %d", (sint32)result);
|
||||||
|
throw std::runtime_error(fmt::format("Unable to retrieve physical device surface capabilities: {}", result));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t formatCount = 0;
|
||||||
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
forceLog_printf("vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error %d", (sint32)result);
|
||||||
|
throw std::runtime_error(fmt::format("Unable to retrieve the number of formats for a surface on a physical device: {}", result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formatCount != 0)
|
||||||
|
{
|
||||||
|
details.formats.resize(formatCount);
|
||||||
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
forceLog_printf("vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error %d", (sint32)result);
|
||||||
|
throw std::runtime_error(fmt::format("Unable to retrieve the formats for a surface on a physical device: {}", result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t presentModeCount = 0;
|
||||||
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
forceLog_printf("vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error %d", (sint32)result);
|
||||||
|
throw std::runtime_error(fmt::format("Unable to retrieve the count of present modes for a surface on a physical device: {}", result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presentModeCount != 0)
|
||||||
|
{
|
||||||
|
details.presentModes.resize(presentModeCount);
|
||||||
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
forceLog_printf("vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error %d", (sint32)result);
|
||||||
|
throw std::runtime_error(fmt::format("Unable to retrieve the present modes for a surface on a physical device: {}", result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const
|
||||||
|
{
|
||||||
|
if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
|
||||||
|
return{ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||||
|
|
||||||
|
for (const auto& format : formats)
|
||||||
|
{
|
||||||
|
bool useSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
|
||||||
|
|
||||||
|
if (useSRGB)
|
||||||
|
{
|
||||||
|
if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const
|
||||||
|
{
|
||||||
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32>::max())
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
|
||||||
|
VkExtent2D actualExtent = { (uint32)size.x, (uint32)size.y };
|
||||||
|
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||||
|
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
|
||||||
|
return actualExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes)
|
||||||
|
{
|
||||||
|
const auto vsyncState = (VSync)GetConfig().vsync.GetValue();
|
||||||
|
if (vsyncState == VSync::MAILBOX)
|
||||||
|
{
|
||||||
|
if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_MAILBOX_KHR) != modes.cend())
|
||||||
|
return VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
|
|
||||||
|
forceLog_printf("Vulkan: Can't find mailbox present mode");
|
||||||
|
}
|
||||||
|
else if (vsyncState == VSync::Immediate)
|
||||||
|
{
|
||||||
|
if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.cend())
|
||||||
|
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
|
|
||||||
|
forceLog_printf("Vulkan: Can't find immediate present mode");
|
||||||
|
}
|
||||||
|
else if (vsyncState == VSync::SYNC_AND_LIMIT)
|
||||||
|
{
|
||||||
|
LatteTiming_EnableHostDrivenVSync();
|
||||||
|
// use immediate mode if available, other wise fall back to
|
||||||
|
//if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.cend())
|
||||||
|
// return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
|
//else
|
||||||
|
// forceLog_printf("Vulkan: Present mode 'immediate' not available. Vsync might not behave as intended");
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent)
|
||||||
|
{
|
||||||
|
VkSwapchainCreateInfoKHR createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
createInfo.surface = surface;
|
||||||
|
createInfo.minImageCount = imageCount;
|
||||||
|
createInfo.imageFormat = surfaceFormat.format;
|
||||||
|
createInfo.imageExtent = extent;
|
||||||
|
createInfo.imageArrayLayers = 1;
|
||||||
|
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
|
const QueueFamilyIndices indices = FindQueueFamilies(surface, m_physicalDevice);
|
||||||
|
uint32_t queueFamilyIndices[] = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily };
|
||||||
|
if (indices.graphicsFamily != indices.presentFamily)
|
||||||
|
{
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
createInfo.queueFamilyIndexCount = 2;
|
||||||
|
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
createInfo.preTransform = swapchainSupport.capabilities.currentTransform;
|
||||||
|
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
createInfo.presentMode = ChoosePresentMode(swapchainSupport.presentModes);
|
||||||
|
createInfo.clipped = VK_TRUE;
|
||||||
|
|
||||||
|
forceLogDebug_printf("vulkan presentation mode: %d", createInfo.presentMode);
|
||||||
|
return createInfo;
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/math/vector2.h"
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
struct SwapchainInfoVk
|
||||||
|
{
|
||||||
|
enum class VSync
|
||||||
|
{
|
||||||
|
// values here must match GeneralSettings2::m_vsync
|
||||||
|
Immediate = 0,
|
||||||
|
FIFO = 1,
|
||||||
|
MAILBOX = 2,
|
||||||
|
SYNC_AND_LIMIT = 3, // synchronize emulated vsync events to monitor vsync. But skip events if rate higher than virtual vsync period
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueueFamilyIndices
|
||||||
|
{
|
||||||
|
int32_t graphicsFamily = -1;
|
||||||
|
int32_t presentFamily = -1;
|
||||||
|
|
||||||
|
bool IsComplete() const { return graphicsFamily >= 0 && presentFamily >= 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SwapchainSupportDetails
|
||||||
|
{
|
||||||
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
|
std::vector<VkPresentModeKHR> presentModes;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Cleanup();
|
||||||
|
void Create(VkPhysicalDevice physicalDevice, VkDevice logicalDevice);
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
|
||||||
|
static void UnrecoverableError(const char* errMsg);
|
||||||
|
|
||||||
|
// todo: move this function somewhere more sensible. Not directly swapchain related
|
||||||
|
static QueueFamilyIndices FindQueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device);
|
||||||
|
static SwapchainSupportDetails QuerySwapchainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
||||||
|
|
||||||
|
VkPresentModeKHR ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes);
|
||||||
|
VkSurfaceFormatKHR ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const;
|
||||||
|
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const;
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent);
|
||||||
|
|
||||||
|
|
||||||
|
void setSize(const Vector2i& newSize)
|
||||||
|
{
|
||||||
|
desiredExtent = newSize;
|
||||||
|
sizeOutOfDate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector2i& getSize() const
|
||||||
|
{
|
||||||
|
return desiredExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapchainInfoVk(VkSurfaceKHR surface, bool mainWindow)
|
||||||
|
: surface(surface), mainWindow(mainWindow) {}
|
||||||
|
SwapchainInfoVk(const SwapchainInfoVk&) = delete;
|
||||||
|
SwapchainInfoVk(SwapchainInfoVk&&) noexcept = default;
|
||||||
|
~SwapchainInfoVk()
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mainWindow{};
|
||||||
|
|
||||||
|
bool sizeOutOfDate{};
|
||||||
|
bool m_usesSRGB = false;
|
||||||
|
bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
||||||
|
|
||||||
|
VkPhysicalDevice m_physicalDevice{};
|
||||||
|
VkDevice m_logicalDevice{};
|
||||||
|
VkSurfaceKHR surface{};
|
||||||
|
VkSurfaceFormatKHR m_surfaceFormat{};
|
||||||
|
VkSwapchainKHR swapchain{};
|
||||||
|
VkExtent2D swapchainExtent{};
|
||||||
|
VkFence m_imageAvailableFence{};
|
||||||
|
uint32 swapchainImageIndex = (uint32)-1;
|
||||||
|
uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
|
||||||
|
VSync m_vsyncState = VSync::Immediate;
|
||||||
|
|
||||||
|
|
||||||
|
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
||||||
|
std::vector<VkImage> m_swapchainImages;
|
||||||
|
std::vector<VkImageView> m_swapchainImageViews;
|
||||||
|
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
||||||
|
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
|
||||||
|
std::vector<VkSemaphore> m_acquireSemaphores; // indexed by acquireIndex
|
||||||
|
|
||||||
|
VkRenderPass m_swapchainRenderPass = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector2i desiredExtent;
|
||||||
|
};
|
||||||
@@ -457,6 +457,12 @@ void PipelineCompiler::InitVertexInputState(const LatteContextRegister& latteReg
|
|||||||
uint32 bufferStride = (latteRegister.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;
|
uint32 bufferStride = (latteRegister.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;
|
||||||
|
|
||||||
VkVertexInputBindingDescription entry{};
|
VkVertexInputBindingDescription entry{};
|
||||||
|
#if BOOST_OS_MACOS
|
||||||
|
if (bufferStride % 4 != 0) {
|
||||||
|
forceLog_printf("MoltenVK error: vertex stride was %d, expected multiple of 4", bufferStride);
|
||||||
|
bufferStride = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
entry.stride = bufferStride;
|
entry.stride = bufferStride;
|
||||||
if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)
|
if (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)
|
||||||
entry.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
entry.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
|
||||||
@@ -6,6 +7,7 @@
|
|||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h"
|
||||||
|
#include "Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h"
|
||||||
#include "util/math/vector2.h"
|
#include "util/math/vector2.h"
|
||||||
#include "util/helpers/Semaphore.h"
|
#include "util/helpers/Semaphore.h"
|
||||||
#include "util/containers/flat_hash_map.hpp"
|
#include "util/containers/flat_hash_map.hpp"
|
||||||
@@ -124,6 +126,9 @@ class VulkanRenderer : public Renderer
|
|||||||
friend class LatteTextureReadbackInfoVk;
|
friend class LatteTextureReadbackInfoVk;
|
||||||
friend class PipelineCompiler;
|
friend class PipelineCompiler;
|
||||||
|
|
||||||
|
using VSync = SwapchainInfoVk::VSync;
|
||||||
|
using QueueFamilyIndices = SwapchainInfoVk::QueueFamilyIndices;
|
||||||
|
|
||||||
static const inline int UNIFORMVAR_RINGBUFFER_SIZE = 1024 * 1024 * 16; // 16MB
|
static const inline int UNIFORMVAR_RINGBUFFER_SIZE = 1024 * 1024 * 16; // 16MB
|
||||||
static const inline int INDEX_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB
|
static const inline int INDEX_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB
|
||||||
|
|
||||||
@@ -132,15 +137,7 @@ class VulkanRenderer : public Renderer
|
|||||||
static const inline int OCCLUSION_QUERY_POOL_SIZE = 1024;
|
static const inline int OCCLUSION_QUERY_POOL_SIZE = 1024;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class VSync
|
|
||||||
{
|
|
||||||
// values here must match GeneralSettings2::m_vsync
|
|
||||||
Immediate = 0,
|
|
||||||
FIFO = 1,
|
|
||||||
MAILBOX = 2,
|
|
||||||
SYNC_AND_LIMIT = 3, // synchronize emulated vsync events to monitor vsync. But skip events if rate higher than virtual vsync period
|
|
||||||
};
|
|
||||||
|
|
||||||
// memory management
|
// memory management
|
||||||
VKRMemoryManager* memoryManager{};
|
VKRMemoryManager* memoryManager{};
|
||||||
VKRMemoryManager* GetMemoryManager() const { return memoryManager; };
|
VKRMemoryManager* GetMemoryManager() const { return memoryManager; };
|
||||||
@@ -185,18 +182,20 @@ public:
|
|||||||
|
|
||||||
void GetDeviceFeatures();
|
void GetDeviceFeatures();
|
||||||
void DetermineVendor();
|
void DetermineVendor();
|
||||||
void Initialize(const Vector2i& size, bool isMainWindow);
|
void Initialize(const Vector2i& size, bool mainWindow);
|
||||||
|
|
||||||
|
const std::unique_ptr<SwapchainInfoVk>& GetChainInfoPtr(bool mainWindow) const;
|
||||||
|
SwapchainInfoVk& GetChainInfo(bool mainWindow) const;
|
||||||
|
|
||||||
|
void StopUsingPadAndWait();
|
||||||
bool IsPadWindowActive() override;
|
bool IsPadWindowActive() override;
|
||||||
|
|
||||||
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;
|
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;
|
||||||
void ResizeSwapchain(const Vector2i& size, bool isMainWindow);
|
void SetSwapchainTargetSize(const Vector2i& size, bool mainWindow);
|
||||||
|
|
||||||
void QueryMemoryInfo();
|
void QueryMemoryInfo();
|
||||||
void QueryAvailableFormats();
|
void QueryAvailableFormats();
|
||||||
|
|
||||||
void EnableVSync(int state) override;
|
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
static VkSurfaceKHR CreateWinSurface(VkInstance instance, HWND hwindow);
|
static VkSurfaceKHR CreateWinSurface(VkInstance instance, HWND hwindow);
|
||||||
#endif
|
#endif
|
||||||
@@ -212,7 +211,7 @@ public:
|
|||||||
void ImguiInit();
|
void ImguiInit();
|
||||||
VkInstance GetVkInstance() const { return m_instance; }
|
VkInstance GetVkInstance() const { return m_instance; }
|
||||||
VkDevice GetLogicalDevice() const { return m_logicalDevice; }
|
VkDevice GetLogicalDevice() const { return m_logicalDevice; }
|
||||||
VkPhysicalDevice GetPhysicalDevice() const { return m_physical_device; }
|
VkPhysicalDevice GetPhysicalDevice() const { return m_physicalDevice; }
|
||||||
|
|
||||||
VkDescriptorPool GetDescriptorPool() const { return m_descriptorPool; }
|
VkDescriptorPool GetDescriptorPool() const { return m_descriptorPool; }
|
||||||
|
|
||||||
@@ -433,85 +432,14 @@ private:
|
|||||||
bool drawSequenceSkip; // if true, skip draw_execute()
|
bool drawSequenceSkip; // if true, skip draw_execute()
|
||||||
}m_state;
|
}m_state;
|
||||||
|
|
||||||
// swapchain - todo move this to m_swapchainState
|
std::unique_ptr<SwapchainInfoVk> m_mainSwapchainInfo{}, m_padSwapchainInfo{};
|
||||||
struct SwapChainInfo
|
Semaphore m_padCloseReadySemaphore;
|
||||||
{
|
bool m_destroyPadSwapchainNextAcquire = false;
|
||||||
SwapChainInfo(VkDevice device, VkSurfaceKHR surface) : m_device(device), surface(surface) {}
|
|
||||||
SwapChainInfo(const SwapChainInfo&) = delete;
|
|
||||||
SwapChainInfo(SwapChainInfo&&) noexcept = default;
|
|
||||||
~SwapChainInfo()
|
|
||||||
{
|
|
||||||
if (m_swapChainRenderPass)
|
|
||||||
{
|
|
||||||
vkDestroyRenderPass(m_device, m_swapChainRenderPass, nullptr);
|
|
||||||
m_swapChainRenderPass = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
if (swapChain)
|
|
||||||
{
|
|
||||||
vkDestroySwapchainKHR(m_device, swapChain, nullptr);
|
|
||||||
swapChain = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
for (auto& imageView : m_swapchainImageViews)
|
|
||||||
vkDestroyImageView(m_device, imageView, nullptr);
|
|
||||||
m_swapchainImageViews.clear();
|
|
||||||
for (auto& framebuffer : m_swapchainFramebuffers)
|
|
||||||
vkDestroyFramebuffer(m_device, framebuffer, nullptr);
|
|
||||||
m_swapchainFramebuffers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDevice m_device;
|
|
||||||
|
|
||||||
VkSurfaceKHR surface{};
|
|
||||||
VkSwapchainKHR swapChain{};
|
|
||||||
VkExtent2D swapchainExtend{};
|
|
||||||
uint32 swapchainImageIndex = (uint32)-1;
|
|
||||||
uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
|
|
||||||
|
|
||||||
struct AcquireInfo
|
|
||||||
{
|
|
||||||
// move fence here?
|
|
||||||
VkSemaphore acquireSemaphore;
|
|
||||||
};
|
|
||||||
std::vector<AcquireInfo> m_acquireInfo; // indexed by acquireIndex
|
|
||||||
|
|
||||||
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
|
||||||
std::vector<VkImage> m_swapchainImages;
|
|
||||||
std::vector<VkImageView> m_swapchainImageViews;
|
|
||||||
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
|
||||||
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
|
|
||||||
|
|
||||||
VkFence m_imageAvailableFence = nullptr;
|
|
||||||
VkRenderPass m_swapChainRenderPass = nullptr;
|
|
||||||
VkRenderPass m_imguiRenderPass = nullptr;
|
|
||||||
};
|
|
||||||
std::unique_ptr<SwapChainInfo> m_mainSwapchainInfo{}, m_padSwapchainInfo{};
|
|
||||||
bool IsSwapchainInfoValid(bool mainWindow) const;
|
bool IsSwapchainInfoValid(bool mainWindow) const;
|
||||||
VkSwapchainKHR CreateSwapChain(SwapChainInfo& swap_chain_info, const Vector2i& size, bool mainwindow);
|
|
||||||
|
|
||||||
struct
|
VkRenderPass m_imguiRenderPass = nullptr;
|
||||||
{
|
|
||||||
bool resizeRequestedMainWindow{};
|
|
||||||
Vector2i newExtentMainWindow;
|
|
||||||
bool resizeRequestedPadWindow{};
|
|
||||||
Vector2i newExtentPadWindow;
|
|
||||||
bool tvHasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
|
||||||
bool drcHasDefinedSwapchainImage{};
|
|
||||||
}m_swapchainState;
|
|
||||||
|
|
||||||
VkDescriptorPool m_descriptorPool;
|
VkDescriptorPool m_descriptorPool;
|
||||||
VkSurfaceFormatKHR m_swapchainFormat;
|
|
||||||
|
|
||||||
bool m_tvBufferUsesSRGB = false;
|
|
||||||
bool m_drvBufferUsesSRGB = false;
|
|
||||||
|
|
||||||
struct QueueFamilyIndices
|
|
||||||
{
|
|
||||||
int32_t graphicsFamily = -1;
|
|
||||||
int32_t presentFamily = -1;
|
|
||||||
|
|
||||||
bool IsComplete() const { return graphicsFamily >= 0 && presentFamily >= 0; }
|
|
||||||
};
|
|
||||||
static QueueFamilyIndices FindQueueFamilies(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
|
||||||
|
|
||||||
struct FeatureControl
|
struct FeatureControl
|
||||||
{
|
{
|
||||||
@@ -557,15 +485,8 @@ private:
|
|||||||
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);
|
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);
|
||||||
static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);
|
static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);
|
||||||
|
|
||||||
void SwapBuffer(bool main_window);
|
void UpdateVSyncState(bool mainWindow);
|
||||||
VSync m_vsync_state = VSync::Immediate;
|
void SwapBuffer(bool mainWindow);
|
||||||
|
|
||||||
struct SwapChainSupportDetails
|
|
||||||
{
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
|
||||||
std::vector<VkSurfaceFormatKHR> formats;
|
|
||||||
std::vector<VkPresentModeKHR> presentModes;
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDescriptorSetLayout m_swapchainDescriptorSetLayout;
|
VkDescriptorSetLayout m_swapchainDescriptorSetLayout;
|
||||||
|
|
||||||
@@ -573,14 +494,9 @@ private:
|
|||||||
|
|
||||||
// swapchain
|
// swapchain
|
||||||
|
|
||||||
static SwapChainSupportDetails QuerySwapChainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> CreateQueueCreateInfos(const std::set<int>& uniqueQueueFamilies) const;
|
std::vector<VkDeviceQueueCreateInfo> CreateQueueCreateInfos(const std::set<int>& uniqueQueueFamilies) const;
|
||||||
VkDeviceCreateInfo CreateDeviceCreateInfo(const std::vector<VkDeviceQueueCreateInfo>& queueCreateInfos, const VkPhysicalDeviceFeatures& deviceFeatures, const void* deviceExtensionStructs, std::vector<const char*>& used_extensions) const;
|
VkDeviceCreateInfo CreateDeviceCreateInfo(const std::vector<VkDeviceQueueCreateInfo>& queueCreateInfos, const VkPhysicalDeviceFeatures& deviceFeatures, const void* deviceExtensionStructs, std::vector<const char*>& used_extensions) const;
|
||||||
static bool IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
static bool IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
||||||
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats, bool mainWindow) const;
|
|
||||||
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& modes);
|
|
||||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const;
|
|
||||||
VkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapChainSupportDetails& swapChainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent);
|
|
||||||
|
|
||||||
void CreateCommandPool();
|
void CreateCommandPool();
|
||||||
void CreateCommandBuffers();
|
void CreateCommandBuffers();
|
||||||
@@ -642,8 +558,8 @@ private:
|
|||||||
void CreatePipelineCache();
|
void CreatePipelineCache();
|
||||||
VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;
|
VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;
|
||||||
VkPipeline backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader);
|
VkPipeline backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader);
|
||||||
void AcquireNextSwapchainImage(bool main_window);
|
bool AcquireNextSwapchainImage(bool mainWindow);
|
||||||
void RecreateSwapchain(bool mainwindow);
|
void RecreateSwapchain(bool mainWindow, bool skipCreate = false);
|
||||||
|
|
||||||
// streamout
|
// streamout
|
||||||
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
||||||
@@ -666,7 +582,7 @@ private:
|
|||||||
|
|
||||||
std::vector<const char*> m_layerNames;
|
std::vector<const char*> m_layerNames;
|
||||||
VkInstance m_instance = VK_NULL_HANDLE;
|
VkInstance m_instance = VK_NULL_HANDLE;
|
||||||
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
|
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||||
VkDevice m_logicalDevice = VK_NULL_HANDLE;
|
VkDevice m_logicalDevice = VK_NULL_HANDLE;
|
||||||
VkDebugUtilsMessengerEXT m_debugCallback = nullptr;
|
VkDebugUtilsMessengerEXT m_debugCallback = nullptr;
|
||||||
volatile bool m_destructionRequested = false;
|
volatile bool m_destructionRequested = false;
|
||||||
|
|||||||
@@ -1196,30 +1196,15 @@ void VulkanRenderer::draw_setRenderPass()
|
|||||||
// update self-dependency flag
|
// update self-dependency flag
|
||||||
if (m_state.descriptorSetsChanged || m_state.activeRenderpassFBO != fboVk)
|
if (m_state.descriptorSetsChanged || m_state.activeRenderpassFBO != fboVk)
|
||||||
{
|
{
|
||||||
bool hadDep = m_state.hasRenderSelfDependency;
|
|
||||||
m_state.hasRenderSelfDependency = fboVk->CheckForCollision(m_state.activeVertexDS, m_state.activeGeometryDS, m_state.activePixelDS);
|
m_state.hasRenderSelfDependency = fboVk->CheckForCollision(m_state.activeVertexDS, m_state.activeGeometryDS, m_state.activePixelDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vkObjRenderPass = fboVk->GetRenderPassObj();
|
auto vkObjRenderPass = fboVk->GetRenderPassObj();
|
||||||
auto vkObjFramebuffer = fboVk->GetFramebufferObj();
|
auto vkObjFramebuffer = fboVk->GetFramebufferObj();
|
||||||
|
|
||||||
if (m_state.hasRenderSelfDependency)
|
bool overridePassReuse = m_state.hasRenderSelfDependency && (GetConfig().vk_accurate_barriers || m_state.activePipelineInfo->neverSkipAccurateBarrier);
|
||||||
{
|
|
||||||
bool triggerBarrier = GetConfig().vk_accurate_barriers || m_state.activePipelineInfo->neverSkipAccurateBarrier;
|
|
||||||
if (triggerBarrier)
|
|
||||||
{
|
|
||||||
VkMemoryBarrier memoryBarrier{};
|
|
||||||
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
|
||||||
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
||||||
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
||||||
vkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
|
|
||||||
performanceMonitor.vk.numDrawBarriersPerFrame.increment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_state.activeRenderpassFBO == fboVk)
|
if (!overridePassReuse && m_state.activeRenderpassFBO == fboVk)
|
||||||
{
|
{
|
||||||
if (m_state.descriptorSetsChanged)
|
if (m_state.descriptorSetsChanged)
|
||||||
sync_inputTexturesChanged();
|
sync_inputTexturesChanged();
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ void iosuCrypto_generateDeviceCertificate()
|
|||||||
BIGNUM* bn_x = BN_CTX_get(context);
|
BIGNUM* bn_x = BN_CTX_get(context);
|
||||||
BIGNUM* bn_y = BN_CTX_get(context);
|
BIGNUM* bn_y = BN_CTX_get(context);
|
||||||
|
|
||||||
EC_POINT_get_affine_coordinates_GF2m(group, pubkey, bn_x, bn_y, NULL);
|
EC_POINT_get_affine_coordinates(group, pubkey, bn_x, bn_y, NULL);
|
||||||
|
|
||||||
uint8 publicKeyOutput[0x3C];
|
uint8 publicKeyOutput[0x3C];
|
||||||
memset(publicKeyOutput, 0, sizeof(publicKeyOutput));
|
memset(publicKeyOutput, 0, sizeof(publicKeyOutput));
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "Cafe/OS/common/OSCommon.h"
|
#include "Cafe/OS/common/OSCommon.h"
|
||||||
#include "input/InputManager.h"
|
#include "input/InputManager.h"
|
||||||
|
#include "audio/IAudioInputAPI.h"
|
||||||
|
#include "config/CemuConfig.h"
|
||||||
|
|
||||||
enum class MIC_RESULT
|
enum class MIC_RESULT
|
||||||
{
|
{
|
||||||
@@ -13,6 +15,7 @@ enum class MIC_RESULT
|
|||||||
|
|
||||||
#define MIC_SAMPLERATE 32000
|
#define MIC_SAMPLERATE 32000
|
||||||
|
|
||||||
|
const int MIC_SAMPLES_PER_3MS_32KHZ = (96); // 32000*3/1000
|
||||||
|
|
||||||
enum class MIC_STATUS_FLAGS : uint32
|
enum class MIC_STATUS_FLAGS : uint32
|
||||||
{
|
{
|
||||||
@@ -22,8 +25,8 @@ enum class MIC_STATUS_FLAGS : uint32
|
|||||||
};
|
};
|
||||||
DEFINE_ENUM_FLAG_OPERATORS(MIC_STATUS_FLAGS);
|
DEFINE_ENUM_FLAG_OPERATORS(MIC_STATUS_FLAGS);
|
||||||
|
|
||||||
#define MIC_HANDLE_DRC0 100
|
#define MIC_HANDLE_DRC0 0
|
||||||
#define MIC_HANDLE_DRC1 101
|
#define MIC_HANDLE_DRC1 1
|
||||||
|
|
||||||
enum class MIC_STATEID
|
enum class MIC_STATEID
|
||||||
{
|
{
|
||||||
@@ -139,6 +142,36 @@ void micExport_MICInit(PPCInterpreter_t* hCPU)
|
|||||||
// return status
|
// return status
|
||||||
memory_writeU32(hCPU->gpr[6], 0); // no error
|
memory_writeU32(hCPU->gpr[6], 0); // no error
|
||||||
osLib_returnFromFunction(hCPU, (drcIndex==0)?MIC_HANDLE_DRC0:MIC_HANDLE_DRC1); // success
|
osLib_returnFromFunction(hCPU, (drcIndex==0)?MIC_HANDLE_DRC0:MIC_HANDLE_DRC1); // success
|
||||||
|
|
||||||
|
auto& config = GetConfig();
|
||||||
|
const auto audio_api = IAudioInputAPI::Cubeb; // change this if more input apis get implemented
|
||||||
|
|
||||||
|
std::unique_lock lock(g_audioInputMutex);
|
||||||
|
if (!g_inputAudio)
|
||||||
|
{
|
||||||
|
IAudioInputAPI::DeviceDescriptionPtr device_description;
|
||||||
|
if (IAudioInputAPI::IsAudioInputAPIAvailable(audio_api))
|
||||||
|
{
|
||||||
|
auto devices = IAudioInputAPI::GetDevices(audio_api);
|
||||||
|
const auto it = std::find_if(devices.begin(), devices.end(), [&config](const auto& d) {return d->GetIdentifier() == config.input_device; });
|
||||||
|
if (it != devices.end())
|
||||||
|
device_description = *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_description)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
g_inputAudio = IAudioInputAPI::CreateDevice(audio_api, device_description, MIC_SAMPLERATE, 1, MIC_SAMPLES_PER_3MS_32KHZ, 16);
|
||||||
|
g_inputAudio->SetVolume(config.input_volume);
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
|
{
|
||||||
|
forceLog_printf("can't initialize audio input: %s", ex.what());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void micExport_MICOpen(PPCInterpreter_t* hCPU)
|
void micExport_MICOpen(PPCInterpreter_t* hCPU)
|
||||||
@@ -172,6 +205,10 @@ void micExport_MICOpen(PPCInterpreter_t* hCPU)
|
|||||||
// success
|
// success
|
||||||
MICStatus.drc[drcIndex].isOpen = true;
|
MICStatus.drc[drcIndex].isOpen = true;
|
||||||
osLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);
|
osLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);
|
||||||
|
|
||||||
|
std::shared_lock lock(g_audioInputMutex);
|
||||||
|
if(g_inputAudio)
|
||||||
|
g_inputAudio->Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void micExport_MICClose(PPCInterpreter_t* hCPU)
|
void micExport_MICClose(PPCInterpreter_t* hCPU)
|
||||||
@@ -198,6 +235,10 @@ void micExport_MICClose(PPCInterpreter_t* hCPU)
|
|||||||
// success
|
// success
|
||||||
MICStatus.drc[drcIndex].isOpen = false;
|
MICStatus.drc[drcIndex].isOpen = false;
|
||||||
osLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);
|
osLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);
|
||||||
|
|
||||||
|
std::shared_lock lock(g_audioInputMutex);
|
||||||
|
if (g_inputAudio)
|
||||||
|
g_inputAudio->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void micExport_MICGetStatus(PPCInterpreter_t* hCPU)
|
void micExport_MICGetStatus(PPCInterpreter_t* hCPU)
|
||||||
@@ -360,6 +401,17 @@ void micExport_MICSetDataConsumed(PPCInterpreter_t* hCPU)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mic_updateDevicePlayState(bool isPlaying)
|
||||||
|
{
|
||||||
|
if (g_inputAudio)
|
||||||
|
{
|
||||||
|
if (isPlaying)
|
||||||
|
g_inputAudio->Play();
|
||||||
|
else
|
||||||
|
g_inputAudio->Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mic_updateOnAXFrame()
|
void mic_updateOnAXFrame()
|
||||||
{
|
{
|
||||||
sint32 drcIndex = 0;
|
sint32 drcIndex = 0;
|
||||||
@@ -368,26 +420,39 @@ void mic_updateOnAXFrame()
|
|||||||
drcIndex = 1;
|
drcIndex = 1;
|
||||||
if (mic_isActive(1) == false)
|
if (mic_isActive(1) == false)
|
||||||
{
|
{
|
||||||
|
std::shared_lock lock(g_audioInputMutex);
|
||||||
|
mic_updateDevicePlayState(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sint32 micSampleCount = 32000/32;
|
std::shared_lock lock(g_audioInputMutex);
|
||||||
sint16 micSampleData[micSampleCount];
|
mic_updateDevicePlayState(true);
|
||||||
|
if (g_inputAudio)
|
||||||
auto controller = InputManager::instance().get_vpad_controller(drcIndex);
|
|
||||||
if( controller && controller->is_mic_active() )
|
|
||||||
{
|
{
|
||||||
for(sint32 i=0; i<micSampleCount; i++)
|
sint16 micSampleData[MIC_SAMPLES_PER_3MS_32KHZ];
|
||||||
{
|
g_inputAudio->ConsumeBlock(micSampleData);
|
||||||
micSampleData[i] = (sint16)(sin((float)GetTickCount()*0.1f+sin((float)GetTickCount()*0.0001f)*100.0f)*30000.0f);
|
mic_feedSamples(0, micSampleData, MIC_SAMPLES_PER_3MS_32KHZ);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memset(micSampleData, 0x00, sizeof(micSampleData));
|
const sint32 micSampleCount = 32000 / 32;
|
||||||
|
sint16 micSampleData[micSampleCount];
|
||||||
|
|
||||||
|
auto controller = InputManager::instance().get_vpad_controller(drcIndex);
|
||||||
|
if( controller && controller->is_mic_active() )
|
||||||
|
{
|
||||||
|
for(sint32 i=0; i<micSampleCount; i++)
|
||||||
|
{
|
||||||
|
micSampleData[i] = (sint16)(sin((float)GetTickCount()*0.1f+sin((float)GetTickCount()*0.0001f)*100.0f)*30000.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(micSampleData, 0x00, sizeof(micSampleData));
|
||||||
|
}
|
||||||
|
mic_feedSamples(0, micSampleData, micSampleCount);
|
||||||
}
|
}
|
||||||
mic_feedSamples(0, micSampleData, micSampleCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mic
|
namespace mic
|
||||||
|
|||||||
@@ -550,7 +550,7 @@ namespace NCrypto
|
|||||||
EC_POINT_mul(group, pubkey, bn_privKey, NULL, NULL, NULL);
|
EC_POINT_mul(group, pubkey, bn_privKey, NULL, NULL, NULL);
|
||||||
BIGNUM* bn_x = BN_new();
|
BIGNUM* bn_x = BN_new();
|
||||||
BIGNUM* bn_y = BN_new();
|
BIGNUM* bn_y = BN_new();
|
||||||
EC_POINT_get_affine_coordinates_GF2m(group, pubkey, bn_x, bn_y, NULL);
|
EC_POINT_get_affine_coordinates(group, pubkey, bn_x, bn_y, NULL);
|
||||||
|
|
||||||
// store public key
|
// store public key
|
||||||
ECCPubKey genPubKey;
|
ECCPubKey genPubKey;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user