Merge branch 'main' into loadaudio

This commit is contained in:
goeiecool9999 2024-03-18 01:46:06 +01:00
commit f633113864
98 changed files with 1513 additions and 1051 deletions

View file

@ -28,7 +28,7 @@ jobs:
run: | run: |
cd dependencies/vcpkg cd dependencies/vcpkg
git fetch --unshallow git fetch --unshallow
git pull --all git checkout 431eb6bda0950874c8d4ed929cc66e15d8aae46f
- name: Setup release mode parameters (for deploy) - name: Setup release mode parameters (for deploy)
if: ${{ inputs.deploymode == 'release' }} if: ${{ inputs.deploymode == 'release' }}
@ -75,7 +75,7 @@ jobs:
- name: "cmake" - name: "cmake"
run: | run: |
cmake -S . -B build ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DPORTABLE=OFF -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja cmake -S . -B build ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja
- name: "Build Cemu" - name: "Build Cemu"
run: | run: |
@ -133,7 +133,7 @@ jobs:
run: | run: |
cd dependencies/vcpkg cd dependencies/vcpkg
git fetch --unshallow git fetch --unshallow
git pull --all git checkout 431eb6bda0950874c8d4ed929cc66e15d8aae46f
- name: Setup release mode parameters (for deploy) - name: Setup release mode parameters (for deploy)
if: ${{ inputs.deploymode == 'release' }} if: ${{ inputs.deploymode == 'release' }}
@ -258,7 +258,6 @@ jobs:
cd build cd build
cmake .. ${{ env.BUILD_FLAGS }} \ cmake .. ${{ env.BUILD_FLAGS }} \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} \ -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} \
-DPORTABLE=OFF \
-DMACOS_BUNDLE=ON \ -DMACOS_BUNDLE=ON \
-DCMAKE_C_COMPILER=/usr/local/opt/llvm@15/bin/clang \ -DCMAKE_C_COMPILER=/usr/local/opt/llvm@15/bin/clang \
-DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@15/bin/clang++ \ -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@15/bin/clang++ \

1
.gitignore vendored
View file

@ -39,6 +39,7 @@ bin/sdcard/*
bin/screenshots/* bin/screenshots/*
bin/dump/* bin/dump/*
bin/cafeLibs/* bin/cafeLibs/*
bin/keys.txt
!bin/shaderCache/info.txt !bin/shaderCache/info.txt
bin/shaderCache/* bin/shaderCache/*

155
BUILD.md
View file

@ -1,4 +1,26 @@
# Build instructions # Build Instructions
## Table of Contents
- [Windows](#windows)
- [Linux](#linux)
- [Dependencies](#dependencies)
- [For Arch and derivatives:](#for-arch-and-derivatives)
- [For Debian, Ubuntu and derivatives](#for-debian-ubuntu-and-derivatives)
- [For Fedora and derivatives:](#for-fedora-and-derivatives)
- [Build Cemu](#build-cemu)
- [CMake and Clang](#cmake-and-clang)
- [GCC](#gcc)
- [Debug Build](#debug-build)
- [Troubleshooting Steps](#troubleshooting-steps)
- [Compiling Errors](#compiling-errors)
- [Building Errors](#building-errors)
- [macOS](#macos)
- [On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used](#on-apple-silicon-macs-rosetta-2-and-the-x86_64-version-of-homebrew-must-be-used)
- [Installing brew](#installing-brew)
- [Installing Dependencies](#installing-dependencies)
- [Build Cemu using CMake and Clang](#build-cemu-using-cmake-and-clang)
- [Updating Cemu and source code](#updating-cemu-and-source-code)
## Windows ## Windows
@ -19,57 +41,109 @@ Any other IDE should also work as long as it has CMake and MSVC support. CLion a
## Linux ## Linux
To compile Cemu, a recent enough compiler and STL with C++20 support is required! clang-15 or higher is what we recommend. To compile Cemu, a recent enough compiler and STL with C++20 support is required! Clang-15 or higher is what we recommend.
### Installing dependencies ### Dependencies
#### For Ubuntu and derivatives:
`sudo apt install -y cmake curl clang-15 freeglut3-dev git libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build`
You may also need to install `libusb-1.0-0-dev` as a workaround for an issue with the vcpkg hidapi package.
At step 3 while building, use:
`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`
#### For Arch and derivatives: #### For Arch and derivatives:
`sudo pacman -S --needed base-devel clang cmake freeglut git glm gtk3 libgcrypt libpulse libsecret linux-headers llvm nasm ninja systemd unzip zip` `sudo pacman -S --needed base-devel clang cmake freeglut git glm gtk3 libgcrypt libpulse libsecret linux-headers llvm nasm ninja systemd unzip zip`
#### For Debian, Ubuntu and derivatives:
`sudo apt install -y cmake curl clang-15 freeglut3-dev git libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libtool nasm ninja-build`
You may also need to install `libusb-1.0-0-dev` as a workaround for an issue with the vcpkg hidapi package.
At Step 3 in [Build Cemu using cmake and clang](#build-cemu-using-cmake-and-clang), use the following command instead:
`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`
#### For Fedora and derivatives: #### For Fedora and derivatives:
`sudo dnf install clang cmake cubeb-devel freeglut-devel git glm-devel gtk3-devel kernel-headers libgcrypt-devel libsecret-devel libtool libusb1-devel nasm ninja-build perl-core systemd-devel zlib-devel` `sudo dnf install clang cmake cubeb-devel freeglut-devel git glm-devel gtk3-devel kernel-headers libgcrypt-devel libsecret-devel libtool libusb1-devel llvm nasm ninja-build perl-core systemd-devel zlib-devel`
### Build Cemu using cmake and clang ### Build Cemu
1. `git clone --recursive https://github.com/cemu-project/Cemu`
2. `cd Cemu`
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja`
4. `cmake --build build`
5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`.
#### Using GCC #### CMake and Clang
While we build and test Cemu using clang, using GCC might work better with your distro (they should be fairly similar performance/issues wise and should only be considered if compilation is the issue).
You can use GCC by doing the following: ```
- make sure you have g++ installed in your system git clone --recursive https://github.com/cemu-project/Cemu
- installation for Ubuntu and derivatives: `sudo apt install g++` cd Cemu
- installation for Fedora and derivatives: `sudo dnf install gcc-c++` cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja
- replace the step 3 with the following: cmake --build build
`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja` ```
#### Troubleshooting steps #### GCC
- If step 3 gives you an error about not being able to find ninja, try appending `-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` to the command and running it again.
- If step 3 fails while compiling the boost-build dependency, it means you don't have a working/good standard library installation. Check the integrity of your system headers and making sure that C++ related packages are installed and intact. If you are building using GCC, make sure you have g++ installed:
- If step 3 gives a random error, read the `[package-name-and-platform]-out.log` and `[package-name-and-platform]-err.log` for the actual reason to see if you might be lacking the headers from a dependency. - Installation for Arch and derivatives: `sudo pacman -S gcc`
- If step 3 is still failing or if you're not able to find the cause, please make an issue on our Github about it! - Installation for Debian, Ubuntu and derivatives: `sudo apt install g++`
- If step 3 fails during rebuild after `git pull` with an error that mentions RPATH, add this to the end of step 3: `-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON` - Installation for Fedora and derivatives: `sudo dnf install gcc-c++`
- If step 4 gives you an error that contains something like `main.cpp.o: in function 'std::__cxx11::basic_string...`, you likely are experiencing a clang-14 issue. This can only be fixed by either lowering the clang version or using GCC, see below.
- If step 4 gives you a different error, you could report it to this repo or try using GCC. Just make sure your standard library and compilers are updated since Cemu uses a lot of modern features! ```
- If step 4 gives you undefined libdecor_xx, you are likely experiencing an issue with sdl2 package that comes with vcpkg. Delete sdl2 from vcpkg.json in source file and recompile. git clone --recursive https://github.com/cemu-project/Cemu
- If step 4 gives you `fatal error: 'span' file not found`, then you're either missing `libstdc++` or are using a version that's too old. Install at least v10 with your package manager, eg `sudo apt install libstdc++-10-dev`. See #644. cd Cemu
cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja
cmake --build build
```
#### Debug Build
```
git clone --recursive https://github.com/cemu-project/Cemu
cd Cemu
cmake -S . -B build -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja
cmake --build build
```
If you are using GCC, replace `cmake -S . -B build -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja` with `cmake -S . -B build -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja`
#### Troubleshooting Steps
##### Compiling Errors
This section refers to running `cmake -S...` (truncated).
* `vcpkg install failed`
* Run the following in the root directory and try running the command again (don't forget to change directories afterwards):
* `cd dependencies/vcpkg && git fetch --unshallow`
* `Please ensure you're using the latest port files with git pull and vcpkg update.`
* Either:
* Update vcpkg by running by the following command:
* `git submodule update --remote dependencies/vcpkg`
* If you are sure vcpkg is up to date, check the following logs:
* `Cemu/dependencies/vcpkg/buildtrees/wxwidgets/config-x64-linux-out.log`
* `Cemu/dependencies/vcpkg/buildtrees/libsystemd/config-x64-linux-dbg-meson-log.txt.log`
* `Cemu/dependencies/vcpkg/buildtrees/libsystemd/config-x64-linux-dbg-out.log`
* Not able to find Ninja.
* Add the following and try running the command again:
* `-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`
* Compiling failed during the boost-build dependency.
* It means you don't have a working/good standard library installation. Check the integrity of your system headers and making sure that C++ related packages are installed and intact.
* Compiling failed during rebuild after `git pull` with an error that mentions RPATH
* Add the following and try running the command again:
* `-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON`
* If you are getting a random error, read the [package-name-and-platform]-out.log and [package-name-and-platform]-err.log for the actual reason to see if you might be lacking the headers from a dependency.
If you are getting a different error than any of the errors listed above, you may either open an issue in this repo or try using [GCC](#gcc). Make sure your standard library and compilers are updated since Cemu uses a lot of modern features!
##### Building Errors
This section refers to running `cmake --build build`.
* `main.cpp.o: in function 'std::__cxx11::basic_string...`
* You likely are experiencing a clang-14 issue. This can only be fixed by either lowering the clang version or using GCC, see [GCC](#gcc).
* `fatal error: 'span' file not found`
* You're either missing `libstdc++` or are using a version that's too old. Install at least v10 with your package manager, eg `sudo apt install libstdc++-10-dev`. See [#644](https://github.com/cemu-project/Cemu/issues/644).
* `undefined libdecor_xx`
* You are likely experiencing an issue with sdl2 package that comes with vcpkg. Delete sdl2 from vcpkg.json in source file and recompile.
If you are getting a different error than any of the errors listed above, you may either open an issue in this repo or try using [GCC](#gcc). Make sure your standard library and compilers are updated since Cemu uses a lot of modern features!
## macOS ## macOS
To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and
below, built in LLVM, and Xcode LLVM don't support the C++20 feature set required. The OpenGL graphics below, built in LLVM, and Xcode LLVM don't support the C++20 feature set required. The OpenGL graphics
API isn't support on macOS, Vulkan must be used. Additionally Vulkan must be used through the API isn't support on macOS, Vulkan must be used. Additionally Vulkan must be used through the
Molten-VK compatibility layer Molten-VK compatibility layer
### On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used ### On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used
@ -84,11 +158,11 @@ You can skip this section if you have an Intel Mac. Every time you compile, you
1. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` 1. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
2. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"` # set x86_64 brew env 2. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"` # set x86_64 brew env
### Installing dependencies ### Installing Dependencies
`brew install boost git cmake llvm ninja nasm molten-vk automake libtool` `brew install boost git cmake llvm ninja nasm molten-vk automake libtool`
### 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`
2. `cd Cemu` 2. `cd Cemu`
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -G Ninja` 3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -G Ninja`
@ -104,3 +178,4 @@ You can skip this section if you have an Intel Mac. Every time you compile, you
2. Then, you can rebuild Cemu using the steps listed above, according to whether you use Linux or Windows. 2. Then, you can rebuild Cemu using the steps listed above, according to whether you use Linux or Windows.
If CMake complains about Cemu already being compiled or another similar error, try deleting the `CMakeCache.txt` file inside the `build` folder and retry building. If CMake complains about Cemu already being compiled or another similar error, try deleting the `CMakeCache.txt` file inside the `build` folder and retry building.

View file

@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.21.1) cmake_minimum_required(VERSION 3.21.1)
option(ENABLE_VCPKG "Enable the vcpkg package manager" ON) option(ENABLE_VCPKG "Enable the vcpkg package manager" ON)
option(PORTABLE "All data created and maintained by Cemu will be in the directory where the executable file is located" ON)
option(MACOS_BUNDLE "The executable when built on macOS will be created as an application bundle" OFF) option(MACOS_BUNDLE "The executable when built on macOS will be created as an application bundle" OFF)
set(EXPERIMENTAL_VERSION "" CACHE STRING "") # used by CI script to set experimental version set(EXPERIMENTAL_VERSION "" CACHE STRING "") # used by CI script to set experimental version
@ -45,10 +44,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_compile_definitions($<$<CONFIG:Debug>:CEMU_DEBUG_ASSERT>) # if build type is debug, set CEMU_DEBUG_ASSERT add_compile_definitions($<$<CONFIG:Debug>:CEMU_DEBUG_ASSERT>) # if build type is debug, set CEMU_DEBUG_ASSERT
if(PORTABLE)
add_compile_definitions(PORTABLE)
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# enable link time optimization for release builds # enable link time optimization for release builds

View file

@ -48,7 +48,7 @@ Before submitting a pull request, please read and follow our code style guidelin
If coding isn't your thing, testing games and making detailed bug reports or updating the (usually outdated) compatibility wiki is also appreciated! If coding isn't your thing, testing games and making detailed bug reports or updating the (usually outdated) compatibility wiki is also appreciated!
Questions about Cemu's software architecture can also be answered on Discord (through the Matrix bridge). Questions about Cemu's software architecture can also be answered on Discord (or through the Matrix bridge).
## License ## License
Cemu is licensed under [Mozilla Public License 2.0](/LICENSE.txt). Exempt from this are all files in the dependencies directory for which the licenses of the original code apply as well as some individual files in the src folder, as specified in those file headers respectively. Cemu is licensed under [Mozilla Public License 2.0](/LICENSE.txt). Exempt from this are all files in the dependencies directory for which the licenses of the original code apply as well as some individual files in the src folder, as specified in those file headers respectively.

View file

@ -0,0 +1,13 @@
diff --git a/SDL2Config.cmake.in b/SDL2Config.cmake.in
index cc8bcf26d..ead829767 100644
--- a/SDL2Config.cmake.in
+++ b/SDL2Config.cmake.in
@@ -35,7 +35,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/sdlfind.cmake")
set(SDL_ALSA @SDL_ALSA@)
set(SDL_ALSA_SHARED @SDL_ALSA_SHARED@)
-if(SDL_ALSA AND NOT SDL_ALSA_SHARED AND TARGET SDL2::SDL2-static)
+if(SDL_ALSA)
sdlFindALSA()
endif()
unset(SDL_ALSA)

View file

@ -0,0 +1,13 @@
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index 65a98efbe..2f99f28f1 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -352,7 +352,7 @@ endmacro()
# - HAVE_SDL_LOADSO opt
macro(CheckLibSampleRate)
if(SDL_LIBSAMPLERATE)
- find_package(SampleRate QUIET)
+ find_package(SampleRate CONFIG REQUIRED)
if(SampleRate_FOUND AND TARGET SampleRate::samplerate)
set(HAVE_LIBSAMPLERATE TRUE)
set(HAVE_LIBSAMPLERATE_H TRUE)

View file

@ -0,0 +1,137 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO libsdl-org/SDL
REF "release-${VERSION}"
SHA512 c7635a83a52f3970a372b804a8631f0a7e6b8d89aed1117bcc54a2040ad0928122175004cf2b42cf84a4fd0f86236f779229eaa63dfa6ca9c89517f999c5ff1c
HEAD_REF main
PATCHES
deps.patch
alsa-dep-fix.patch
)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" SDL_STATIC)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" SDL_SHARED)
string(COMPARE EQUAL "${VCPKG_CRT_LINKAGE}" "static" FORCE_STATIC_VCRT)
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
alsa SDL_ALSA
alsa CMAKE_REQUIRE_FIND_PACKAGE_ALSA
ibus SDL_IBUS
samplerate SDL_LIBSAMPLERATE
vulkan SDL_VULKAN
wayland SDL_WAYLAND
x11 SDL_X11
INVERTED_FEATURES
alsa CMAKE_DISABLE_FIND_PACKAGE_ALSA
)
if ("x11" IN_LIST FEATURES)
message(WARNING "You will need to install Xorg dependencies to use feature x11:\nsudo apt install libx11-dev libxft-dev libxext-dev\n")
endif()
if ("wayland" IN_LIST FEATURES)
message(WARNING "You will need to install Wayland dependencies to use feature wayland:\nsudo apt install libwayland-dev libxkbcommon-dev libegl1-mesa-dev\n")
endif()
if ("ibus" IN_LIST FEATURES)
message(WARNING "You will need to install ibus dependencies to use feature ibus:\nsudo apt install libibus-1.0-dev\n")
endif()
if(VCPKG_TARGET_IS_UWP)
set(configure_opts WINDOWS_USE_MSBUILD)
endif()
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
${configure_opts}
OPTIONS ${FEATURE_OPTIONS}
-DSDL_STATIC=${SDL_STATIC}
-DSDL_SHARED=${SDL_SHARED}
-DSDL_FORCE_STATIC_VCRT=${FORCE_STATIC_VCRT}
-DSDL_LIBC=ON
-DSDL_TEST=OFF
-DSDL_INSTALL_CMAKEDIR="cmake"
-DCMAKE_DISABLE_FIND_PACKAGE_Git=ON
-DPKG_CONFIG_USE_CMAKE_PREFIX_PATH=ON
-DSDL_LIBSAMPLERATE_SHARED=OFF
MAYBE_UNUSED_VARIABLES
SDL_FORCE_STATIC_VCRT
PKG_CONFIG_USE_CMAKE_PREFIX_PATH
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(CONFIG_PATH cmake)
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/debug/include"
"${CURRENT_PACKAGES_DIR}/debug/share"
"${CURRENT_PACKAGES_DIR}/bin/sdl2-config"
"${CURRENT_PACKAGES_DIR}/debug/bin/sdl2-config"
"${CURRENT_PACKAGES_DIR}/SDL2.framework"
"${CURRENT_PACKAGES_DIR}/debug/SDL2.framework"
"${CURRENT_PACKAGES_DIR}/share/licenses"
"${CURRENT_PACKAGES_DIR}/share/aclocal"
)
file(GLOB BINS "${CURRENT_PACKAGES_DIR}/debug/bin/*" "${CURRENT_PACKAGES_DIR}/bin/*")
if(NOT BINS)
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/bin"
"${CURRENT_PACKAGES_DIR}/debug/bin"
)
endif()
if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_UWP AND NOT VCPKG_TARGET_IS_MINGW)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib/manual-link")
file(RENAME "${CURRENT_PACKAGES_DIR}/lib/SDL2main.lib" "${CURRENT_PACKAGES_DIR}/lib/manual-link/SDL2main.lib")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link")
file(RENAME "${CURRENT_PACKAGES_DIR}/debug/lib/SDL2maind.lib" "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link/SDL2maind.lib")
endif()
file(GLOB SHARE_FILES "${CURRENT_PACKAGES_DIR}/share/sdl2/*.cmake")
foreach(SHARE_FILE ${SHARE_FILES})
vcpkg_replace_string("${SHARE_FILE}" "lib/SDL2main" "lib/manual-link/SDL2main")
endforeach()
endif()
vcpkg_copy_pdbs()
set(DYLIB_COMPATIBILITY_VERSION_REGEX "set\\(DYLIB_COMPATIBILITY_VERSION (.+)\\)")
set(DYLIB_CURRENT_VERSION_REGEX "set\\(DYLIB_CURRENT_VERSION (.+)\\)")
file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_COMPATIBILITY_VERSION REGEX ${DYLIB_COMPATIBILITY_VERSION_REGEX})
file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_CURRENT_VERSION REGEX ${DYLIB_CURRENT_VERSION_REGEX})
string(REGEX REPLACE ${DYLIB_COMPATIBILITY_VERSION_REGEX} "\\1" DYLIB_COMPATIBILITY_VERSION "${DYLIB_COMPATIBILITY_VERSION}")
string(REGEX REPLACE ${DYLIB_CURRENT_VERSION_REGEX} "\\1" DYLIB_CURRENT_VERSION "${DYLIB_CURRENT_VERSION}")
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2main" "-lSDL2maind")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2 " "-lSDL2d ")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-static " "-lSDL2-staticd ")
endif()
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic" AND VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-lSDL2-static " " ")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-staticd " " ")
endif()
endif()
if(VCPKG_TARGET_IS_UWP)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "$<$<CONFIG:Debug>:d>.lib" "")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "$<$<CONFIG:Debug>:d>.lib" "d")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:")
endif()
endif()
vcpkg_fixup_pkgconfig()
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.txt")

View file

@ -0,0 +1,8 @@
sdl2 provides CMake targets:
find_package(SDL2 CONFIG REQUIRED)
target_link_libraries(main
PRIVATE
$<TARGET_NAME_IF_EXISTS:SDL2::SDL2main>
$<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>
)

View file

@ -0,0 +1,68 @@
{
"name": "sdl2",
"version": "2.30.0",
"description": "Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.",
"homepage": "https://www.libsdl.org/download-2.0.php",
"license": "Zlib",
"dependencies": [
{
"name": "dbus",
"default-features": false,
"platform": "linux"
},
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
],
"default-features": [
{
"name": "ibus",
"platform": "linux"
},
{
"name": "wayland",
"platform": "linux"
},
{
"name": "x11",
"platform": "linux"
}
],
"features": {
"alsa": {
"description": "Support for alsa audio",
"dependencies": [
{
"name": "alsa",
"platform": "linux"
}
]
},
"ibus": {
"description": "Build with ibus IME support",
"supports": "linux"
},
"samplerate": {
"description": "Use libsamplerate for audio rate conversion",
"dependencies": [
"libsamplerate"
]
},
"vulkan": {
"description": "Vulkan functionality for SDL"
},
"wayland": {
"description": "Build with Wayland support",
"supports": "linux"
},
"x11": {
"description": "Build with X11 support",
"supports": "!windows"
}
}
}

View file

@ -0,0 +1,13 @@
diff --git a/SDL2Config.cmake.in b/SDL2Config.cmake.in
index cc8bcf26d..ead829767 100644
--- a/SDL2Config.cmake.in
+++ b/SDL2Config.cmake.in
@@ -35,7 +35,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/sdlfind.cmake")
set(SDL_ALSA @SDL_ALSA@)
set(SDL_ALSA_SHARED @SDL_ALSA_SHARED@)
-if(SDL_ALSA AND NOT SDL_ALSA_SHARED AND TARGET SDL2::SDL2-static)
+if(SDL_ALSA)
sdlFindALSA()
endif()
unset(SDL_ALSA)

View file

@ -0,0 +1,13 @@
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index 65a98efbe..2f99f28f1 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -352,7 +352,7 @@ endmacro()
# - HAVE_SDL_LOADSO opt
macro(CheckLibSampleRate)
if(SDL_LIBSAMPLERATE)
- find_package(SampleRate QUIET)
+ find_package(SampleRate CONFIG REQUIRED)
if(SampleRate_FOUND AND TARGET SampleRate::samplerate)
set(HAVE_LIBSAMPLERATE TRUE)
set(HAVE_LIBSAMPLERATE_H TRUE)

View file

@ -0,0 +1,137 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO libsdl-org/SDL
REF "release-${VERSION}"
SHA512 c7635a83a52f3970a372b804a8631f0a7e6b8d89aed1117bcc54a2040ad0928122175004cf2b42cf84a4fd0f86236f779229eaa63dfa6ca9c89517f999c5ff1c
HEAD_REF main
PATCHES
deps.patch
alsa-dep-fix.patch
)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" SDL_STATIC)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" SDL_SHARED)
string(COMPARE EQUAL "${VCPKG_CRT_LINKAGE}" "static" FORCE_STATIC_VCRT)
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
alsa SDL_ALSA
alsa CMAKE_REQUIRE_FIND_PACKAGE_ALSA
ibus SDL_IBUS
samplerate SDL_LIBSAMPLERATE
vulkan SDL_VULKAN
wayland SDL_WAYLAND
x11 SDL_X11
INVERTED_FEATURES
alsa CMAKE_DISABLE_FIND_PACKAGE_ALSA
)
if ("x11" IN_LIST FEATURES)
message(WARNING "You will need to install Xorg dependencies to use feature x11:\nsudo apt install libx11-dev libxft-dev libxext-dev\n")
endif()
if ("wayland" IN_LIST FEATURES)
message(WARNING "You will need to install Wayland dependencies to use feature wayland:\nsudo apt install libwayland-dev libxkbcommon-dev libegl1-mesa-dev\n")
endif()
if ("ibus" IN_LIST FEATURES)
message(WARNING "You will need to install ibus dependencies to use feature ibus:\nsudo apt install libibus-1.0-dev\n")
endif()
if(VCPKG_TARGET_IS_UWP)
set(configure_opts WINDOWS_USE_MSBUILD)
endif()
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
${configure_opts}
OPTIONS ${FEATURE_OPTIONS}
-DSDL_STATIC=${SDL_STATIC}
-DSDL_SHARED=${SDL_SHARED}
-DSDL_FORCE_STATIC_VCRT=${FORCE_STATIC_VCRT}
-DSDL_LIBC=ON
-DSDL_TEST=OFF
-DSDL_INSTALL_CMAKEDIR="cmake"
-DCMAKE_DISABLE_FIND_PACKAGE_Git=ON
-DPKG_CONFIG_USE_CMAKE_PREFIX_PATH=ON
-DSDL_LIBSAMPLERATE_SHARED=OFF
MAYBE_UNUSED_VARIABLES
SDL_FORCE_STATIC_VCRT
PKG_CONFIG_USE_CMAKE_PREFIX_PATH
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(CONFIG_PATH cmake)
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/debug/include"
"${CURRENT_PACKAGES_DIR}/debug/share"
"${CURRENT_PACKAGES_DIR}/bin/sdl2-config"
"${CURRENT_PACKAGES_DIR}/debug/bin/sdl2-config"
"${CURRENT_PACKAGES_DIR}/SDL2.framework"
"${CURRENT_PACKAGES_DIR}/debug/SDL2.framework"
"${CURRENT_PACKAGES_DIR}/share/licenses"
"${CURRENT_PACKAGES_DIR}/share/aclocal"
)
file(GLOB BINS "${CURRENT_PACKAGES_DIR}/debug/bin/*" "${CURRENT_PACKAGES_DIR}/bin/*")
if(NOT BINS)
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/bin"
"${CURRENT_PACKAGES_DIR}/debug/bin"
)
endif()
if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_UWP AND NOT VCPKG_TARGET_IS_MINGW)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib/manual-link")
file(RENAME "${CURRENT_PACKAGES_DIR}/lib/SDL2main.lib" "${CURRENT_PACKAGES_DIR}/lib/manual-link/SDL2main.lib")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link")
file(RENAME "${CURRENT_PACKAGES_DIR}/debug/lib/SDL2maind.lib" "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link/SDL2maind.lib")
endif()
file(GLOB SHARE_FILES "${CURRENT_PACKAGES_DIR}/share/sdl2/*.cmake")
foreach(SHARE_FILE ${SHARE_FILES})
vcpkg_replace_string("${SHARE_FILE}" "lib/SDL2main" "lib/manual-link/SDL2main")
endforeach()
endif()
vcpkg_copy_pdbs()
set(DYLIB_COMPATIBILITY_VERSION_REGEX "set\\(DYLIB_COMPATIBILITY_VERSION (.+)\\)")
set(DYLIB_CURRENT_VERSION_REGEX "set\\(DYLIB_CURRENT_VERSION (.+)\\)")
file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_COMPATIBILITY_VERSION REGEX ${DYLIB_COMPATIBILITY_VERSION_REGEX})
file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_CURRENT_VERSION REGEX ${DYLIB_CURRENT_VERSION_REGEX})
string(REGEX REPLACE ${DYLIB_COMPATIBILITY_VERSION_REGEX} "\\1" DYLIB_COMPATIBILITY_VERSION "${DYLIB_COMPATIBILITY_VERSION}")
string(REGEX REPLACE ${DYLIB_CURRENT_VERSION_REGEX} "\\1" DYLIB_CURRENT_VERSION "${DYLIB_CURRENT_VERSION}")
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2main" "-lSDL2maind")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2 " "-lSDL2d ")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-static " "-lSDL2-staticd ")
endif()
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic" AND VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-lSDL2-static " " ")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-staticd " " ")
endif()
endif()
if(VCPKG_TARGET_IS_UWP)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "$<$<CONFIG:Debug>:d>.lib" "")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "$<$<CONFIG:Debug>:d>.lib" "d")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:")
endif()
endif()
vcpkg_fixup_pkgconfig()
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.txt")

View file

@ -0,0 +1,8 @@
sdl2 provides CMake targets:
find_package(SDL2 CONFIG REQUIRED)
target_link_libraries(main
PRIVATE
$<TARGET_NAME_IF_EXISTS:SDL2::SDL2main>
$<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>
)

View file

@ -0,0 +1,68 @@
{
"name": "sdl2",
"version": "2.30.0",
"description": "Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.",
"homepage": "https://www.libsdl.org/download-2.0.php",
"license": "Zlib",
"dependencies": [
{
"name": "dbus",
"default-features": false,
"platform": "linux"
},
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
],
"default-features": [
{
"name": "ibus",
"platform": "linux"
},
{
"name": "wayland",
"platform": "linux"
},
{
"name": "x11",
"platform": "linux"
}
],
"features": {
"alsa": {
"description": "Support for alsa audio",
"dependencies": [
{
"name": "alsa",
"platform": "linux"
}
]
},
"ibus": {
"description": "Build with ibus IME support",
"supports": "linux"
},
"samplerate": {
"description": "Use libsamplerate for audio rate conversion",
"dependencies": [
"libsamplerate"
]
},
"vulkan": {
"description": "Vulkan functionality for SDL"
},
"wayland": {
"description": "Build with Wayland support",
"supports": "linux"
},
"x11": {
"description": "Build with X11 support",
"supports": "!windows"
}
}
}

View file

@ -0,0 +1,13 @@
diff --git a/SDL2Config.cmake.in b/SDL2Config.cmake.in
index cc8bcf26d..ead829767 100644
--- a/SDL2Config.cmake.in
+++ b/SDL2Config.cmake.in
@@ -35,7 +35,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/sdlfind.cmake")
set(SDL_ALSA @SDL_ALSA@)
set(SDL_ALSA_SHARED @SDL_ALSA_SHARED@)
-if(SDL_ALSA AND NOT SDL_ALSA_SHARED AND TARGET SDL2::SDL2-static)
+if(SDL_ALSA)
sdlFindALSA()
endif()
unset(SDL_ALSA)

View file

@ -0,0 +1,13 @@
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index 65a98efbe..2f99f28f1 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -352,7 +352,7 @@ endmacro()
# - HAVE_SDL_LOADSO opt
macro(CheckLibSampleRate)
if(SDL_LIBSAMPLERATE)
- find_package(SampleRate QUIET)
+ find_package(SampleRate CONFIG REQUIRED)
if(SampleRate_FOUND AND TARGET SampleRate::samplerate)
set(HAVE_LIBSAMPLERATE TRUE)
set(HAVE_LIBSAMPLERATE_H TRUE)

View file

@ -0,0 +1,137 @@
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO libsdl-org/SDL
REF "release-${VERSION}"
SHA512 c7635a83a52f3970a372b804a8631f0a7e6b8d89aed1117bcc54a2040ad0928122175004cf2b42cf84a4fd0f86236f779229eaa63dfa6ca9c89517f999c5ff1c
HEAD_REF main
PATCHES
deps.patch
alsa-dep-fix.patch
)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" SDL_STATIC)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" SDL_SHARED)
string(COMPARE EQUAL "${VCPKG_CRT_LINKAGE}" "static" FORCE_STATIC_VCRT)
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
FEATURES
alsa SDL_ALSA
alsa CMAKE_REQUIRE_FIND_PACKAGE_ALSA
ibus SDL_IBUS
samplerate SDL_LIBSAMPLERATE
vulkan SDL_VULKAN
wayland SDL_WAYLAND
x11 SDL_X11
INVERTED_FEATURES
alsa CMAKE_DISABLE_FIND_PACKAGE_ALSA
)
if ("x11" IN_LIST FEATURES)
message(WARNING "You will need to install Xorg dependencies to use feature x11:\nsudo apt install libx11-dev libxft-dev libxext-dev\n")
endif()
if ("wayland" IN_LIST FEATURES)
message(WARNING "You will need to install Wayland dependencies to use feature wayland:\nsudo apt install libwayland-dev libxkbcommon-dev libegl1-mesa-dev\n")
endif()
if ("ibus" IN_LIST FEATURES)
message(WARNING "You will need to install ibus dependencies to use feature ibus:\nsudo apt install libibus-1.0-dev\n")
endif()
if(VCPKG_TARGET_IS_UWP)
set(configure_opts WINDOWS_USE_MSBUILD)
endif()
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
${configure_opts}
OPTIONS ${FEATURE_OPTIONS}
-DSDL_STATIC=${SDL_STATIC}
-DSDL_SHARED=${SDL_SHARED}
-DSDL_FORCE_STATIC_VCRT=${FORCE_STATIC_VCRT}
-DSDL_LIBC=ON
-DSDL_TEST=OFF
-DSDL_INSTALL_CMAKEDIR="cmake"
-DCMAKE_DISABLE_FIND_PACKAGE_Git=ON
-DPKG_CONFIG_USE_CMAKE_PREFIX_PATH=ON
-DSDL_LIBSAMPLERATE_SHARED=OFF
MAYBE_UNUSED_VARIABLES
SDL_FORCE_STATIC_VCRT
PKG_CONFIG_USE_CMAKE_PREFIX_PATH
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(CONFIG_PATH cmake)
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/debug/include"
"${CURRENT_PACKAGES_DIR}/debug/share"
"${CURRENT_PACKAGES_DIR}/bin/sdl2-config"
"${CURRENT_PACKAGES_DIR}/debug/bin/sdl2-config"
"${CURRENT_PACKAGES_DIR}/SDL2.framework"
"${CURRENT_PACKAGES_DIR}/debug/SDL2.framework"
"${CURRENT_PACKAGES_DIR}/share/licenses"
"${CURRENT_PACKAGES_DIR}/share/aclocal"
)
file(GLOB BINS "${CURRENT_PACKAGES_DIR}/debug/bin/*" "${CURRENT_PACKAGES_DIR}/bin/*")
if(NOT BINS)
file(REMOVE_RECURSE
"${CURRENT_PACKAGES_DIR}/bin"
"${CURRENT_PACKAGES_DIR}/debug/bin"
)
endif()
if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_UWP AND NOT VCPKG_TARGET_IS_MINGW)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib/manual-link")
file(RENAME "${CURRENT_PACKAGES_DIR}/lib/SDL2main.lib" "${CURRENT_PACKAGES_DIR}/lib/manual-link/SDL2main.lib")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link")
file(RENAME "${CURRENT_PACKAGES_DIR}/debug/lib/SDL2maind.lib" "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link/SDL2maind.lib")
endif()
file(GLOB SHARE_FILES "${CURRENT_PACKAGES_DIR}/share/sdl2/*.cmake")
foreach(SHARE_FILE ${SHARE_FILES})
vcpkg_replace_string("${SHARE_FILE}" "lib/SDL2main" "lib/manual-link/SDL2main")
endforeach()
endif()
vcpkg_copy_pdbs()
set(DYLIB_COMPATIBILITY_VERSION_REGEX "set\\(DYLIB_COMPATIBILITY_VERSION (.+)\\)")
set(DYLIB_CURRENT_VERSION_REGEX "set\\(DYLIB_CURRENT_VERSION (.+)\\)")
file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_COMPATIBILITY_VERSION REGEX ${DYLIB_COMPATIBILITY_VERSION_REGEX})
file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_CURRENT_VERSION REGEX ${DYLIB_CURRENT_VERSION_REGEX})
string(REGEX REPLACE ${DYLIB_COMPATIBILITY_VERSION_REGEX} "\\1" DYLIB_COMPATIBILITY_VERSION "${DYLIB_COMPATIBILITY_VERSION}")
string(REGEX REPLACE ${DYLIB_CURRENT_VERSION_REGEX} "\\1" DYLIB_CURRENT_VERSION "${DYLIB_CURRENT_VERSION}")
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2main" "-lSDL2maind")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2 " "-lSDL2d ")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-static " "-lSDL2-staticd ")
endif()
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic" AND VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-lSDL2-static " " ")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-staticd " " ")
endif()
endif()
if(VCPKG_TARGET_IS_UWP)
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "$<$<CONFIG:Debug>:d>.lib" "")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "$<$<CONFIG:Debug>:d>.lib" "d")
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:")
endif()
endif()
vcpkg_fixup_pkgconfig()
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.txt")

View file

@ -0,0 +1,8 @@
sdl2 provides CMake targets:
find_package(SDL2 CONFIG REQUIRED)
target_link_libraries(main
PRIVATE
$<TARGET_NAME_IF_EXISTS:SDL2::SDL2main>
$<IF:$<TARGET_EXISTS:SDL2::SDL2>,SDL2::SDL2,SDL2::SDL2-static>
)

View file

@ -0,0 +1,68 @@
{
"name": "sdl2",
"version": "2.30.0",
"description": "Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.",
"homepage": "https://www.libsdl.org/download-2.0.php",
"license": "Zlib",
"dependencies": [
{
"name": "dbus",
"default-features": false,
"platform": "linux"
},
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
],
"default-features": [
{
"name": "ibus",
"platform": "linux"
},
{
"name": "wayland",
"platform": "linux"
},
{
"name": "x11",
"platform": "linux"
}
],
"features": {
"alsa": {
"description": "Support for alsa audio",
"dependencies": [
{
"name": "alsa",
"platform": "linux"
}
]
},
"ibus": {
"description": "Build with ibus IME support",
"supports": "linux"
},
"samplerate": {
"description": "Use libsamplerate for audio rate conversion",
"dependencies": [
"libsamplerate"
]
},
"vulkan": {
"description": "Vulkan functionality for SDL"
},
"wayland": {
"description": "Build with Wayland support",
"supports": "linux"
},
"x11": {
"description": "Build with X11 support",
"supports": "!windows"
}
}
}

View file

@ -748,7 +748,6 @@ namespace CafeSystem
} }
} }
LoadMainExecutable(); LoadMainExecutable();
gameProfile_load();
return STATUS_CODE::SUCCESS; return STATUS_CODE::SUCCESS;
} }
@ -777,6 +776,7 @@ namespace CafeSystem
STATUS_CODE r = LoadAndMountForegroundTitle(titleId); STATUS_CODE r = LoadAndMountForegroundTitle(titleId);
if (r != STATUS_CODE::SUCCESS) if (r != STATUS_CODE::SUCCESS)
return r; return r;
gameProfile_load();
// setup memory space and PPC recompiler // setup memory space and PPC recompiler
SetupMemorySpace(); SetupMemorySpace();
PPCRecompiler_init(); PPCRecompiler_init();

View file

@ -878,9 +878,6 @@ bool GraphicPack2::Activate()
if (m_gfx_vendor.has_value()) if (m_gfx_vendor.has_value())
{ {
auto vendor = g_renderer->GetVendor(); auto vendor = g_renderer->GetVendor();
if (vendor == GfxVendor::IntelLegacy || vendor == GfxVendor::IntelNoLegacy)
vendor = GfxVendor::Intel;
if (m_gfx_vendor.value() != vendor) if (m_gfx_vendor.value() != vendor)
return false; return false;
} }

View file

@ -297,7 +297,7 @@ bool GDBServer::Initialize()
void GDBServer::ThreadFunc() void GDBServer::ThreadFunc()
{ {
SetThreadName("GDBServer::ThreadFunc"); SetThreadName("GDBServer");
while (!m_stopRequested) while (!m_stopRequested)
{ {

View file

@ -294,7 +294,7 @@ std::atomic_bool s_recompilerThreadStopSignal{false};
void PPCRecompiler_thread() void PPCRecompiler_thread()
{ {
SetThreadName("PPCRecompiler_thread"); SetThreadName("PPCRecompiler");
while (true) while (true)
{ {
if(s_recompilerThreadStopSignal) if(s_recompilerThreadStopSignal)

View file

@ -98,7 +98,7 @@ void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPa
void LatteRenderTarget_GetCurrentVirtualViewportSize(sint32* viewportWidth, sint32* viewportHeight); void LatteRenderTarget_GetCurrentVirtualViewportSize(sint32* viewportWidth, sint32* viewportHeight);
void LatteRenderTarget_itHLESwapScanBuffer(); void LatteRenderTarget_itHLESwapScanBuffer();
void LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask, MPTR colorBufferMPTR, MPTR colorBufferFormat, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferPitch, uint32 colorBufferViewFirstSlice, uint32 colorBufferViewNumSlice, MPTR depthBufferMPTR, MPTR depthBufferFormat, Latte::E_HWTILEMODE depthBufferTileMode, sint32 depthBufferWidth, sint32 depthBufferHeight, sint32 depthBufferPitch, sint32 depthBufferViewFirstSlice, sint32 depthBufferViewNumSlice, float r, float g, float b, float a, float clearDepth, uint32 clearStencil); void LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask, MPTR colorBufferMPTR, Latte::E_GX2SURFFMT colorBufferFormat, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferPitch, uint32 colorBufferViewFirstSlice, uint32 colorBufferViewNumSlice, MPTR depthBufferMPTR, Latte::E_GX2SURFFMT depthBufferFormat, Latte::E_HWTILEMODE depthBufferTileMode, sint32 depthBufferWidth, sint32 depthBufferHeight, sint32 depthBufferPitch, sint32 depthBufferViewFirstSlice, sint32 depthBufferViewNumSlice, float r, float g, float b, float a, float clearDepth, uint32 clearStencil);
void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferSliceIndex, uint32 colorBufferFormat, uint32 colorBufferPitch, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferSwizzle, uint32 renderTarget); void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferSliceIndex, uint32 colorBufferFormat, uint32 colorBufferPitch, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferSwizzle, uint32 renderTarget);
void LatteRenderTarget_unloadAll(); void LatteRenderTarget_unloadAll();

View file

@ -309,7 +309,7 @@ public:
{ {
if ((rangeBegin & 0xF)) if ((rangeBegin & 0xF))
{ {
cemuLog_logDebug(LogType::Force, "writeStreamout(): RangeBegin not aligned to 16. Begin {:08x} End {:08x}", rangeBegin, rangeEnd); cemuLog_logDebugOnce(LogType::Force, "writeStreamout(): RangeBegin not aligned to 16. Begin {:08x} End {:08x}", rangeBegin, rangeEnd);
rangeBegin = (rangeBegin + 0xF) & ~0xF; rangeBegin = (rangeBegin + 0xF) & ~0xF;
rangeEnd = std::max(rangeBegin, rangeEnd); rangeEnd = std::max(rangeBegin, rangeEnd);
} }

View file

@ -42,7 +42,7 @@ private:
if(colorBuffer[i].texture == nullptr) if(colorBuffer[i].texture == nullptr)
continue; continue;
sint32 effectiveWidth, effectiveHeight; sint32 effectiveWidth, effectiveHeight;
LatteTexture_getEffectiveSize(colorBuffer[i].texture->baseTexture, &effectiveWidth, &effectiveHeight, nullptr, colorBuffer[i].texture->firstMip); colorBuffer[i].texture->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, colorBuffer[i].texture->firstMip);
if (rtEffectiveSize.x == 0 && rtEffectiveSize.y == 0) if (rtEffectiveSize.x == 0 && rtEffectiveSize.y == 0)
{ {
rtEffectiveSize.x = effectiveWidth; rtEffectiveSize.x = effectiveWidth;
@ -64,7 +64,7 @@ private:
if (depthBuffer.texture) if (depthBuffer.texture)
{ {
sint32 effectiveWidth, effectiveHeight; sint32 effectiveWidth, effectiveHeight;
LatteTexture_getEffectiveSize(depthBuffer.texture->baseTexture, &effectiveWidth, &effectiveHeight, nullptr, depthBuffer.texture->firstMip); depthBuffer.texture->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, depthBuffer.texture->firstMip);
if (rtEffectiveSize.x == 0 && rtEffectiveSize.y == 0) if (rtEffectiveSize.x == 0 && rtEffectiveSize.y == 0)
{ {
rtEffectiveSize.x = effectiveWidth; rtEffectiveSize.x = effectiveWidth;

View file

@ -864,8 +864,8 @@ LatteCMDPtr LatteCP_itHLEClearColorDepthStencil(LatteCMDPtr cmd, uint32 nWords)
cemu_assert_debug(nWords == 23); cemu_assert_debug(nWords == 23);
uint32 clearMask = LatteReadCMD(); // color (1), depth (2), stencil (4) uint32 clearMask = LatteReadCMD(); // color (1), depth (2), stencil (4)
// color buffer // color buffer
MPTR colorBufferMPTR = LatteReadCMD(); // MPTR for color buffer (physical address) MPTR colorBufferMPTR = LatteReadCMD(); // physical address for color buffer
MPTR colorBufferFormat = LatteReadCMD(); // format for color buffer Latte::E_GX2SURFFMT colorBufferFormat = (Latte::E_GX2SURFFMT)LatteReadCMD();
Latte::E_HWTILEMODE colorBufferTilemode = (Latte::E_HWTILEMODE)LatteReadCMD(); Latte::E_HWTILEMODE colorBufferTilemode = (Latte::E_HWTILEMODE)LatteReadCMD();
uint32 colorBufferWidth = LatteReadCMD(); uint32 colorBufferWidth = LatteReadCMD();
uint32 colorBufferHeight = LatteReadCMD(); uint32 colorBufferHeight = LatteReadCMD();
@ -873,8 +873,8 @@ LatteCMDPtr LatteCP_itHLEClearColorDepthStencil(LatteCMDPtr cmd, uint32 nWords)
uint32 colorBufferViewFirstSlice = LatteReadCMD(); uint32 colorBufferViewFirstSlice = LatteReadCMD();
uint32 colorBufferViewNumSlice = LatteReadCMD(); uint32 colorBufferViewNumSlice = LatteReadCMD();
// depth buffer // depth buffer
MPTR depthBufferMPTR = LatteReadCMD(); // MPTR for depth buffer (physical address) MPTR depthBufferMPTR = LatteReadCMD(); // physical address for depth buffer
MPTR depthBufferFormat = LatteReadCMD(); // format for depth buffer Latte::E_GX2SURFFMT depthBufferFormat = (Latte::E_GX2SURFFMT)LatteReadCMD();
Latte::E_HWTILEMODE depthBufferTileMode = (Latte::E_HWTILEMODE)LatteReadCMD(); Latte::E_HWTILEMODE depthBufferTileMode = (Latte::E_HWTILEMODE)LatteReadCMD();
uint32 depthBufferWidth = LatteReadCMD(); uint32 depthBufferWidth = LatteReadCMD();
uint32 depthBufferHeight = LatteReadCMD(); uint32 depthBufferHeight = LatteReadCMD();
@ -893,8 +893,8 @@ LatteCMDPtr LatteCP_itHLEClearColorDepthStencil(LatteCMDPtr cmd, uint32 nWords)
LatteRenderTarget_itHLEClearColorDepthStencil( LatteRenderTarget_itHLEClearColorDepthStencil(
clearMask, clearMask,
colorBufferMPTR, colorBufferFormat, colorBufferTilemode, colorBufferWidth, colorBufferHeight, colorBufferPitch, colorBufferViewFirstSlice, colorBufferViewNumSlice, colorBufferMPTR, colorBufferFormat, colorBufferTilemode, colorBufferWidth, colorBufferHeight, colorBufferPitch, colorBufferViewFirstSlice, colorBufferViewNumSlice,
depthBufferMPTR, depthBufferFormat, depthBufferTileMode, depthBufferWidth, depthBufferHeight, depthBufferPitch, depthBufferViewFirstSlice, depthBufferViewNumSlice, depthBufferMPTR, depthBufferFormat, depthBufferTileMode, depthBufferWidth, depthBufferHeight, depthBufferPitch, depthBufferViewFirstSlice, depthBufferViewNumSlice,
r, g, b, a, r, g, b, a,
clearDepth, clearStencil); clearDepth, clearStencil);
return cmd; return cmd;

View file

@ -82,8 +82,6 @@
#define GLVENDOR_UNKNOWN (0) #define GLVENDOR_UNKNOWN (0)
#define GLVENDOR_AMD (1) // AMD/ATI #define GLVENDOR_AMD (1) // AMD/ATI
#define GLVENDOR_NVIDIA (2) #define GLVENDOR_NVIDIA (2)
#define GLVENDOR_INTEL_LEGACY (3)
#define GLVENDOR_INTEL_NOLEGACY (4)
#define GLVENDOR_INTEL (5) #define GLVENDOR_INTEL (5)
#define GLVENDOR_APPLE (6) #define GLVENDOR_APPLE (6)

View file

@ -221,35 +221,9 @@ void LatteMRT::BindDepthBufferOnly(LatteTextureView* view)
ApplyCurrentState(); ApplyCurrentState();
} }
/***************************************************/
LatteTextureView* LatteMRT_FindColorBufferForClearing(MPTR colorBufferPtr, sint32 colorBufferWidth, sint32 colorBufferHeight, sint32 colorBufferPitch, uint32 format, sint32 sliceIndex, sint32* searchIndex)
{
LatteTextureView* view = LatteTC_LookupTextureByData(colorBufferPtr, colorBufferWidth, colorBufferHeight, colorBufferPitch, 0, 1, sliceIndex, 1, searchIndex);
if (view == nullptr)
return nullptr;
return view;
}
LatteTextureView* LatteMRT_CreateColorBuffer(MPTR colorBufferPhysMem, uint32 width, uint32 height, uint32 pitch, Latte::E_GX2SURFFMT format, Latte::E_HWTILEMODE tileMode, uint32 swizzle, uint32 viewSlice)
{
cemu_assert_debug(colorBufferPhysMem != MPTR_NULL);
LatteTextureView* textureView;
if(viewSlice != 0)
textureView = LatteTexture_CreateMapping(colorBufferPhysMem, MPTR_NULL, width, height, viewSlice+1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D_ARRAY, Latte::E_DIM::DIM_2D, false);
else
textureView = LatteTexture_CreateMapping(colorBufferPhysMem, MPTR_NULL, width, height, 1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false);
return textureView;
}
LatteTextureView* LatteMRT_CreateDepthBuffer(MPTR depthBufferPhysMem, uint32 width, uint32 height, uint32 pitch, Latte::E_HWTILEMODE tileMode, Latte::E_GX2SURFFMT format, uint32 swizzle, sint32 viewSlice) LatteTextureView* LatteMRT_CreateDepthBuffer(MPTR depthBufferPhysMem, uint32 width, uint32 height, uint32 pitch, Latte::E_HWTILEMODE tileMode, Latte::E_GX2SURFFMT format, uint32 swizzle, sint32 viewSlice)
{ {
LatteTextureView* textureView; LatteTextureView* textureView = LatteTexture_CreateMapping(depthBufferPhysMem, MPTR_NULL, width, height, viewSlice+1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, viewSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true);
if(viewSlice == 0)
textureView = LatteTexture_CreateMapping(depthBufferPhysMem, MPTR_NULL, width, height, 1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true);
else
textureView = LatteTexture_CreateMapping(depthBufferPhysMem, MPTR_NULL, width, height, viewSlice+1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D_ARRAY, Latte::E_DIM::DIM_2D, true);
LatteMRT::SetDepthAndStencilAttachment(textureView, textureView->baseTexture->hasStencil); LatteMRT::SetDepthAndStencilAttachment(textureView, textureView->baseTexture->hasStencil);
return textureView; return textureView;
} }
@ -516,14 +490,12 @@ bool LatteMRT::UpdateCurrentFBO()
sLatteRenderTargetState.rtUpdateList[sLatteRenderTargetState.rtUpdateListCount] = colorAttachmentView; sLatteRenderTargetState.rtUpdateList[sLatteRenderTargetState.rtUpdateListCount] = colorAttachmentView;
sLatteRenderTargetState.rtUpdateListCount++; sLatteRenderTargetState.rtUpdateListCount++;
sint32 colorAttachmentWidth; sint32 colorAttachmentWidth, colorAttachmentHeight;
sint32 colorAttachmentHeight; colorAttachmentView->baseTexture->GetSize(colorAttachmentWidth, colorAttachmentHeight, colorAttachmentView->firstMip);
LatteTexture_getSize(colorAttachmentView->baseTexture, &colorAttachmentWidth, &colorAttachmentHeight, nullptr, colorAttachmentView->firstMip);
// set effective size // set effective size
sint32 effectiveWidth, effectiveHeight; sint32 effectiveWidth, effectiveHeight;
LatteTexture_getEffectiveSize(colorAttachmentView->baseTexture, &effectiveWidth, &effectiveHeight, nullptr, colorAttachmentView->firstMip); colorAttachmentView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, colorAttachmentView->firstMip);
if (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0) if (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0)
{ {
rtEffectiveSize->width = effectiveWidth; rtEffectiveSize->width = effectiveWidth;
@ -531,9 +503,7 @@ bool LatteMRT::UpdateCurrentFBO()
} }
else if (rtEffectiveSize->width != effectiveWidth && rtEffectiveSize->height != effectiveHeight) else if (rtEffectiveSize->width != effectiveWidth && rtEffectiveSize->height != effectiveHeight)
{ {
#ifdef CEMU_DEBUG_ASSERT cemuLog_logDebug(LogType::Force, "Color buffer size mismatch ({}x{}). Effective size: {}x{} Real size: {}x{} Mismatching texture: {:08x} {}x{} fmt {:04x}", rtEffectiveSize->width, rtEffectiveSize->height, effectiveWidth, effectiveHeight, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, colorAttachmentView->baseTexture->physAddress, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, (uint32)colorAttachmentView->baseTexture->format);
cemuLog_log(LogType::Force, "Color buffer size mismatch ({}x{}). Effective size: {}x{} Real size: {}x{} Mismatching texture: {:08x} {}x{} fmt {:04x}", rtEffectiveSize->width, rtEffectiveSize->height, effectiveWidth, effectiveHeight, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, colorAttachmentView->baseTexture->physAddress, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, (uint32)colorAttachmentView->baseTexture->format);
#endif
} }
// currently the first color attachment defines the size of the current render target // currently the first color attachment defines the size of the current render target
if (rtRealSize->width == 0 && rtRealSize->height == 0) if (rtRealSize->width == 0 && rtRealSize->height == 0)
@ -608,15 +578,11 @@ bool LatteMRT::UpdateCurrentFBO()
if (depthBufferPhysMem != MPTR_NULL) if (depthBufferPhysMem != MPTR_NULL)
{ {
bool depthBufferWasFound = false;
LatteTextureView* depthBufferView = LatteTextureViewLookupCache::lookupSliceEx(depthBufferPhysMem, depthBufferWidth, depthBufferHeight, depthBufferPitch, 0, depthBufferViewFirstSlice, depthBufferFormat, true); LatteTextureView* depthBufferView = LatteTextureViewLookupCache::lookupSliceEx(depthBufferPhysMem, depthBufferWidth, depthBufferHeight, depthBufferPitch, 0, depthBufferViewFirstSlice, depthBufferFormat, true);
if (depthBufferView == nullptr) if (!depthBufferView)
{ {
// create depth buffer view // create new depth buffer view and if it doesn't exist then also create the texture
if(depthBufferViewFirstSlice == 0) depthBufferView = LatteTexture_CreateMapping(depthBufferPhysMem, 0, depthBufferWidth, depthBufferHeight, depthBufferViewFirstSlice+1, depthBufferPitch, depthBufferTileMode, depthBufferSwizzle, 0, 1, depthBufferViewFirstSlice, 1, depthBufferFormat, depthBufferViewFirstSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true);
depthBufferView = LatteTexture_CreateMapping(depthBufferPhysMem, 0, depthBufferWidth, depthBufferHeight, 1, depthBufferPitch, depthBufferTileMode, depthBufferSwizzle, 0, 1, 0, 1, depthBufferFormat, Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true);
else
depthBufferView = LatteTexture_CreateMapping(depthBufferPhysMem, 0, depthBufferWidth, depthBufferHeight, depthBufferViewFirstSlice+1, depthBufferPitch, depthBufferTileMode, depthBufferSwizzle, 0, 1, depthBufferViewFirstSlice, 1, depthBufferFormat, Latte::E_DIM::DIM_2D_ARRAY, Latte::E_DIM::DIM_2D, true);
LatteGPUState.repeatTextureInitialization = true; LatteGPUState.repeatTextureInitialization = true;
} }
else else
@ -626,7 +592,7 @@ bool LatteMRT::UpdateCurrentFBO()
} }
// set effective size // set effective size
sint32 effectiveWidth, effectiveHeight; sint32 effectiveWidth, effectiveHeight;
LatteTexture_getEffectiveSize(depthBufferView->baseTexture, &effectiveWidth, &effectiveHeight, NULL); depthBufferView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, depthBufferView->firstMip);
if (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0) if (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0)
{ {
rtEffectiveSize->width = effectiveWidth; rtEffectiveSize->width = effectiveWidth;
@ -776,7 +742,10 @@ void LatteRenderTarget_applyTextureDepthClear(LatteTexture* texture, uint32 slic
LatteTexture_MarkDynamicTextureAsChanged(texture->baseView, sliceIndex, mipIndex, eventCounter); LatteTexture_MarkDynamicTextureAsChanged(texture->baseView, sliceIndex, mipIndex, eventCounter);
} }
void LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask, MPTR colorBufferMPTR, MPTR colorBufferFormat, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferPitch, uint32 colorBufferViewFirstSlice, uint32 colorBufferViewNumSlice, MPTR depthBufferMPTR, MPTR depthBufferFormat, Latte::E_HWTILEMODE depthBufferTileMode, sint32 depthBufferWidth, sint32 depthBufferHeight, sint32 depthBufferPitch, sint32 depthBufferViewFirstSlice, sint32 depthBufferViewNumSlice, float r, float g, float b, float a, float clearDepth, uint32 clearStencil) void LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask,
MPTR colorBufferMPTR, Latte::E_GX2SURFFMT colorBufferFormat, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferPitch, uint32 colorBufferViewFirstSlice, uint32 colorBufferViewNumSlice,
MPTR depthBufferMPTR, Latte::E_GX2SURFFMT depthBufferFormat, Latte::E_HWTILEMODE depthBufferTileMode, sint32 depthBufferWidth, sint32 depthBufferHeight, sint32 depthBufferPitch, sint32 depthBufferViewFirstSlice, sint32 depthBufferViewNumSlice,
float r, float g, float b, float a, float clearDepth, uint32 clearStencil)
{ {
uint32 depthBufferMipIndex = 0; // todo uint32 depthBufferMipIndex = 0; // todo
uint32 colorBufferMipIndex = 0; // todo uint32 colorBufferMipIndex = 0; // todo
@ -811,13 +780,11 @@ void LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask, MPTR colorB
bool targetFound = false; bool targetFound = false;
while (true) while (true)
{ {
LatteTextureView* colorView = LatteMRT_FindColorBufferForClearing(colorBufferMPTR, colorBufferWidth, colorBufferHeight, colorBufferPitch, colorBufferFormat, colorBufferViewFirstSlice, &searchIndex); LatteTextureView* colorView = LatteTC_LookupTextureByData(colorBufferMPTR, colorBufferWidth, colorBufferHeight, colorBufferPitch, 0, 1, colorBufferViewFirstSlice, 1, &searchIndex);
if (!colorView) if (!colorView)
break; break;
if (Latte::GetFormatBits((Latte::E_GX2SURFFMT)colorBufferFormat) != Latte::GetFormatBits(colorView->baseTexture->format)) if (Latte::GetFormatBits(colorBufferFormat) != Latte::GetFormatBits(colorView->baseTexture->format))
{
continue; continue;
}
if (colorView->baseTexture->pitch == colorBufferPitch && colorView->baseTexture->height == colorBufferHeight) if (colorView->baseTexture->pitch == colorBufferPitch && colorView->baseTexture->height == colorBufferHeight)
targetFound = true; targetFound = true;
@ -829,7 +796,7 @@ void LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask, MPTR colorB
{ {
// create new texture with matching format // create new texture with matching format
cemu_assert_debug(colorBufferViewNumSlice <= 1); cemu_assert_debug(colorBufferViewNumSlice <= 1);
LatteTextureView* newColorView = LatteMRT_CreateColorBuffer(colorBufferMPTR, colorBufferWidth, colorBufferHeight, colorBufferPitch, (Latte::E_GX2SURFFMT)colorBufferFormat, colorBufferTilemode, colorBufferSwizzle, colorBufferViewFirstSlice); LatteTextureView* newColorView = LatteTexture_CreateMapping(colorBufferMPTR, MPTR_NULL, colorBufferWidth, colorBufferHeight, colorBufferViewFirstSlice+1, colorBufferPitch, colorBufferTilemode, colorBufferSwizzle, 0, 1, colorBufferViewFirstSlice, 1, colorBufferFormat, colorBufferViewFirstSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false);
LatteRenderTarget_applyTextureColorClear(newColorView->baseTexture, colorBufferViewFirstSlice, colorBufferMipIndex, r, g, b, a, eventCounter); LatteRenderTarget_applyTextureColorClear(newColorView->baseTexture, colorBufferViewFirstSlice, colorBufferMipIndex, r, g, b, a, eventCounter);
} }
} }
@ -917,10 +884,8 @@ void LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPa
// mark source texture as still in use // mark source texture as still in use
LatteTC_MarkTextureStillInUse(textureView->baseTexture); LatteTC_MarkTextureStillInUse(textureView->baseTexture);
sint32 effectiveWidth; sint32 effectiveWidth, effectiveHeight;
sint32 effectiveHeight; textureView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0);
sint32 effectiveDepth;
LatteTexture_getEffectiveSize(textureView->baseTexture, &effectiveWidth, &effectiveHeight, &effectiveDepth, 0);
_currentOutputImageWidth = effectiveWidth; _currentOutputImageWidth = effectiveWidth;
_currentOutputImageHeight = effectiveHeight; _currentOutputImageHeight = effectiveHeight;

View file

@ -652,7 +652,7 @@ LatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompi
} }
else else
{ {
shader->uniform.count_uniformRegister = decompilerOutput.uniformOffsetsVK.count_uniformRegister; shader->uniform.count_uniformRegister = decompilerOutput.uniformOffsetsGL.count_uniformRegister;
} }
// calculate aux hash // calculate aux hash
if (calculateAuxHash) if (calculateAuxHash)

View file

@ -37,7 +37,7 @@ void LatteSurfaceCopy_copySurfaceNew(MPTR srcPhysAddr, MPTR srcMipAddr, uint32 s
if (!destinationTexture) if (!destinationTexture)
{ {
LatteTexture* renderTargetConf = nullptr; LatteTexture* renderTargetConf = nullptr;
destinationView = LatteTexture_CreateMapping(dstPhysAddr, dstMipAddr, dstWidth, dstHeight, dstDepth, dstPitch, dstTilemode, dstSwizzle, dstLevel, 1, dstSlice, 1, dstSurfaceFormat, dstDim, Latte::E_DIM::DIM_2D, false); destinationView = LatteTexture_CreateMapping(dstPhysAddr, dstMipAddr, dstWidth, dstHeight, dstDepth, dstPitch, dstTilemode, dstSwizzle, dstLevel, 1, dstSlice, 1, dstSurfaceFormat, dstDim, Latte::IsMSAA(dstDim) ? Latte::E_DIM::DIM_2D_MSAA : Latte::E_DIM::DIM_2D, false);
destinationTexture = destinationView->baseTexture; destinationTexture = destinationView->baseTexture;
} }
// copy texture // copy texture

View file

@ -297,9 +297,9 @@ void LatteTexture_copyData(LatteTexture* srcTexture, LatteTexture* dstTexture, s
else else
{ {
sint32 effectiveWidth_dst, effectiveHeight_dst; sint32 effectiveWidth_dst, effectiveHeight_dst;
LatteTexture_getEffectiveSize(srcTexture, &effectiveWidth_dst, &effectiveHeight_dst, NULL, 0); srcTexture->GetEffectiveSize(effectiveWidth_dst, effectiveHeight_dst, 0);
sint32 effectiveWidth_src, effectiveHeight_src; sint32 effectiveWidth_src, effectiveHeight_src;
LatteTexture_getEffectiveSize(dstTexture, &effectiveWidth_src, &effectiveHeight_src, NULL, 0); dstTexture->GetEffectiveSize(effectiveWidth_src, effectiveHeight_src, 0);
debug_printf("texture_copyData(): Effective size mismatch\n"); debug_printf("texture_copyData(): Effective size mismatch\n");
cemuLog_logDebug(LogType::Force, "texture_copyData(): Effective size mismatch (due to texture rule)"); cemuLog_logDebug(LogType::Force, "texture_copyData(): Effective size mismatch (due to texture rule)");
@ -307,8 +307,6 @@ void LatteTexture_copyData(LatteTexture* srcTexture, LatteTexture* dstTexture, s
cemuLog_logDebug(LogType::Force, "Source: origResolution {:04}x{:04} effectiveResolution {:04}x{:04} fmt {:04x} mipIndex {}", srcTexture->width, srcTexture->height, effectiveWidth_src, effectiveHeight_src, (uint32)srcTexture->format, 0); cemuLog_logDebug(LogType::Force, "Source: origResolution {:04}x{:04} effectiveResolution {:04}x{:04} fmt {:04x} mipIndex {}", srcTexture->width, srcTexture->height, effectiveWidth_src, effectiveHeight_src, (uint32)srcTexture->format, 0);
return; return;
} }
catchOpenGLError();
for (sint32 mipIndex = 0; mipIndex < mipCount; mipIndex++) for (sint32 mipIndex = 0; mipIndex < mipCount; mipIndex++)
{ {
sint32 sliceCopyWidth = std::max(effectiveCopyWidth >> mipIndex, 1); sint32 sliceCopyWidth = std::max(effectiveCopyWidth >> mipIndex, 1);
@ -323,9 +321,7 @@ void LatteTexture_copyData(LatteTexture* srcTexture, LatteTexture* dstTexture, s
LatteTextureSliceMipInfo* dstTexSliceInfo = dstTexture->sliceMipInfo + dstTexture->GetSliceMipArrayIndex(sliceIndex, mipIndex); LatteTextureSliceMipInfo* dstTexSliceInfo = dstTexture->sliceMipInfo + dstTexture->GetSliceMipArrayIndex(sliceIndex, mipIndex);
dstTexSliceInfo->lastDynamicUpdate = srcTexSliceInfo->lastDynamicUpdate; dstTexSliceInfo->lastDynamicUpdate = srcTexSliceInfo->lastDynamicUpdate;
} }
catchOpenGLError();
} }
catchOpenGLError();
} }
template<bool bothMustMatch> template<bool bothMustMatch>
@ -438,6 +434,11 @@ void LatteTexture_SyncSlice(LatteTexture* srcTexture, sint32 srcSliceIndex, sint
sint32 dstWidth = dstTexture->width; sint32 dstWidth = dstTexture->width;
sint32 dstHeight = dstTexture->height; sint32 dstHeight = dstTexture->height;
if(srcTexture->overwriteInfo.hasFormatOverwrite != dstTexture->overwriteInfo.hasFormatOverwrite)
return; // dont sync: format overwrite state needs to match. Not strictly necessary but it simplifies logic down the road
else if(srcTexture->overwriteInfo.hasFormatOverwrite && srcTexture->overwriteInfo.format != dstTexture->overwriteInfo.format)
return; // both are overwritten but with different formats
if (srcMipIndex == 0 && dstMipIndex == 0 && (srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED || srcTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1) && srcTexture->height > dstTexture->height && (srcTexture->height % dstTexture->height) == 0) if (srcMipIndex == 0 && dstMipIndex == 0 && (srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED || srcTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1) && srcTexture->height > dstTexture->height && (srcTexture->height % dstTexture->height) == 0)
{ {
bool isMatch = srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED; bool isMatch = srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED;
@ -790,87 +791,42 @@ enum VIEWCOMPATIBILITY
VIEW_NOT_COMPATIBLE, VIEW_NOT_COMPATIBLE,
}; };
bool IsDimensionCompatibleForView(Latte::E_DIM baseDim, Latte::E_DIM viewDim) bool IsDimensionCompatibleForGX2View(Latte::E_DIM baseDim, Latte::E_DIM viewDim)
{ {
bool incompatibleDim = false; // Note that some combinations depend on the exact view/slice index and count which we currently ignore (like a 3D view of a 3D texture)
if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D) bool isCompatible =
; (baseDim == viewDim) ||
else if (baseDim == Latte::E_DIM::DIM_1D && viewDim == Latte::E_DIM::DIM_1D) (baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D) ||
; (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_ARRAY) ||
else if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_ARRAY) (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_2D) ||
; (baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D_ARRAY) ||
else if (baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_CUBEMAP) (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_CUBEMAP) ||
; (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_2D_ARRAY);
else if (baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D_ARRAY) if(isCompatible)
; return true;
else if (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_2D_ARRAY) // these combinations have been seen in use by games and are considered incompatible:
; // (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_3D) -> Not allowed on OpenGL
else if (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_2D) // (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_MSAA)
; // (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_1D)
else if (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_CUBEMAP) // (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_3D)
; // (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_2D)
else if (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_2D_ARRAY) // (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_3D) -> Only compatible if the same depth and shared at mip/slice 0
; // (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_CUBEMAP)
else if (baseDim == Latte::E_DIM::DIM_2D_MSAA && viewDim == Latte::E_DIM::DIM_2D_MSAA) // (baseDim == Latte::E_DIM::DIM_2D_MSAA && viewDim == Latte::E_DIM::DIM_2D)
; // (baseDim == Latte::E_DIM::DIM_1D && viewDim == Latte::E_DIM::DIM_2D)
else if (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_3D) return false;
{
// not compatible on OpenGL
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_MSAA)
{
// not compatible
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_1D)
{
// not compatible
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_3D)
{
// not compatible
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_2D)
{
// not compatible
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_3D)
{
// incompatible by default, but may be compatible if the view matches the depth of the base texture and starts at mip/slice 0
incompatibleDim = true;
}
else if ((baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_CUBEMAP) ||
(baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D))
{
// not compatible
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_2D_MSAA && viewDim == Latte::E_DIM::DIM_2D)
{
// not compatible
incompatibleDim = true;
}
else if (baseDim == Latte::E_DIM::DIM_1D && viewDim == Latte::E_DIM::DIM_2D)
{
// not compatible (probably?)
incompatibleDim = true;
}
else
{
cemu_assert_debug(false);
incompatibleDim = true;
}
return !incompatibleDim;
} }
VIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseTexture, uint32 physAddr, sint32 width, sint32 height, sint32 pitch, Latte::E_DIM dimView, Latte::E_GX2SURFFMT format, bool isDepth, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32& relativeMipIndex, sint32& relativeSliceIndex) VIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseTexture, uint32 physAddr, sint32 width, sint32 height, sint32 pitch, Latte::E_DIM dimView, Latte::E_GX2SURFFMT format, bool isDepth, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32& relativeMipIndex, sint32& relativeSliceIndex)
{ {
relativeMipIndex = 0; relativeMipIndex = 0;
relativeSliceIndex = 0; relativeSliceIndex = 0;
if (baseTexture->overwriteInfo.hasFormatOverwrite)
{
// if the base format is overwritten, then we only allow aliasing if the view format matches the base format
if (baseTexture->format != format)
return VIEW_NOT_COMPATIBLE;
}
if (LatteTexture_IsFormatViewCompatible(baseTexture->format, format) == false) if (LatteTexture_IsFormatViewCompatible(baseTexture->format, format) == false)
return VIEW_NOT_COMPATIBLE; return VIEW_NOT_COMPATIBLE;
if (baseTexture->physAddress == physAddr && baseTexture->pitch == pitch) if (baseTexture->physAddress == physAddr && baseTexture->pitch == pitch)
@ -881,7 +837,7 @@ VIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseT
return VIEW_NOT_COMPATIBLE; return VIEW_NOT_COMPATIBLE;
// 3D views are only compatible on Vulkan if they match the base texture in regards to mip and slice count // 3D views are only compatible on Vulkan if they match the base texture in regards to mip and slice count
bool isCompatible3DView = dimView == Latte::E_DIM::DIM_3D && baseTexture->dim == dimView && firstSlice == 0 && firstMip == 0 && baseTexture->mipLevels == numMip && baseTexture->depth == numSlice; bool isCompatible3DView = dimView == Latte::E_DIM::DIM_3D && baseTexture->dim == dimView && firstSlice == 0 && firstMip == 0 && baseTexture->mipLevels == numMip && baseTexture->depth == numSlice;
if (!isCompatible3DView && !IsDimensionCompatibleForView(baseTexture->dim, dimView)) if (!isCompatible3DView && !IsDimensionCompatibleForGX2View(baseTexture->dim, dimView))
return VIEW_NOT_COMPATIBLE; return VIEW_NOT_COMPATIBLE;
if (baseTexture->isDepth && baseTexture->format != format) if (baseTexture->isDepth && baseTexture->format != format)
{ {
@ -933,7 +889,7 @@ VIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseT
if (!LatteTexture_IsTexelSizeCompatibleFormat(baseTexture->format, format) ) if (!LatteTexture_IsTexelSizeCompatibleFormat(baseTexture->format, format) )
return VIEW_NOT_COMPATIBLE; return VIEW_NOT_COMPATIBLE;
if (!IsDimensionCompatibleForView(baseTexture->dim, dimView)) if (!IsDimensionCompatibleForGX2View(baseTexture->dim, dimView))
return VIEW_NOT_COMPATIBLE; return VIEW_NOT_COMPATIBLE;
if (baseTexture->isDepth && baseTexture->format != format) if (baseTexture->isDepth && baseTexture->format != format)
{ {
@ -1243,6 +1199,15 @@ std::vector<LatteTexture*>& LatteTexture::GetAllTextures()
return sAllTextures; return sAllTextures;
} }
bool LatteTexture_GX2FormatHasStencil(bool isDepth, Latte::E_GX2SURFFMT format)
{
if (!isDepth)
return false;
return format == Latte::E_GX2SURFFMT::D24_S8_UNORM ||
format == Latte::E_GX2SURFFMT::D24_S8_FLOAT ||
format == Latte::E_GX2SURFFMT::D32_S8_FLOAT;
}
LatteTexture::LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, LatteTexture::LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,
Latte::E_HWTILEMODE tileMode, bool isDepth) Latte::E_HWTILEMODE tileMode, bool isDepth)
{ {
@ -1261,6 +1226,7 @@ LatteTexture::LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddre
this->mipLevels = mipLevels; this->mipLevels = mipLevels;
this->tileMode = tileMode; this->tileMode = tileMode;
this->isDepth = isDepth; this->isDepth = isDepth;
this->hasStencil = LatteTexture_GX2FormatHasStencil(isDepth, format);
this->physMipAddress = physMipAddress; this->physMipAddress = physMipAddress;
this->lastUpdateEventCounter = LatteTexture_getNextUpdateEventCounter(); this->lastUpdateEventCounter = LatteTexture_getNextUpdateEventCounter();
this->lastWriteEventCounter = LatteTexture_getNextUpdateEventCounter(); this->lastWriteEventCounter = LatteTexture_getNextUpdateEventCounter();

View file

@ -27,6 +27,8 @@ public:
LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);
virtual ~LatteTexture(); virtual ~LatteTexture();
virtual void AllocateOnHost() = 0;
LatteTextureView* GetOrCreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) LatteTextureView* GetOrCreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
{ {
for (auto& itr : views) for (auto& itr : views)
@ -55,6 +57,29 @@ public:
bool Is3DTexture() const { return dim == Latte::E_DIM::DIM_3D; }; bool Is3DTexture() const { return dim == Latte::E_DIM::DIM_3D; };
void GetSize(sint32& width, sint32& height, sint32 mipLevel) const
{
width = std::max(1, this->width >> mipLevel);
height = std::max(1, this->height >> mipLevel);
}
// similar to GetSize, but returns the real size of the texture taking into account any resolution overwrite by gfx pack rules
void GetEffectiveSize(sint32& effectiveWidth, sint32& effectiveHeight, sint32 mipLevel) const
{
if( overwriteInfo.hasResolutionOverwrite )
{
effectiveWidth = overwriteInfo.width;
effectiveHeight = overwriteInfo.height;
}
else
{
effectiveWidth = this->width;
effectiveHeight = this->height;
}
effectiveWidth = std::max(1, effectiveWidth >> mipLevel);
effectiveHeight = std::max(1, effectiveHeight >> mipLevel);
}
sint32 GetMipDepth(sint32 mipIndex) sint32 GetMipDepth(sint32 mipIndex)
{ {
cemu_assert_debug(mipIndex >= 0 && mipIndex < this->mipLevels); cemu_assert_debug(mipIndex >= 0 && mipIndex < this->mipLevels);
@ -310,8 +335,6 @@ void LatteTexture_Delete(LatteTexture* texture);
void LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* textureData, uint32 sliceIndex, uint32 mipIndex, uint8* linearPixelData); void LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* textureData, uint32 sliceIndex, uint32 mipIndex, uint8* linearPixelData);
void LatteTexture_getSize(LatteTexture* texture, sint32* width, sint32* height, sint32* depth, sint32 mipLevel);
void LatteTexture_getEffectiveSize(LatteTexture* texture, sint32* effectiveWidth, sint32* effectiveHeight, sint32* effectiveDepth, sint32 mipLevel = 0);
sint32 LatteTexture_getEffectiveWidth(LatteTexture* texture); sint32 LatteTexture_getEffectiveWidth(LatteTexture* texture);
bool LatteTexture_doesEffectiveRescaleRatioMatch(LatteTexture* texture1, sint32 mipLevel1, LatteTexture* texture2, sint32 mipLevel2); bool LatteTexture_doesEffectiveRescaleRatioMatch(LatteTexture* texture1, sint32 mipLevel1, LatteTexture* texture2, sint32 mipLevel2);
void LatteTexture_scaleToEffectiveSize(LatteTexture* texture, sint32* x, sint32* y, sint32 mipLevel); void LatteTexture_scaleToEffectiveSize(LatteTexture* texture, sint32* x, sint32* y, sint32 mipLevel);

View file

@ -316,7 +316,7 @@ void LatteTexture_Delete(LatteTexture* texture)
delete[] texture->sliceMipInfo; delete[] texture->sliceMipInfo;
texture->sliceMipInfo = nullptr; texture->sliceMipInfo = nullptr;
} }
g_renderer->texture_destroy(texture); delete texture;
} }
/* /*

View file

@ -207,13 +207,13 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u
bool isDepthSampler = shaderContext->textureUsesDepthCompare[textureIndex]; bool isDepthSampler = shaderContext->textureUsesDepthCompare[textureIndex];
// look for already existing texture // look for already existing texture
LatteTextureView* textureView; LatteTextureView* textureView;
if (isDepthSampler == false) if (!isDepthSampler)
textureView = LatteTextureViewLookupCache::lookup(physAddr, width, height, depth, pitch, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim); textureView = LatteTextureViewLookupCache::lookup(physAddr, width, height, depth, pitch, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim);
else else
textureView = LatteTextureViewLookupCache::lookup(physAddr, width, height, depth, pitch, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim, true); textureView = LatteTextureViewLookupCache::lookupWithColorOrDepthType(physAddr, width, height, depth, pitch, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim, true);
if (textureView == nullptr) if (!textureView)
{ {
// create new mapping // view not found, create a new mapping which will also create a new texture if necessary
textureView = LatteTexture_CreateMapping(physAddr, physMipAddr, width, height, depth, pitch, tileMode, swizzle, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim, dim, isDepthSampler); textureView = LatteTexture_CreateMapping(physAddr, physMipAddr, width, height, depth, pitch, tileMode, swizzle, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim, dim, isDepthSampler);
if (textureView == nullptr) if (textureView == nullptr)
continue; continue;
@ -229,21 +229,16 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u
// if this texture is bound multiple times then use alternative views // if this texture is bound multiple times then use alternative views
if (textureView->lastTextureBindIndex == LatteGPUState.textureBindCounter) if (textureView->lastTextureBindIndex == LatteGPUState.textureBindCounter)
{ {
// Intel driver has issues with textures that have multiple views bound and used by a shader, causes a softlock in BotW LatteTextureViewGL* textureViewGL = (LatteTextureViewGL*)textureView;
// therefore we disable this on Intel // get next unused alternative texture view
if (LatteGPUState.glVendor != GLVENDOR_INTEL_NOLEGACY) while (true)
{ {
LatteTextureViewGL* textureViewGL = (LatteTextureViewGL*)textureView; textureViewGL = textureViewGL->GetAlternativeView();
// get next unused alternative texture view if (textureViewGL->lastTextureBindIndex != LatteGPUState.textureBindCounter)
while (true) break;
{
textureViewGL = textureViewGL->GetAlternativeView();
if (textureViewGL->lastTextureBindIndex != LatteGPUState.textureBindCounter)
break;
}
textureView = textureViewGL;
} }
} textureView = textureViewGL;
}
textureView->lastTextureBindIndex = LatteGPUState.textureBindCounter; textureView->lastTextureBindIndex = LatteGPUState.textureBindCounter;
rendererGL->renderstate_updateTextureSettingsGL(shaderContext, textureView, textureIndex + glBackendBaseTexUnit, word4, textureIndex, isDepthSampler); rendererGL->renderstate_updateTextureSettingsGL(shaderContext, textureView, textureIndex + glBackendBaseTexUnit, word4, textureIndex, isDepthSampler);
} }
@ -273,9 +268,7 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u
// check for changes // check for changes
if (LatteTC_HasTextureChanged(textureView->baseTexture) || swizzleChanged) if (LatteTC_HasTextureChanged(textureView->baseTexture) || swizzleChanged)
{ {
#ifdef CEMU_DEBUG_ASSERT
debug_printf("Reload texture 0x%08x res %dx%d memRange %08x-%08x SwizzleChange: %s\n", textureView->baseTexture->physAddress, textureView->baseTexture->width, textureView->baseTexture->height, textureView->baseTexture->texDataPtrLow, textureView->baseTexture->texDataPtrHigh, swizzleChanged ? "yes" : "no"); debug_printf("Reload texture 0x%08x res %dx%d memRange %08x-%08x SwizzleChange: %s\n", textureView->baseTexture->physAddress, textureView->baseTexture->width, textureView->baseTexture->height, textureView->baseTexture->texDataPtrLow, textureView->baseTexture->texDataPtrHigh, swizzleChanged ? "yes" : "no");
#endif
// update swizzle / changed mip address // update swizzle / changed mip address
if (swizzleChanged) if (swizzleChanged)
{ {
@ -338,44 +331,6 @@ void LatteTexture_updateTextures()
LatteTexture_updateTexturesForStage(geometryShader, LATTE_CEMU_GS_TEX_UNIT_BASE, LatteGPUState.contextNew.SQ_TEX_START_GS); LatteTexture_updateTexturesForStage(geometryShader, LATTE_CEMU_GS_TEX_UNIT_BASE, LatteGPUState.contextNew.SQ_TEX_START_GS);
} }
// returns the width, height, depth of the texture
void LatteTexture_getSize(LatteTexture* texture, sint32* width, sint32* height, sint32* depth, sint32 mipLevel)
{
*width = texture->width;
*height = texture->height;
if (depth != NULL)
*depth = texture->depth;
// handle mip level
*width = std::max(1, *width >> mipLevel);
*height = std::max(1, *height >> mipLevel);
if(texture->Is3DTexture() && depth)
*depth = std::max(1, *depth >> mipLevel);
}
/*
* Returns the internally used width/height/depth of the texture
* Usually this is the width/height/depth specified by the game,
* unless the texture resolution was redefined via graphic pack texture rules
*/
void LatteTexture_getEffectiveSize(LatteTexture* texture, sint32* effectiveWidth, sint32* effectiveHeight, sint32* effectiveDepth, sint32 mipLevel)
{
*effectiveWidth = texture->width;
*effectiveHeight = texture->height;
if( effectiveDepth != NULL )
*effectiveDepth = texture->depth;
if( texture->overwriteInfo.hasResolutionOverwrite )
{
*effectiveWidth = texture->overwriteInfo.width;
*effectiveHeight = texture->overwriteInfo.height;
if( effectiveDepth != NULL )
*effectiveDepth = texture->overwriteInfo.depth;
}
// handle mipLevel
// todo: Mip-mapped 3D textures decrease in depth also?
*effectiveWidth = std::max(1, *effectiveWidth >> mipLevel);
*effectiveHeight = std::max(1, *effectiveHeight >> mipLevel);
}
sint32 LatteTexture_getEffectiveWidth(LatteTexture* texture) sint32 LatteTexture_getEffectiveWidth(LatteTexture* texture)
{ {
if (texture->overwriteInfo.hasResolutionOverwrite) if (texture->overwriteInfo.hasResolutionOverwrite)

View file

@ -621,7 +621,7 @@ void LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, uint32 sliceIn
if (tex->isDataDefined == false) if (tex->isDataDefined == false)
{ {
g_renderer->texture_reserveTextureOnGPU(tex); tex->AllocateOnHost();
tex->isDataDefined = true; tex->isDataDefined = true;
// if decoder is not set then clear texture // if decoder is not set then clear texture
// on Vulkan this is used to make sure the texture is no longer in UNDEFINED layout // on Vulkan this is used to make sure the texture is no longer in UNDEFINED layout

View file

@ -143,7 +143,6 @@ void LatteTextureViewLookupCache::RemoveAll(LatteTextureView* view)
} }
} }
LatteTextureView* LatteTextureViewLookupCache::lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim) LatteTextureView* LatteTextureViewLookupCache::lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim)
{ {
// todo - add tileMode param to this and the other lookup functions? // todo - add tileMode param to this and the other lookup functions?
@ -163,7 +162,7 @@ LatteTextureView* LatteTextureViewLookupCache::lookup(MPTR physAddr, sint32 widt
return nullptr; return nullptr;
} }
LatteTextureView* LatteTextureViewLookupCache::lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, bool isDepth) LatteTextureView* LatteTextureViewLookupCache::lookupWithColorOrDepthType(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, bool isDepth)
{ {
cemu_assert_debug(firstSlice == 0); cemu_assert_debug(firstSlice == 0);
uint32 key = _getViewBucketKey(physAddr, width, height, pitch); uint32 key = _getViewBucketKey(physAddr, width, height, pitch);

View file

@ -41,7 +41,7 @@ public:
static void RemoveAll(LatteTextureView* view); static void RemoveAll(LatteTextureView* view);
static LatteTextureView* lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim); static LatteTextureView* lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim);
static LatteTextureView* lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, bool isDepth); static LatteTextureView* lookupWithColorOrDepthType(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, bool isDepth);
static LatteTextureView* lookupSlice(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format); static LatteTextureView* lookupSlice(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format);
static LatteTextureView* lookupSliceMinSize(MPTR physAddr, sint32 minWidth, sint32 minHeight, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format); static LatteTextureView* lookupSliceMinSize(MPTR physAddr, sint32 minWidth, sint32 minHeight, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format);
static LatteTextureView* lookupSliceEx(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format, bool isDepth); static LatteTextureView* lookupSliceEx(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format, bool isDepth);

View file

@ -140,13 +140,7 @@ int Latte_ThreadEntry()
case GfxVendor::AMD: case GfxVendor::AMD:
LatteGPUState.glVendor = GLVENDOR_AMD; LatteGPUState.glVendor = GLVENDOR_AMD;
break; break;
case GfxVendor::IntelLegacy: case GfxVendor::Intel:
LatteGPUState.glVendor = GLVENDOR_INTEL_LEGACY;
break;
case GfxVendor::IntelNoLegacy:
LatteGPUState.glVendor = GLVENDOR_INTEL_NOLEGACY;
break;
case GfxVendor::Intel:
LatteGPUState.glVendor = GLVENDOR_INTEL; LatteGPUState.glVendor = GLVENDOR_INTEL;
break; break;
case GfxVendor::Nvidia: case GfxVendor::Nvidia:

View file

@ -345,6 +345,11 @@ namespace Latte
return IsCompressedFormat((Latte::E_HWSURFFMT)((uint32)format & 0x3F)); return IsCompressedFormat((Latte::E_HWSURFFMT)((uint32)format & 0x3F));
} }
inline bool IsMSAA(Latte::E_DIM dim)
{
return dim == E_DIM::DIM_2D_MSAA || dim == E_DIM::DIM_2D_ARRAY_MSAA;
}
enum GPU_LIMITS enum GPU_LIMITS
{ {
NUM_VERTEX_BUFFERS = 16, NUM_VERTEX_BUFFERS = 16,

View file

@ -787,7 +787,7 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
continue; continue;
LatteDecompilerShader::QuickBufferEntry entry; LatteDecompilerShader::QuickBufferEntry entry;
entry.index = i; entry.index = i;
entry.size = shaderContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE) * 16; entry.size = shaderContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(shaderContext->shaderBaseHash, LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE) * 16;
shader->list_quickBufferList.push_back(entry); shader->list_quickBufferList.push_back(entry);
} }
// get dimension of each used texture // get dimension of each used texture

View file

@ -37,7 +37,7 @@ namespace LatteDecompiler
} }
else if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE) else if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)
{ {
uint32 cfileSize = decompilerContext->analyzer.uniformRegisterAccessTracker.DetermineSize(256); uint32 cfileSize = decompilerContext->analyzer.uniformRegisterAccessTracker.DetermineSize(decompilerContext->shaderBaseHash, 256);
// full or partial uniform register file has to be present // full or partial uniform register file has to be present
if (shaderType == LatteConst::ShaderType::Vertex) if (shaderType == LatteConst::ShaderType::Vertex)
shaderSrc->addFmt("uniform ivec4 uf_uniformRegisterVS[{}];" _CRLF, cfileSize); shaderSrc->addFmt("uniform ivec4 uf_uniformRegisterVS[{}];" _CRLF, cfileSize);
@ -156,7 +156,7 @@ namespace LatteDecompiler
shaderSrc->addFmt("uniform {}{}" _CRLF, _getShaderUniformBlockInterfaceName(decompilerContext->shaderType), i); shaderSrc->addFmt("uniform {}{}" _CRLF, _getShaderUniformBlockInterfaceName(decompilerContext->shaderType), i);
shaderSrc->add("{" _CRLF); shaderSrc->add("{" _CRLF);
shaderSrc->addFmt("vec4 {}{}[{}];" _CRLF, _getShaderUniformBlockVariableName(decompilerContext->shaderType), i, decompilerContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE)); shaderSrc->addFmt("vec4 {}{}[{}];" _CRLF, _getShaderUniformBlockVariableName(decompilerContext->shaderType), i, decompilerContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(decompilerContext->shaderBaseHash, LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE));
shaderSrc->add("};" _CRLF _CRLF); shaderSrc->add("};" _CRLF _CRLF);
shaderSrc->add(_CRLF); shaderSrc->add(_CRLF);
} }

View file

@ -157,19 +157,23 @@ struct LatteDecompilerBufferAccessTracker
} }
} }
sint32 DetermineSize(sint32 maximumSize) const sint32 DetermineSize(uint64 shaderBaseHash, sint32 maximumSize) const
{ {
// here we try to predict the accessed range so we dont have to upload the whole buffer // here we try to predict the accessed byte range so we dont have to upload the whole buffer
// potential risky optimization: assume that if there is a fixed-index access on an index higher than any other non-zero relative accesses, it bounds the prior relative access // if no bound can be determined then return maximumSize
// for some known shaders we use hand-tuned values instead of the maximumSize fallback value that those shaders would normally use
if(shaderBaseHash == 0x8ff56afdf1a2f837) // XCX text rendering
return 24;
if(shaderBaseHash == 0x37b9100c1310d3bb) // BotW UI backdrops 1
return 24;
if(shaderBaseHash == 0xf7ba548c1fefe24a) // BotW UI backdrops 2
return 30;
sint32 highestAccessIndex = -1; sint32 highestAccessIndex = -1;
if(hasStaticIndexAccess) if(hasStaticIndexAccess)
{
highestAccessIndex = highestAccessStaticIndex; highestAccessIndex = highestAccessStaticIndex;
}
if(hasDynamicIndexAccess) if(hasDynamicIndexAccess)
{
return maximumSize; // dynamic index exists and no bound can be determined return maximumSize; // dynamic index exists and no bound can be determined
}
if (highestAccessIndex < 0) if (highestAccessIndex < 0)
return 1; // no access at all? But avoid zero as a size return 1; // no access at all? But avoid zero as a size
return highestAccessIndex + 1; return highestAccessIndex + 1;

View file

@ -5,20 +5,6 @@
#include "config/LaunchSettings.h" #include "config/LaunchSettings.h"
GLuint texIdPool[64];
sint32 texIdPoolIndex = 64;
static GLuint _genTextureHandleGL()
{
if (texIdPoolIndex == 64)
{
glGenTextures(64, texIdPool);
texIdPoolIndex = 0;
}
texIdPoolIndex++;
return texIdPool[texIdPoolIndex - 1];
}
LatteTextureGL::LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, LatteTextureGL::LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,
Latte::E_HWTILEMODE tileMode, bool isDepth) Latte::E_HWTILEMODE tileMode, bool isDepth)
: LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth) : LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth)
@ -26,10 +12,9 @@ LatteTextureGL::LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipA
GenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget, true); GenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget, true);
// set format info // set format info
FormatInfoGL glFormatInfo; FormatInfoGL glFormatInfo;
GetOpenGLFormatInfo(isDepth, format, dim, &glFormatInfo); GetOpenGLFormatInfo(isDepth, overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)overwriteInfo.format : format, dim, &glFormatInfo);
this->glInternalFormat = glFormatInfo.glInternalFormat; this->glInternalFormat = glFormatInfo.glInternalFormat;
this->isAlternativeFormat = glFormatInfo.isUsingAlternativeFormat; this->isAlternativeFormat = glFormatInfo.isUsingAlternativeFormat;
this->hasStencil = glFormatInfo.hasStencil; // todo - should get this from the GX2 format?
// set debug name // set debug name
bool useGLDebugNames = false; bool useGLDebugNames = false;
#ifdef CEMU_DEBUG_ASSERT #ifdef CEMU_DEBUG_ASSERT
@ -88,34 +73,34 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
{ {
if (format == Latte::E_GX2SURFFMT::D24_S8_UNORM) if (format == Latte::E_GX2SURFFMT::D24_S8_UNORM)
{ {
formatInfoOut->setDepthFormat(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, true); formatInfoOut->setFormat(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
return; return;
} }
else if (format == Latte::E_GX2SURFFMT::D24_S8_FLOAT) else if (format == Latte::E_GX2SURFFMT::D24_S8_FLOAT)
{ {
formatInfoOut->setDepthFormat(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, true); formatInfoOut->setFormat(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
formatInfoOut->markAsAlternativeFormat(); formatInfoOut->markAsAlternativeFormat();
return; return;
} }
else if (format == Latte::E_GX2SURFFMT::D32_S8_FLOAT) else if (format == Latte::E_GX2SURFFMT::D32_S8_FLOAT)
{ {
formatInfoOut->setDepthFormat(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, true); formatInfoOut->setFormat(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
return; return;
} }
else if (format == Latte::E_GX2SURFFMT::D32_FLOAT) else if (format == Latte::E_GX2SURFFMT::D32_FLOAT)
{ {
formatInfoOut->setDepthFormat(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, false); formatInfoOut->setFormat(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT);
return; return;
} }
else if (format == Latte::E_GX2SURFFMT::D16_UNORM) else if (format == Latte::E_GX2SURFFMT::D16_UNORM)
{ {
formatInfoOut->setDepthFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false); formatInfoOut->setFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);
return; return;
} }
// unsupported depth format // unsupported depth format
cemuLog_log(LogType::Force, "OpenGL: Unsupported texture depth format 0x{:04x}", (uint32)format); cemuLog_log(LogType::Force, "OpenGL: Unsupported texture depth format 0x{:04x}", (uint32)format);
// use placeholder format // use placeholder format
formatInfoOut->setDepthFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, false); formatInfoOut->setFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);
formatInfoOut->markAsAlternativeFormat(); formatInfoOut->markAsAlternativeFormat();
return; return;
} }
@ -125,10 +110,6 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
sint32 glInternalFormat; sint32 glInternalFormat;
sint32 glSuppliedFormat; sint32 glSuppliedFormat;
sint32 glSuppliedFormatType; sint32 glSuppliedFormatType;
// check if compressed textures should be used
bool allowCompressedGLFormat = true;
if (LatteGPUState.glVendor == GLVENDOR_INTEL_LEGACY)
allowCompressedGLFormat = false; // compressed formats seem to cause more harm than good on Intel
// get format information // get format information
if (format == Latte::E_GX2SURFFMT::R4_G4_UNORM) if (format == Latte::E_GX2SURFFMT::R4_G4_UNORM)
{ {
@ -164,20 +145,11 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
else if (format == Latte::E_GX2SURFFMT::BC1_UNORM || else if (format == Latte::E_GX2SURFFMT::BC1_UNORM ||
format == Latte::E_GX2SURFFMT::BC1_SRGB) format == Latte::E_GX2SURFFMT::BC1_SRGB)
{ {
if (allowCompressedGLFormat) if (format == Latte::E_GX2SURFFMT::BC1_SRGB)
{ formatInfoOut->setCompressed(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, -1, -1);
if (format == Latte::E_GX2SURFFMT::BC1_SRGB)
formatInfoOut->setCompressed(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, -1, -1);
else
formatInfoOut->setCompressed(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, -1, -1);
return;
}
else else
{ formatInfoOut->setCompressed(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, -1, -1);
formatInfoOut->setFormat(GL_RGBA16F, GL_RGBA, GL_FLOAT); return;
formatInfoOut->markAsAlternativeFormat();
return;
}
} }
else if (format == Latte::E_GX2SURFFMT::BC2_UNORM || format == Latte::E_GX2SURFFMT::BC2_SRGB) else if (format == Latte::E_GX2SURFFMT::BC2_UNORM || format == Latte::E_GX2SURFFMT::BC2_SRGB)
{ {
@ -188,28 +160,18 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
} }
else if (format == Latte::E_GX2SURFFMT::BC3_UNORM || format == Latte::E_GX2SURFFMT::BC3_SRGB) else if (format == Latte::E_GX2SURFFMT::BC3_UNORM || format == Latte::E_GX2SURFFMT::BC3_SRGB)
{ {
if (allowCompressedGLFormat) if (format == Latte::E_GX2SURFFMT::BC3_SRGB)
{ formatInfoOut->setCompressed(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, -1, -1);
if (format == Latte::E_GX2SURFFMT::BC3_SRGB)
formatInfoOut->setCompressed(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, -1, -1);
else
formatInfoOut->setCompressed(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, -1, -1);
return;
}
else else
{ formatInfoOut->setCompressed(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, -1, -1);
// todo: SRGB support return;
formatInfoOut->setFormat(GL_RGBA16F, GL_RGBA, GL_FLOAT);
formatInfoOut->markAsAlternativeFormat();
return;
}
} }
else if (format == Latte::E_GX2SURFFMT::BC4_UNORM || format == Latte::E_GX2SURFFMT::BC4_SNORM) else if (format == Latte::E_GX2SURFFMT::BC4_UNORM || format == Latte::E_GX2SURFFMT::BC4_SNORM)
{ {
bool allowCompressed = true;
if (dim != Latte::E_DIM::DIM_2D && dim != Latte::E_DIM::DIM_2D_ARRAY) if (dim != Latte::E_DIM::DIM_2D && dim != Latte::E_DIM::DIM_2D_ARRAY)
allowCompressedGLFormat = false; // RGTC1 does not support non-2D textures allowCompressed = false; // RGTC1 does not support non-2D textures
if (allowCompressed)
if (allowCompressedGLFormat)
{ {
if (format == Latte::E_GX2SURFFMT::BC4_UNORM) if (format == Latte::E_GX2SURFFMT::BC4_UNORM)
formatInfoOut->setCompressed(GL_COMPRESSED_RED_RGTC1, -1, -1); formatInfoOut->setCompressed(GL_COMPRESSED_RED_RGTC1, -1, -1);
@ -226,20 +188,11 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
} }
else if (format == Latte::E_GX2SURFFMT::BC5_UNORM || format == Latte::E_GX2SURFFMT::BC5_SNORM) else if (format == Latte::E_GX2SURFFMT::BC5_UNORM || format == Latte::E_GX2SURFFMT::BC5_SNORM)
{ {
if (allowCompressedGLFormat) if (format == Latte::E_GX2SURFFMT::BC5_SNORM)
{ formatInfoOut->setCompressed(GL_COMPRESSED_SIGNED_RG_RGTC2, -1, -1);
if (format == Latte::E_GX2SURFFMT::BC5_SNORM)
formatInfoOut->setCompressed(GL_COMPRESSED_SIGNED_RG_RGTC2, -1, -1);
else
formatInfoOut->setCompressed(GL_COMPRESSED_RG_RGTC2, -1, -1);
return;
}
else else
{ formatInfoOut->setCompressed(GL_COMPRESSED_RG_RGTC2, -1, -1);
formatInfoOut->setFormat(GL_RG16F, GL_RG, GL_FLOAT); return;
formatInfoOut->markAsAlternativeFormat();
return;
}
} }
else if (format == Latte::E_GX2SURFFMT::R32_FLOAT) else if (format == Latte::E_GX2SURFFMT::R32_FLOAT)
{ {
@ -496,3 +449,49 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
formatInfoOut->glIsCompressed = glIsCompressed; formatInfoOut->glIsCompressed = glIsCompressed;
formatInfoOut->isUsingAlternativeFormat = isUsingAlternativeFormat; formatInfoOut->isUsingAlternativeFormat = isUsingAlternativeFormat;
} }
void LatteTextureGL::AllocateOnHost()
{
auto hostTexture = this;
cemu_assert_debug(hostTexture->isDataDefined == false);
sint32 effectiveBaseWidth = hostTexture->width;
sint32 effectiveBaseHeight = hostTexture->height;
sint32 effectiveBaseDepth = hostTexture->depth;
if (hostTexture->overwriteInfo.hasResolutionOverwrite)
{
effectiveBaseWidth = hostTexture->overwriteInfo.width;
effectiveBaseHeight = hostTexture->overwriteInfo.height;
effectiveBaseDepth = hostTexture->overwriteInfo.depth;
}
// calculate mip count
sint32 mipLevels = std::min(hostTexture->mipLevels, hostTexture->maxPossibleMipLevels);
mipLevels = std::max(mipLevels, 1);
// create immutable storage
if (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA)
{
cemu_assert_debug(effectiveBaseDepth == 1);
glTextureStorage2DWrapper(GL_TEXTURE_2D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight);
}
else if (hostTexture->dim == Latte::E_DIM::DIM_1D)
{
cemu_assert_debug(effectiveBaseHeight == 1);
cemu_assert_debug(effectiveBaseDepth == 1);
glTextureStorage1DWrapper(GL_TEXTURE_1D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth);
}
else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)
{
glTextureStorage3DWrapper(GL_TEXTURE_2D_ARRAY, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
}
else if (hostTexture->dim == Latte::E_DIM::DIM_3D)
{
glTextureStorage3DWrapper(GL_TEXTURE_3D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
}
else if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP)
{
glTextureStorage3DWrapper(GL_TEXTURE_CUBE_MAP_ARRAY, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth);
}
else
{
cemu_assert_unimplemented();
}
}

View file

@ -11,6 +11,8 @@ public:
~LatteTextureGL(); ~LatteTextureGL();
void AllocateOnHost() override;
static void GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget, bool createForTargetType); static void GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget, bool createForTargetType);
protected: protected:
@ -23,7 +25,6 @@ public:
sint32 glSuppliedFormat; sint32 glSuppliedFormat;
sint32 glSuppliedFormatType; sint32 glSuppliedFormatType;
bool glIsCompressed; bool glIsCompressed;
bool hasStencil{};
bool isUsingAlternativeFormat{}; bool isUsingAlternativeFormat{};
void setFormat(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType) void setFormat(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType)
@ -34,15 +35,6 @@ public:
this->glIsCompressed = false; this->glIsCompressed = false;
} }
void setDepthFormat(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType, bool hasStencil)
{
this->glInternalFormat = glInternalFormat;
this->glSuppliedFormat = glSuppliedFormat;
this->glSuppliedFormatType = glSuppliedFormatType;
this->glIsCompressed = false;
this->hasStencil = hasStencil;
}
void setCompressed(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType) void setCompressed(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType)
{ {
setFormat(glInternalFormat, glSuppliedFormat, glSuppliedFormatType); setFormat(glInternalFormat, glSuppliedFormat, glSuppliedFormatType);

View file

@ -55,12 +55,16 @@ LatteTextureViewGL::~LatteTextureViewGL()
void LatteTextureViewGL::InitAliasView() void LatteTextureViewGL::InitAliasView()
{ {
const auto texture = (LatteTextureGL*)baseTexture; const auto texture = (LatteTextureGL*)baseTexture;
// get internal format // compute internal format
if (baseTexture->isDepth) if(texture->overwriteInfo.hasFormatOverwrite)
{
cemu_assert_debug(format == texture->format);
glInternalFormat = texture->glInternalFormat; // for format overwrite no aliasing is allowed and thus we always inherit the internal format of the base texture
}
else if (baseTexture->isDepth)
{ {
// depth is handled differently // depth is handled differently
cemuLog_logDebug(LogType::Force, "Creating depth view"); cemu_assert(format == texture->format); // is depth alias with different format intended?
cemu_assert(format == texture->format); // todo
glInternalFormat = texture->glInternalFormat; glInternalFormat = texture->glInternalFormat;
} }
else else
@ -73,7 +77,7 @@ void LatteTextureViewGL::InitAliasView()
catchOpenGLError(); catchOpenGLError();
if (firstMip >= texture->maxPossibleMipLevels) if (firstMip >= texture->maxPossibleMipLevels)
{ {
cemuLog_logDebug(LogType::Force, "_createNewView: Out of bounds mip level requested"); cemuLog_logDebug(LogType::Force, "InitAliasView(): Out of bounds mip level requested");
glTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, texture->maxPossibleMipLevels - 1, numMip, firstSlice, this->numSlice); glTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, texture->maxPossibleMipLevels - 1, numMip, firstSlice, this->numSlice);
} }
else else

View file

@ -24,11 +24,14 @@
#define STRINGIFY2(X) #X #define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X) #define STRINGIFY(X) STRINGIFY2(X)
namespace CemuGL
{
#define GLFUNC(__type, __name) __type __name; #define GLFUNC(__type, __name) __type __name;
#define EGLFUNC(__type, __name) __type __name; #define EGLFUNC(__type, __name) __type __name;
#include "Common/GLInclude/glFunctions.h" #include "Common/GLInclude/glFunctions.h"
#undef GLFUNC #undef GLFUNC
#undef EGLFUNC #undef EGLFUNC
}
#include "config/ActiveSettings.h" #include "config/ActiveSettings.h"
#include "config/LaunchSettings.h" #include "config/LaunchSettings.h"
@ -241,6 +244,17 @@ void LoadOpenGLImports()
#undef GLFUNC #undef GLFUNC
#undef EGLFUNC #undef EGLFUNC
} }
#if BOOST_OS_LINUX
// dummy function for all code that is statically linked with cemu and attempts to use eglSwapInterval
// used to suppress wxWidgets calls to eglSwapInterval
extern "C"
EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval)
{
return EGL_TRUE;
}
#endif
#elif BOOST_OS_MACOS #elif BOOST_OS_MACOS
void LoadOpenGLImports() void LoadOpenGLImports()
{ {
@ -316,13 +330,14 @@ void OpenGLRenderer::Initialize()
lock.unlock(); lock.unlock();
// create framebuffer for fast clearing (avoid glClearTexSubImage on Nvidia) // create framebuffer for fast clearing (avoid glClearTexSubImage on Nvidia)
if (this->m_vendor == GfxVendor::Nvidia || glClearTexSubImage == nullptr) if (glCreateFramebuffers)
glCreateFramebuffers(1, &glRendererState.clearFBO);
else
{ {
// generate framebuffer glGenFramebuffers(1, &glRendererState.clearFBO);
if (glCreateFramebuffers && false) // bind to initialize
glCreateFramebuffers(1, &glRendererState.clearFBO); glBindFramebuffer(GL_FRAMEBUFFER_EXT, glRendererState.clearFBO);
else glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glGenFramebuffers(1, &glRendererState.clearFBO);
} }
draw_init(); draw_init();
@ -392,10 +407,7 @@ void OpenGLRenderer::GetVendorInformation()
} }
else if (memcmp(glVendorString, "Intel", 5) == 0) else if (memcmp(glVendorString, "Intel", 5) == 0)
{ {
if (LaunchSettings::ForceIntelLegacyEnabled()) m_vendor = GfxVendor::Intel;
m_vendor = GfxVendor::IntelLegacy;
else
m_vendor = GfxVendor::IntelNoLegacy;
return; return;
} }
} }
@ -411,9 +423,12 @@ void _glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GL
return; return;
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "Dithering is enabled")) if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "Dithering is enabled"))
return; return;
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "Blending is enabled, but is not supported for integer framebuffers"))
return;
if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "does not have a defined base level")) if (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "does not have a defined base level"))
return; return;
if(LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, "has depth comparisons disabled, with a texture object"))
return;
cemuLog_log(LogType::Force, "GLDEBUG: {}", message); cemuLog_log(LogType::Force, "GLDEBUG: {}", message);
@ -555,10 +570,8 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
g_renderer->ClearColorbuffer(padView); g_renderer->ClearColorbuffer(padView);
} }
// calculate effective size sint32 effectiveWidth, effectiveHeight;
sint32 effectiveWidth; texView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0);
sint32 effectiveHeight;
LatteTexture_getEffectiveSize(texView->baseTexture, &effectiveWidth, &effectiveHeight, nullptr, 0);
shader_unbind(RendererShader::ShaderType::kGeometry); shader_unbind(RendererShader::ShaderType::kGeometry);
shader_bind(shader->GetVertexShader()); shader_bind(shader->GetVertexShader());
@ -658,7 +671,10 @@ void OpenGLRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo)
{ {
auto cfboGL = (CachedFBOGL*)cfbo; auto cfboGL = (CachedFBOGL*)cfbo;
if (prevBoundFBO == cfboGL->glId_fbo) if (prevBoundFBO == cfboGL->glId_fbo)
prevBoundFBO = -1; {
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
prevBoundFBO = 0;
}
glDeleteFramebuffers(1, &cfboGL->glId_fbo); glDeleteFramebuffers(1, &cfboGL->glId_fbo);
} }
@ -830,45 +846,6 @@ TextureDecoder* OpenGLRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT
} }
return nullptr; return nullptr;
} }
if (LatteGPUState.glVendor == GLVENDOR_INTEL_LEGACY)
{
if (format == Latte::E_GX2SURFFMT::BC1_UNORM)
{
texDecoder = TextureDecoder_BC1_UNORM_uncompress::getInstance();
}
else if (format == Latte::E_GX2SURFFMT::BC1_SRGB)
{
texDecoder = TextureDecoder_BC1_SRGB_uncompress::getInstance();
}
else if (format == Latte::E_GX2SURFFMT::BC3_UNORM)
{
texDecoder = TextureDecoder_BC3_UNORM_uncompress::getInstance();
}
else if (format == Latte::E_GX2SURFFMT::BC3_SRGB)
{
texDecoder = TextureDecoder_BC3_SRGB_uncompress::getInstance();
}
else if (format == Latte::E_GX2SURFFMT::BC4_UNORM)
{
texDecoder = TextureDecoder_BC4_UNORM_uncompress::getInstance();
}
else if (format == Latte::E_GX2SURFFMT::BC4_SNORM)
{
cemu_assert_debug(false); // todo
}
else if (format == Latte::E_GX2SURFFMT::BC5_UNORM)
{
texDecoder = TextureDecoder_BC5_UNORM_uncompress::getInstance();
}
else if (format == Latte::E_GX2SURFFMT::BC5_SNORM)
{
texDecoder = TextureDecoder_BC5_SNORM_uncompress::getInstance();
}
if (texDecoder)
return texDecoder;
}
if (format == Latte::E_GX2SURFFMT::R4_G4_UNORM) if (format == Latte::E_GX2SURFFMT::R4_G4_UNORM)
texDecoder = TextureDecoder_R4_G4_UNORM_To_RGBA4::getInstance(); texDecoder = TextureDecoder_R4_G4_UNORM_To_RGBA4::getInstance();
else if (format == Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM) else if (format == Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM)
@ -983,60 +960,6 @@ TextureDecoder* OpenGLRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT
return texDecoder; return texDecoder;
} }
void OpenGLRenderer::texture_destroy(LatteTexture* hostTexture)
{
delete hostTexture;
}
void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTextureGeneric)
{
auto hostTexture = (LatteTextureGL*)hostTextureGeneric;
cemu_assert_debug(hostTexture->isDataDefined == false);
sint32 effectiveBaseWidth = hostTexture->width;
sint32 effectiveBaseHeight = hostTexture->height;
sint32 effectiveBaseDepth = hostTexture->depth;
if (hostTexture->overwriteInfo.hasResolutionOverwrite)
{
effectiveBaseWidth = hostTexture->overwriteInfo.width;
effectiveBaseHeight = hostTexture->overwriteInfo.height;
effectiveBaseDepth = hostTexture->overwriteInfo.depth;
}
// get format info
LatteTextureGL::FormatInfoGL glFormatInfo;
LatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)hostTexture->overwriteInfo.format : hostTexture->format, hostTexture->dim, &glFormatInfo);
// calculate mip count
sint32 mipLevels = std::min(hostTexture->mipLevels, hostTexture->maxPossibleMipLevels);
mipLevels = std::max(mipLevels, 1);
// create immutable storage
if (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA)
{
cemu_assert_debug(effectiveBaseDepth == 1);
glTextureStorage2DWrapper(GL_TEXTURE_2D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight);
}
else if (hostTexture->dim == Latte::E_DIM::DIM_1D)
{
cemu_assert_debug(effectiveBaseHeight == 1);
cemu_assert_debug(effectiveBaseDepth == 1);
glTextureStorage1DWrapper(GL_TEXTURE_1D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth);
}
else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)
{
glTextureStorage3DWrapper(GL_TEXTURE_2D_ARRAY, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
}
else if (hostTexture->dim == Latte::E_DIM::DIM_3D)
{
glTextureStorage3DWrapper(GL_TEXTURE_3D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));
}
else if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP)
{
glTextureStorage3DWrapper(GL_TEXTURE_CUBE_MAP_ARRAY, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth);
}
else
{
cemu_assert_unimplemented();
}
}
// use standard API to upload texture data // use standard API to upload texture data
void OpenGLRenderer_texture_loadSlice_normal(LatteTexture* hostTextureGeneric, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize) void OpenGLRenderer_texture_loadSlice_normal(LatteTexture* hostTextureGeneric, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize)
{ {
@ -1113,8 +1036,8 @@ void OpenGLRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 s
LatteTextureGL* texGL = (LatteTextureGL*)hostTexture; LatteTextureGL* texGL = (LatteTextureGL*)hostTexture;
cemu_assert_debug(!texGL->isDepth); cemu_assert_debug(!texGL->isDepth);
sint32 eWidth, eHeight, eDepth; sint32 eWidth, eHeight;
LatteTexture_getEffectiveSize(hostTexture, &eWidth, &eHeight, &eDepth, mipIndex); hostTexture->GetEffectiveSize(eWidth, eHeight, mipIndex);
renderstate_resetColorControl(); renderstate_resetColorControl();
renderTarget_setViewport(0, 0, eWidth, eHeight, 0.0f, 1.0f); renderTarget_setViewport(0, 0, eWidth, eHeight, 0.0f, 1.0f);
LatteMRT::BindColorBufferOnly(hostTexture->GetOrCreateView(mipIndex, 1, sliceIndex, 1)); LatteMRT::BindColorBufferOnly(hostTexture->GetOrCreateView(mipIndex, 1, sliceIndex, 1));
@ -1127,8 +1050,8 @@ void OpenGLRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 s
LatteTextureGL* texGL = (LatteTextureGL*)hostTexture; LatteTextureGL* texGL = (LatteTextureGL*)hostTexture;
cemu_assert_debug(texGL->isDepth); cemu_assert_debug(texGL->isDepth);
sint32 eWidth, eHeight, eDepth; sint32 eWidth, eHeight;
LatteTexture_getEffectiveSize(hostTexture, &eWidth, &eHeight, &eDepth, mipIndex); hostTexture->GetEffectiveSize(eWidth, eHeight, mipIndex);
renderstate_resetColorControl(); renderstate_resetColorControl();
renderstate_resetDepthControl(); renderstate_resetDepthControl();
renderTarget_setViewport(0, 0, eWidth, eHeight, 0.0f, 1.0f); renderTarget_setViewport(0, 0, eWidth, eHeight, 0.0f, 1.0f);
@ -1156,13 +1079,12 @@ void OpenGLRenderer::texture_clearSlice(LatteTexture* hostTextureGeneric, sint32
LatteTextureGL::FormatInfoGL formatInfoGL; LatteTextureGL::FormatInfoGL formatInfoGL;
LatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->format, hostTexture->dim, &formatInfoGL); LatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->format, hostTexture->dim, &formatInfoGL);
// get effective size of mip // get effective size of mip
sint32 effectiveWidth; sint32 effectiveWidth, effectiveHeight;
sint32 effectiveHeight; hostTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, mipIndex);
LatteTexture_getEffectiveSize(hostTexture, &effectiveWidth, &effectiveHeight, nullptr, mipIndex);
// on Nvidia glClearTexImage and glClearTexSubImage has bad performance (clearing a 4K texture takes up to 50ms) // on Nvidia glClearTexImage and glClearTexSubImage has bad performance (clearing a 4K texture takes up to 50ms)
// clearing with glTextureSubImage2D from a CPU RAM buffer is only slightly slower // clearing with glTextureSubImage2D from a CPU RAM buffer is only slightly slower
// clearing with glTextureSubImage2D from a OpenGL buffer is 10-20% faster than glClearTexImage) // clearing with glTextureSubImage2D from a OpenGL buffer is 10-20% faster than glClearTexImage
// clearing with FBO and glClear is orders of magnitude faster than the other methods // clearing with FBO and glClear is orders of magnitude faster than the other methods
// (these are results from 2018, may be different now) // (these are results from 2018, may be different now)
@ -1193,7 +1115,6 @@ void OpenGLRenderer::texture_clearSlice(LatteTexture* hostTextureGeneric, sint32
} }
if (glClearTexSubImage == nullptr) if (glClearTexSubImage == nullptr)
return; return;
// clear
glClearTexSubImage(hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, formatInfoGL.glSuppliedFormat, formatInfoGL.glSuppliedFormatType, NULL); glClearTexSubImage(hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, formatInfoGL.glSuppliedFormat, formatInfoGL.glSuppliedFormatType, NULL);
} }
@ -1201,7 +1122,6 @@ LatteTexture* OpenGLRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR phy
uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth)
{ {
return new LatteTextureGL(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); return new LatteTextureGL(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth);
} }
void OpenGLRenderer::texture_setActiveTextureUnit(sint32 index) void OpenGLRenderer::texture_setActiveTextureUnit(sint32 index)
@ -1270,7 +1190,6 @@ void OpenGLRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip,
{ {
auto srcGL = (LatteTextureGL*)src; auto srcGL = (LatteTextureGL*)src;
auto dstGL = (LatteTextureGL*)dst; auto dstGL = (LatteTextureGL*)dst;
if ((srcGL->isAlternativeFormat || dstGL->isAlternativeFormat) && (srcGL->glInternalFormat != dstGL->glInternalFormat)) if ((srcGL->isAlternativeFormat || dstGL->isAlternativeFormat) && (srcGL->glInternalFormat != dstGL->glInternalFormat))
{ {
if (srcGL->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT && dstGL->format == Latte::E_GX2SURFFMT::BC4_UNORM) if (srcGL->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT && dstGL->format == Latte::E_GX2SURFFMT::BC4_UNORM)

View file

@ -66,14 +66,11 @@ public:
void renderstate_updateTextureSettingsGL(LatteDecompilerShader* shaderContext, LatteTextureView* _hostTextureView, uint32 hostTextureUnit, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N texUnitWord4, uint32 texUnitIndex, bool isDepthSampler); void renderstate_updateTextureSettingsGL(LatteDecompilerShader* shaderContext, LatteTextureView* _hostTextureView, uint32 hostTextureUnit, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N texUnitWord4, uint32 texUnitIndex, bool isDepthSampler);
// texture functions // texture functions
void texture_destroy(LatteTexture* hostTexture) override;
void* texture_acquireTextureUploadBuffer(uint32 size) override; void* texture_acquireTextureUploadBuffer(uint32 size) override;
void texture_releaseTextureUploadBuffer(uint8* mem) override; void texture_releaseTextureUploadBuffer(uint8* mem) override;
TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override; TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;
void texture_reserveTextureOnGPU(LatteTexture* hostTexture) override;
void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override; void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;
void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override; void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override;
void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override; void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;
@ -195,7 +192,7 @@ private:
GLuint glStreamoutCacheRingBuffer; GLuint glStreamoutCacheRingBuffer;
// cfbo // cfbo
GLuint prevBoundFBO = -1; GLuint prevBoundFBO = 0;
GLuint glId_fbo = 0; GLuint glId_fbo = 0;
// renderstate // renderstate

View file

@ -950,7 +950,7 @@ void OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInsta
bool streamoutEnable = LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0; bool streamoutEnable = LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0;
if (streamoutEnable) if (streamoutEnable)
{ {
if (glBeginTransformFeedback == nullptr || LatteGPUState.glVendor == GLVENDOR_INTEL_NOLEGACY) if (glBeginTransformFeedback == nullptr)
{ {
cemu_assert_debug(false); cemu_assert_debug(false);
return; // transform feedback not supported return; // transform feedback not supported

View file

@ -30,9 +30,8 @@ void OpenGLRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* s
sint32 effectiveCopyWidth = width; sint32 effectiveCopyWidth = width;
sint32 effectiveCopyHeight = height; sint32 effectiveCopyHeight = height;
LatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0); LatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);
sint32 sourceEffectiveWidth; sint32 sourceEffectiveWidth, sourceEffectiveHeight;
sint32 sourceEffectiveHeight; sourceTexture->GetEffectiveSize(sourceEffectiveWidth, sourceEffectiveHeight, srcMip);
LatteTexture_getEffectiveSize(sourceTexture, &sourceEffectiveWidth, &sourceEffectiveHeight, nullptr, srcMip);
// reset everything // reset everything
renderstate_resetColorControl(); renderstate_resetColorControl();
renderstate_resetDepthControl(); renderstate_resetDepthControl();

View file

@ -21,8 +21,6 @@ enum class GfxVendor
Generic, Generic,
AMD, AMD,
IntelLegacy,
IntelNoLegacy,
Intel, Intel,
Nvidia, Nvidia,
Apple, Apple,
@ -97,14 +95,11 @@ public:
virtual void rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) = 0; virtual void rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) = 0;
// texture functions // texture functions
virtual void texture_destroy(LatteTexture* hostTexture) = 0;
virtual void* texture_acquireTextureUploadBuffer(uint32 size) = 0; virtual void* texture_acquireTextureUploadBuffer(uint32 size) = 0;
virtual void texture_releaseTextureUploadBuffer(uint8* mem) = 0; virtual void texture_releaseTextureUploadBuffer(uint8* mem) = 0;
virtual TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) = 0; virtual TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) = 0;
virtual void texture_reserveTextureOnGPU(LatteTexture* hostTexture) = 0;
virtual void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) = 0; virtual void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) = 0;
virtual void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) = 0; virtual void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) = 0;
virtual void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) = 0; virtual void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) = 0;

View file

@ -44,9 +44,9 @@ CachedFBOVk::~CachedFBOVk()
while (!m_usedByPipelines.empty()) while (!m_usedByPipelines.empty())
delete m_usedByPipelines[0]; delete m_usedByPipelines[0];
auto vkr = VulkanRenderer::GetInstance(); auto vkr = VulkanRenderer::GetInstance();
vkr->releaseDestructibleObject(m_vkrObjFramebuffer); vkr->ReleaseDestructibleObject(m_vkrObjFramebuffer);
m_vkrObjFramebuffer = nullptr; m_vkrObjFramebuffer = nullptr;
vkr->releaseDestructibleObject(m_vkrObjRenderPass); vkr->ReleaseDestructibleObject(m_vkrObjRenderPass);
m_vkrObjRenderPass = nullptr; m_vkrObjRenderPass = nullptr;
} }

View file

@ -57,7 +57,12 @@ uint32 LatteTextureVk_AdjustTextureCompSel(Latte::E_GX2SURFFMT format, uint32 co
LatteTextureViewVk::LatteTextureViewVk(VkDevice device, LatteTextureVk* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) LatteTextureViewVk::LatteTextureViewVk(VkDevice device, LatteTextureVk* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_device(device) : LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_device(device)
{ {
if (dim != texture->dim || format != texture->format) if(texture->overwriteInfo.hasFormatOverwrite)
{
cemu_assert_debug(format == texture->format); // if format overwrite is used, the texture is no longer taking part in aliasing and the format of any view has to match
m_format = texture->GetFormat();
}
else if (dim != texture->dim || format != texture->format)
{ {
VulkanRenderer::FormatInfoVK texFormatInfo; VulkanRenderer::FormatInfoVK texFormatInfo;
VulkanRenderer::GetInstance()->GetTextureFormatInfoVK(format, texture->isDepth, dim, 0, 0, &texFormatInfo); VulkanRenderer::GetInstance()->GetTextureFormatInfoVK(format, texture->isDepth, dim, 0, 0, &texFormatInfo);
@ -74,14 +79,14 @@ LatteTextureViewVk::~LatteTextureViewVk()
delete list_descriptorSets[0]; delete list_descriptorSets[0];
if (m_smallCacheView0) if (m_smallCacheView0)
VulkanRenderer::GetInstance()->releaseDestructibleObject(m_smallCacheView0); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_smallCacheView0);
if (m_smallCacheView1) if (m_smallCacheView1)
VulkanRenderer::GetInstance()->releaseDestructibleObject(m_smallCacheView1); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_smallCacheView1);
if (m_fallbackCache) if (m_fallbackCache)
{ {
for (auto& itr : *m_fallbackCache) for (auto& itr : *m_fallbackCache)
VulkanRenderer::GetInstance()->releaseDestructibleObject(itr.second); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(itr.second);
delete m_fallbackCache; delete m_fallbackCache;
m_fallbackCache = nullptr; m_fallbackCache = nullptr;
} }

View file

@ -46,7 +46,7 @@ LatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM di
VulkanRenderer::FormatInfoVK texFormatInfo; VulkanRenderer::FormatInfoVK texFormatInfo;
vkRenderer->GetTextureFormatInfoVK(format, isDepth, dim, effectiveBaseWidth, effectiveBaseHeight, &texFormatInfo); vkRenderer->GetTextureFormatInfoVK(format, isDepth, dim, effectiveBaseWidth, effectiveBaseHeight, &texFormatInfo);
hasStencil = (texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; cemu_assert_debug(hasStencil == ((texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0));
imageInfo.format = texFormatInfo.vkImageFormat; imageInfo.format = texFormatInfo.vkImageFormat;
vkObjTex->m_imageAspect = texFormatInfo.vkImageAspect; vkObjTex->m_imageAspect = texFormatInfo.vkImageAspect;
@ -117,7 +117,7 @@ LatteTextureVk::~LatteTextureVk()
m_vkr->surfaceCopy_notifyTextureRelease(this); m_vkr->surfaceCopy_notifyTextureRelease(this);
VulkanRenderer::GetInstance()->releaseDestructibleObject(vkObjTex); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(vkObjTex);
vkObjTex = nullptr; vkObjTex = nullptr;
} }
@ -130,12 +130,8 @@ LatteTextureView* LatteTextureVk::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFF
return new LatteTextureViewVk(m_vkr->GetLogicalDevice(), this, dim, format, firstMip, mipCount, firstSlice, sliceCount); return new LatteTextureViewVk(m_vkr->GetLogicalDevice(), this, dim, format, firstMip, mipCount, firstSlice, sliceCount);
} }
void LatteTextureVk::setAllocation(struct VkImageMemAllocation* memAllocation) void LatteTextureVk::AllocateOnHost()
{ {
vkObjTex->m_allocation = memAllocation; auto allocationInfo = VulkanRenderer::GetInstance()->GetMemoryManager()->imageMemoryAllocate(GetImageObj()->m_image);
} vkObjTex->m_allocation = allocationInfo;
struct VkImageMemAllocation* LatteTextureVk::getAllocation() const
{
return vkObjTex->m_allocation;
} }

View file

@ -14,14 +14,13 @@ public:
~LatteTextureVk(); ~LatteTextureVk();
void AllocateOnHost() override;
VKRObjectTexture* GetImageObj() const { return vkObjTex; }; VKRObjectTexture* GetImageObj() const { return vkObjTex; };
VkFormat GetFormat() const { return vkObjTex->m_format; } VkFormat GetFormat() const { return vkObjTex->m_format; }
VkImageAspectFlags GetImageAspect() const { return vkObjTex->m_imageAspect; } VkImageAspectFlags GetImageAspect() const { return vkObjTex->m_imageAspect; }
void setAllocation(struct VkImageMemAllocation* memAllocation);
struct VkImageMemAllocation* getAllocation() const;
VkImageLayout GetImageLayout(VkImageSubresource& subresource) VkImageLayout GetImageLayout(VkImageSubresource& subresource)
{ {
cemu_assert_debug(subresource.mipLevel < m_layoutsMips); cemu_assert_debug(subresource.mipLevel < m_layoutsMips);

View file

@ -8,6 +8,7 @@
#include <glslang/Public/ShaderLang.h> #include <glslang/Public/ShaderLang.h>
#include <glslang/SPIRV/GlslangToSpv.h> #include <glslang/SPIRV/GlslangToSpv.h>
#include <util/helpers/helpers.h>
bool s_isLoadingShadersVk{ false }; bool s_isLoadingShadersVk{ false };
class FileCache* s_spirvCache{nullptr}; class FileCache* s_spirvCache{nullptr};
@ -129,19 +130,18 @@ class _ShaderVkThreadPool
public: public:
void StartThreads() void StartThreads()
{ {
if (s_threads.empty()) if (m_threadsActive.exchange(true))
{ return;
// create thread pool // create thread pool
m_shutdownThread.store(false); const uint32 threadCount = 2;
const uint32 threadCount = 2; for (uint32 i = 0; i < threadCount; ++i)
for (uint32 i = 0; i < threadCount; ++i) s_threads.emplace_back(&_ShaderVkThreadPool::CompilerThreadFunc, this);
s_threads.emplace_back(&_ShaderVkThreadPool::CompilerThreadFunc, this);
}
} }
void StopThreads() void StopThreads()
{ {
m_shutdownThread.store(true); if (!m_threadsActive.exchange(false))
return;
for (uint32 i = 0; i < s_threads.size(); ++i) for (uint32 i = 0; i < s_threads.size(); ++i)
s_compilationQueueCount.increment(); s_compilationQueueCount.increment();
for (auto& it : s_threads) for (auto& it : s_threads)
@ -156,7 +156,8 @@ public:
void CompilerThreadFunc() void CompilerThreadFunc()
{ {
while (!m_shutdownThread.load(std::memory_order::relaxed)) SetThreadName("vkShaderComp");
while (m_threadsActive.load(std::memory_order::relaxed))
{ {
s_compilationQueueCount.decrementWithWait(); s_compilationQueueCount.decrementWithWait();
s_compilationQueueMutex.lock(); s_compilationQueueMutex.lock();
@ -181,7 +182,7 @@ public:
} }
} }
bool HasThreadsRunning() const { return !m_shutdownThread; } bool HasThreadsRunning() const { return m_threadsActive; }
public: public:
std::vector<std::thread> s_threads; std::vector<std::thread> s_threads;
@ -191,7 +192,7 @@ public:
std::mutex s_compilationQueueMutex; std::mutex s_compilationQueueMutex;
private: private:
std::atomic<bool> m_shutdownThread; std::atomic<bool> m_threadsActive;
}ShaderVkThreadPool; }ShaderVkThreadPool;
RendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode) RendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode)
@ -208,7 +209,8 @@ RendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxH
RendererShaderVk::~RendererShaderVk() RendererShaderVk::~RendererShaderVk()
{ {
VulkanRenderer::GetInstance()->destroyShader(this); while (!list_pipelineInfo.empty())
delete list_pipelineInfo[0];
} }
void RendererShaderVk::Init() void RendererShaderVk::Init()

View file

@ -84,7 +84,7 @@ PipelineInfo::~PipelineInfo()
// queue pipeline for destruction // queue pipeline for destruction
if (m_vkrObjPipeline) if (m_vkrObjPipeline)
{ {
VulkanRenderer::GetInstance()->releaseDestructibleObject(m_vkrObjPipeline); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_vkrObjPipeline);
m_vkrObjPipeline = nullptr; m_vkrObjPipeline = nullptr;
} }

View file

@ -300,7 +300,7 @@ void VulkanPipelineStableCache::LoadPipelineFromCache(std::span<uint8> fileData)
delete pipelineInfo; delete pipelineInfo;
delete lcr; delete lcr;
delete cachedPipeline; delete cachedPipeline;
VulkanRenderer::GetInstance()->releaseDestructibleObject(renderPass); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(renderPass);
s_spinlockSharedInternal.unlock(); s_spinlockSharedInternal.unlock();
} }
@ -408,6 +408,7 @@ bool VulkanPipelineStableCache::DeserializePipeline(MemStreamReader& memReader,
int VulkanPipelineStableCache::CompilerThread() int VulkanPipelineStableCache::CompilerThread()
{ {
SetThreadName("plCacheCompiler");
while (m_numCompilationThreads != 0) while (m_numCompilationThreads != 0)
{ {
std::vector<uint8> pipelineData = m_compilationQueue.pop(); std::vector<uint8> pipelineData = m_compilationQueue.pop();
@ -421,6 +422,7 @@ int VulkanPipelineStableCache::CompilerThread()
void VulkanPipelineStableCache::WorkerThread() void VulkanPipelineStableCache::WorkerThread()
{ {
SetThreadName("plCacheWriter");
while (true) while (true)
{ {
CachedPipeline* job; CachedPipeline* job;

View file

@ -531,7 +531,6 @@ VulkanRenderer::VulkanRenderer()
QueryMemoryInfo(); QueryMemoryInfo();
QueryAvailableFormats(); QueryAvailableFormats();
CreateBackbufferIndexBuffer();
CreateCommandPool(); CreateCommandPool();
CreateCommandBuffers(); CreateCommandBuffers();
CreateDescriptorPool(); CreateDescriptorPool();
@ -578,20 +577,6 @@ VulkanRenderer::VulkanRenderer()
for (sint32 i = 0; i < OCCLUSION_QUERY_POOL_SIZE; i++) for (sint32 i = 0; i < OCCLUSION_QUERY_POOL_SIZE; i++)
m_occlusionQueries.list_availableQueryIndices.emplace_back(i); m_occlusionQueries.list_availableQueryIndices.emplace_back(i);
// enable surface copies via buffer if we have plenty of memory available (otherwise use drawcalls)
size_t availableSurfaceCopyBufferMem = memoryManager->GetTotalMemoryForBufferType(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
//m_featureControl.mode.useBufferSurfaceCopies = availableSurfaceCopyBufferMem >= 2000ull * 1024ull * 1024ull; // enable if at least 2000MB VRAM
m_featureControl.mode.useBufferSurfaceCopies = false;
if (m_featureControl.mode.useBufferSurfaceCopies)
{
//cemuLog_log(LogType::Force, "Enable surface copies via buffer");
}
else
{
//cemuLog_log(LogType::Force, "Disable surface copies via buffer (Requires 2GB. Has only {}MB available)", availableSurfaceCopyBufferMem / 1024ull / 1024ull);
}
// start compilation threads // start compilation threads
RendererShaderVk::Init(); RendererShaderVk::Init();
} }
@ -601,7 +586,7 @@ VulkanRenderer::~VulkanRenderer()
SubmitCommandBuffer(); SubmitCommandBuffer();
WaitDeviceIdle(); WaitDeviceIdle();
WaitCommandBufferFinished(GetCurrentCommandBufferId()); WaitCommandBufferFinished(GetCurrentCommandBufferId());
// shut down compilation threads // make sure compilation threads have been shut down
RendererShaderVk::Shutdown(); RendererShaderVk::Shutdown();
// shut down pipeline save thread // shut down pipeline save thread
m_destructionRequested = true; m_destructionRequested = true;
@ -615,7 +600,6 @@ VulkanRenderer::~VulkanRenderer()
DeleteNullObjects(); DeleteNullObjects();
// delete buffers // delete buffers
memoryManager->DeleteBuffer(m_indexBuffer, m_indexBufferMemory);
memoryManager->DeleteBuffer(m_uniformVarBuffer, m_uniformVarBufferMemory); memoryManager->DeleteBuffer(m_uniformVarBuffer, m_uniformVarBufferMemory);
memoryManager->DeleteBuffer(m_textureReadbackBuffer, m_textureReadbackBufferMemory); memoryManager->DeleteBuffer(m_textureReadbackBuffer, m_textureReadbackBufferMemory);
memoryManager->DeleteBuffer(m_xfbRingBuffer, m_xfbRingBufferMemory); memoryManager->DeleteBuffer(m_xfbRingBuffer, m_xfbRingBufferMemory);
@ -766,7 +750,7 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad
//dumpImage->flagForCurrentCommandBuffer(); //dumpImage->flagForCurrentCommandBuffer();
int width, height; int width, height;
LatteTexture_getEffectiveSize(baseImageTex, &width, &height, nullptr, 0); baseImageTex->GetEffectiveSize(width, height, 0);
VkImage image = nullptr; VkImage image = nullptr;
VkDeviceMemory imageMemory = nullptr;; VkDeviceMemory imageMemory = nullptr;;
@ -1405,8 +1389,7 @@ bool VulkanRenderer::IsSwapchainInfoValid(bool mainWindow) const
void VulkanRenderer::CreateNullTexture(NullTexture& nullTex, VkImageType imageType) void VulkanRenderer::CreateNullTexture(NullTexture& nullTex, VkImageType imageType)
{ {
// these are used when the game requests NULL ptr textures or buffers // these are used when the game requests NULL ptr textures
// texture
VkImageCreateInfo imageInfo{}; VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
if (imageType == VK_IMAGE_TYPE_1D) if (imageType == VK_IMAGE_TYPE_1D)
@ -1561,12 +1544,12 @@ void VulkanRenderer::Shutdown()
Renderer::Shutdown(); Renderer::Shutdown();
SubmitCommandBuffer(); SubmitCommandBuffer();
WaitDeviceIdle(); WaitDeviceIdle();
if (m_imguiRenderPass != VK_NULL_HANDLE) if (m_imguiRenderPass != VK_NULL_HANDLE)
{ {
vkDestroyRenderPass(m_logicalDevice, m_imguiRenderPass, nullptr); vkDestroyRenderPass(m_logicalDevice, m_imguiRenderPass, nullptr);
m_imguiRenderPass = VK_NULL_HANDLE; m_imguiRenderPass = VK_NULL_HANDLE;
} }
RendererShaderVk::Shutdown();
} }
void VulkanRenderer::UnrecoverableError(const char* errMsg) const void VulkanRenderer::UnrecoverableError(const char* errMsg) const
@ -1820,44 +1803,6 @@ void VulkanRenderer::PreparePresentationFrame(bool mainWindow)
AcquireNextSwapchainImage(mainWindow); AcquireNextSwapchainImage(mainWindow);
} }
void VulkanRenderer::ProcessDestructionQueues(size_t commandBufferIndex)
{
auto& current_descriptor_cache = m_destructionQueues.m_cmd_descriptor_set_objects[commandBufferIndex];
if (!current_descriptor_cache.empty())
{
assert_dbg();
//for (const auto& descriptor : current_descriptor_cache)
//{
// vkFreeDescriptorSets(m_logicalDevice, m_descriptorPool, 1, &descriptor);
// performanceMonitor.vk.numDescriptorSets.decrement();
//}
current_descriptor_cache.clear();
}
// destroy buffers
for (auto& itr : m_destructionQueues.m_buffers[commandBufferIndex])
vkDestroyBuffer(m_logicalDevice, itr, nullptr);
m_destructionQueues.m_buffers[commandBufferIndex].clear();
// destroy device memory objects
for (auto& itr : m_destructionQueues.m_memory[commandBufferIndex])
vkFreeMemory(m_logicalDevice, itr, nullptr);
m_destructionQueues.m_memory[commandBufferIndex].clear();
// destroy image views
for (auto& itr : m_destructionQueues.m_cmd_image_views[commandBufferIndex])
vkDestroyImageView(m_logicalDevice, itr, nullptr);
m_destructionQueues.m_cmd_image_views[commandBufferIndex].clear();
// destroy host textures
for (auto itr : m_destructionQueues.m_host_textures[commandBufferIndex])
delete itr;
m_destructionQueues.m_host_textures[commandBufferIndex].clear();
ProcessDestructionQueue2();
}
void VulkanRenderer::InitFirstCommandBuffer() void VulkanRenderer::InitFirstCommandBuffer()
{ {
cemu_assert_debug(m_state.currentCommandBuffer == nullptr); cemu_assert_debug(m_state.currentCommandBuffer == nullptr);
@ -1886,7 +1831,7 @@ void VulkanRenderer::ProcessFinishedCommandBuffers()
VkResult fenceStatus = vkGetFenceStatus(m_logicalDevice, m_cmd_buffer_fences[m_commandBufferSyncIndex]); VkResult fenceStatus = vkGetFenceStatus(m_logicalDevice, m_cmd_buffer_fences[m_commandBufferSyncIndex]);
if (fenceStatus == VK_SUCCESS) if (fenceStatus == VK_SUCCESS)
{ {
ProcessDestructionQueues(m_commandBufferSyncIndex); ProcessDestructionQueue();
m_commandBufferSyncIndex = (m_commandBufferSyncIndex + 1) % m_commandBuffers.size(); m_commandBufferSyncIndex = (m_commandBufferSyncIndex + 1) % m_commandBuffers.size();
memoryManager->cleanupBuffers(m_countCommandBufferFinished); memoryManager->cleanupBuffers(m_countCommandBufferFinished);
m_countCommandBufferFinished++; m_countCommandBufferFinished++;
@ -2041,6 +1986,7 @@ void VulkanRenderer::WaitCommandBufferFinished(uint64 commandBufferId)
void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size)
{ {
SetThreadName("vkDriverPlCache");
const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk");
if (!fs::exists(dir)) if (!fs::exists(dir))
{ {
@ -2811,6 +2757,35 @@ void VulkanRenderer::ClearColorImageRaw(VkImage image, uint32 sliceIndex, uint32
void VulkanRenderer::ClearColorImage(LatteTextureVk* vkTexture, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout outputLayout) void VulkanRenderer::ClearColorImage(LatteTextureVk* vkTexture, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout outputLayout)
{ {
if(vkTexture->isDepth)
{
cemu_assert_suspicious();
return;
}
if (vkTexture->IsCompressedFormat())
{
// vkCmdClearColorImage cannot be called on compressed formats
// for now we ignore affected clears but still transition the image to the correct layout
auto imageObj = vkTexture->GetImageObj();
imageObj->flagForCurrentCommandBuffer();
VkImageSubresourceLayers subresourceRange{};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.mipLevel = mipIndex;
subresourceRange.baseArrayLayer = sliceIndex;
subresourceRange.layerCount = 1;
barrier_image<ANY_TRANSFER | IMAGE_READ, ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE>(vkTexture, subresourceRange, outputLayout);
if(color.float32[0] == 0.0f && color.float32[1] == 0.0f && color.float32[2] == 0.0f && color.float32[3] == 0.0f)
{
static bool dbgMsgPrinted = false;
if(!dbgMsgPrinted)
{
cemuLog_logDebug(LogType::Force, "Unsupported compressed texture clear to zero");
dbgMsgPrinted = true;
}
}
return;
}
VkImageSubresourceRange subresourceRange; VkImageSubresourceRange subresourceRange;
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -2827,18 +2802,6 @@ void VulkanRenderer::ClearColorImage(LatteTextureVk* vkTexture, uint32 sliceInde
vkTexture->SetImageLayout(subresourceRange, outputLayout); vkTexture->SetImageLayout(subresourceRange, outputLayout);
} }
void VulkanRenderer::CreateBackbufferIndexBuffer()
{
const VkDeviceSize bufferSize = sizeof(uint16) * 6;
memoryManager->CreateBuffer(bufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, m_indexBuffer, m_indexBufferMemory);
uint16* data;
vkMapMemory(m_logicalDevice, m_indexBufferMemory, 0, bufferSize, 0, (void**)&data);
const uint16 tmp[] = { 0, 1, 2, 3, 4, 5 };
std::copy(std::begin(tmp), std::end(tmp), data);
vkUnmapMemory(m_logicalDevice, m_indexBufferMemory);
}
void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground) void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground)
{ {
if(!AcquireNextSwapchainImage(!padView)) if(!AcquireNextSwapchainImage(!padView))
@ -2890,11 +2853,9 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
vkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
m_state.currentPipeline = pipeline; m_state.currentPipeline = pipeline;
vkCmdBindIndexBuffer(m_state.currentCommandBuffer, m_indexBuffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &descriptSet, 0, nullptr); vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &descriptSet, 0, nullptr);
vkCmdDrawIndexed(m_state.currentCommandBuffer, 6, 1, 0, 0, 0); vkCmdDraw(m_state.currentCommandBuffer, 6, 1, 0, 0);
vkCmdEndRenderPass(m_state.currentCommandBuffer); vkCmdEndRenderPass(m_state.currentCommandBuffer);
@ -3037,48 +2998,7 @@ TextureDecoder* VulkanRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT
return texFormatInfo.decoder; return texFormatInfo.decoder;
} }
void VulkanRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTexture) void VulkanRenderer::ReleaseDestructibleObject(VKRDestructibleObject* destructibleObject)
{
LatteTextureVk* vkTexture = (LatteTextureVk*)hostTexture;
auto allocationInfo = memoryManager->imageMemoryAllocate(vkTexture->GetImageObj()->m_image);
vkTexture->setAllocation(allocationInfo);
}
void VulkanRenderer::texture_destroy(LatteTexture* hostTexture)
{
LatteTextureVk* texVk = (LatteTextureVk*)hostTexture;
delete texVk;
}
void VulkanRenderer::destroyViewDepr(VkImageView imageView)
{
cemu_assert_debug(false);
m_destructionQueues.m_cmd_image_views[m_commandBufferIndex].emplace_back(imageView);
}
void VulkanRenderer::destroyBuffer(VkBuffer buffer)
{
m_destructionQueues.m_buffers[m_commandBufferIndex].emplace_back(buffer);
}
void VulkanRenderer::destroyDeviceMemory(VkDeviceMemory mem)
{
m_destructionQueues.m_memory[m_commandBufferIndex].emplace_back(mem);
}
void VulkanRenderer::destroyPipelineInfo(PipelineInfo* pipelineInfo)
{
cemu_assert_debug(false);
}
void VulkanRenderer::destroyShader(RendererShaderVk* shader)
{
while (!shader->list_pipelineInfo.empty())
delete shader->list_pipelineInfo[0];
}
void VulkanRenderer::releaseDestructibleObject(VKRDestructibleObject* destructibleObject)
{ {
// destroy immediately if possible // destroy immediately if possible
if (destructibleObject->canDestroy()) if (destructibleObject->canDestroy())
@ -3092,7 +3012,7 @@ void VulkanRenderer::releaseDestructibleObject(VKRDestructibleObject* destructib
m_spinlockDestructionQueue.unlock(); m_spinlockDestructionQueue.unlock();
} }
void VulkanRenderer::ProcessDestructionQueue2() void VulkanRenderer::ProcessDestructionQueue()
{ {
m_spinlockDestructionQueue.lock(); m_spinlockDestructionQueue.lock();
for (auto it = m_destructionQueue.begin(); it != m_destructionQueue.end();) for (auto it = m_destructionQueue.begin(); it != m_destructionQueue.end();)
@ -3141,7 +3061,7 @@ VkDescriptorSetInfo::~VkDescriptorSetInfo()
performanceMonitor.vk.numDescriptorDynUniformBuffers.decrement(statsNumDynUniformBuffers); performanceMonitor.vk.numDescriptorDynUniformBuffers.decrement(statsNumDynUniformBuffers);
performanceMonitor.vk.numDescriptorStorageBuffers.decrement(statsNumStorageBuffers); performanceMonitor.vk.numDescriptorStorageBuffers.decrement(statsNumStorageBuffers);
VulkanRenderer::GetInstance()->releaseDestructibleObject(m_vkObjDescriptorSet); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_vkObjDescriptorSet);
m_vkObjDescriptorSet = nullptr; m_vkObjDescriptorSet = nullptr;
} }
@ -3154,32 +3074,18 @@ void VulkanRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceI
else else
{ {
cemu_assert_debug(vkTexture->dim != Latte::E_DIM::DIM_3D); cemu_assert_debug(vkTexture->dim != Latte::E_DIM::DIM_3D);
if (hostTexture->IsCompressedFormat()) ClearColorImage(vkTexture, sliceIndex, mipIndex, { 0,0,0,0 }, VK_IMAGE_LAYOUT_GENERAL);
{
auto imageObj = vkTexture->GetImageObj();
imageObj->flagForCurrentCommandBuffer();
cemuLog_logDebug(LogType::Force, "Compressed texture ({}/{} fmt {:04x}) unsupported clear", vkTexture->width, vkTexture->height, (uint32)vkTexture->format);
VkImageSubresourceLayers subresourceRange{};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.mipLevel = mipIndex;
subresourceRange.baseArrayLayer = sliceIndex;
subresourceRange.layerCount = 1;
barrier_image<ANY_TRANSFER | IMAGE_READ, ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE>(vkTexture, subresourceRange, VK_IMAGE_LAYOUT_GENERAL);
}
else
{
ClearColorImage(vkTexture, sliceIndex, mipIndex, { 0,0,0,0 }, VK_IMAGE_LAYOUT_GENERAL);
}
} }
} }
void VulkanRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) void VulkanRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)
{ {
auto vkTexture = (LatteTextureVk*)hostTexture; auto vkTexture = (LatteTextureVk*)hostTexture;
cemu_assert_debug(vkTexture->dim != Latte::E_DIM::DIM_3D); if(vkTexture->dim == Latte::E_DIM::DIM_3D)
ClearColorImage(vkTexture, sliceIndex, mipIndex, { r,g,b,a }, VK_IMAGE_LAYOUT_GENERAL); {
cemu_assert_unimplemented();
}
ClearColorImage(vkTexture, sliceIndex, mipIndex, {r, g, b, a}, VK_IMAGE_LAYOUT_GENERAL);
} }
void VulkanRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) void VulkanRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue)

View file

@ -130,7 +130,6 @@ class VulkanRenderer : public Renderer
using QueueFamilyIndices = SwapchainInfoVk::QueueFamilyIndices; 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 TEXTURE_READBACK_SIZE = 32 * 1024 * 1024; // 32 MB static const inline int TEXTURE_READBACK_SIZE = 32 * 1024 * 1024; // 32 MB
@ -232,7 +231,6 @@ public:
void DrawEmptyFrame(bool mainWindow) override; void DrawEmptyFrame(bool mainWindow) override;
void PreparePresentationFrame(bool mainWindow); void PreparePresentationFrame(bool mainWindow);
void ProcessDestructionQueues(size_t commandBufferIndex);
void InitFirstCommandBuffer(); void InitFirstCommandBuffer();
void ProcessFinishedCommandBuffers(); void ProcessFinishedCommandBuffers();
void WaitForNextFinishedCommandBuffer(); void WaitForNextFinishedCommandBuffer();
@ -245,15 +243,9 @@ public:
bool HasCommandBufferFinished(uint64 commandBufferId) const; bool HasCommandBufferFinished(uint64 commandBufferId) const;
void WaitCommandBufferFinished(uint64 commandBufferId); void WaitCommandBufferFinished(uint64 commandBufferId);
// clean up (deprecated) // resource destruction queue
void destroyViewDepr(VkImageView imageView); void ReleaseDestructibleObject(VKRDestructibleObject* destructibleObject);
void destroyBuffer(VkBuffer buffer); void ProcessDestructionQueue();
void destroyDeviceMemory(VkDeviceMemory mem);
void destroyPipelineInfo(PipelineInfo* pipelineInfo);
void destroyShader(RendererShaderVk* shader);
// clean up (new)
void releaseDestructibleObject(VKRDestructibleObject* destructibleObject);
void ProcessDestructionQueue2();
FSpinlock m_spinlockDestructionQueue; FSpinlock m_spinlockDestructionQueue;
std::vector<VKRDestructibleObject*> m_destructionQueue; std::vector<VKRDestructibleObject*> m_destructionQueue;
@ -291,9 +283,6 @@ public:
TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override; TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;
void texture_reserveTextureOnGPU(LatteTexture* hostTexture) override;
void texture_destroy(LatteTexture* hostTexture) override;
void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override; void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;
void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override; void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;
void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override; void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override;
@ -312,7 +301,6 @@ public:
void surfaceCopy_notifyTextureRelease(LatteTextureVk* hostTexture); void surfaceCopy_notifyTextureRelease(LatteTextureVk* hostTexture);
private: private:
void surfaceCopy_viaBuffer(LatteTextureVk* srcTextureVk, sint32 texSrcMip, sint32 texSrcLevel, LatteTextureVk* dstTextureVk, sint32 texDstMip, sint32 texDstLevel, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight);
void surfaceCopy_viaDrawcall(LatteTextureVk* srcTextureVk, sint32 texSrcMip, sint32 texSrcSlice, LatteTextureVk* dstTextureVk, sint32 texDstMip, sint32 texDstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight); void surfaceCopy_viaDrawcall(LatteTextureVk* srcTextureVk, sint32 texSrcMip, sint32 texSrcSlice, LatteTextureVk* dstTextureVk, sint32 texDstMip, sint32 texDstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight);
void surfaceCopy_cleanup(); void surfaceCopy_cleanup();
@ -329,10 +317,6 @@ private:
std::unordered_map<uint64, struct CopySurfacePipelineInfo*> m_copySurfacePipelineCache; std::unordered_map<uint64, struct CopySurfacePipelineInfo*> m_copySurfacePipelineCache;
VkBuffer m_surfaceCopyBuffer = VK_NULL_HANDLE;
VkDeviceMemory m_surfaceCopyBufferMemory = VK_NULL_HANDLE;
size_t m_surfaceCopyBufferSize{};
public: public:
// renderer interface // renderer interface
void bufferCache_init(const sint32 bufferSize) override; void bufferCache_init(const sint32 bufferSize) override;
@ -471,7 +455,6 @@ private:
struct struct
{ {
bool useBufferSurfaceCopies; // if GPU has enough VRAM to spare, allow to use a buffer to copy surfaces (instead of drawcalls)
bool useTFEmulationViaSSBO = true; // emulate transform feedback via shader writes to a storage buffer bool useTFEmulationViaSSBO = true; // emulate transform feedback via shader writes to a storage buffer
}mode; }mode;
@ -548,15 +531,11 @@ private:
void sync_RenderPassStoreTextures(CachedFBOVk* fboVk); void sync_RenderPassStoreTextures(CachedFBOVk* fboVk);
// command buffer // command buffer
VkCommandBuffer getCurrentCommandBuffer() const { return m_state.currentCommandBuffer; } VkCommandBuffer getCurrentCommandBuffer() const { return m_state.currentCommandBuffer; }
// uniform // uniform
void uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader); void uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader);
// indices
void CreateBackbufferIndexBuffer();
// misc // misc
void CreatePipelineCache(); void CreatePipelineCache();
VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const; VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;
@ -580,9 +559,6 @@ private:
void occlusionQuery_notifyBeginCommandBuffer(); void occlusionQuery_notifyBeginCommandBuffer();
private: private:
VkBuffer m_indexBuffer = VK_NULL_HANDLE;
VkDeviceMemory m_indexBufferMemory = VK_NULL_HANDLE;
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_physicalDevice = VK_NULL_HANDLE; VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
@ -648,15 +624,6 @@ private:
// command buffer, garbage collection, synchronization // command buffer, garbage collection, synchronization
static constexpr uint32 kCommandBufferPoolSize = 128; static constexpr uint32 kCommandBufferPoolSize = 128;
struct
{
std::array<std::vector<VkDescriptorSet>, kCommandBufferPoolSize> m_cmd_descriptor_set_objects;
std::array<std::vector<VkImageView>, kCommandBufferPoolSize> m_cmd_image_views;
std::array<std::vector<LatteTextureVk*>, kCommandBufferPoolSize> m_host_textures;
std::array<std::vector<VkBuffer>, kCommandBufferPoolSize> m_buffers;
std::array<std::vector<VkDeviceMemory>, kCommandBufferPoolSize> m_memory;
}m_destructionQueues;
size_t m_commandBufferIndex = 0; // current buffer being filled size_t m_commandBufferIndex = 0; // current buffer being filled
size_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit) size_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit)
std::array<VkFence, kCommandBufferPoolSize> m_cmd_buffer_fences; std::array<VkFence, kCommandBufferPoolSize> m_cmd_buffer_fences;

View file

@ -190,6 +190,7 @@ std::queue<PipelineCompiler*> g_compilePipelineRequests;
void compilePipeline_thread(sint32 threadIndex) void compilePipeline_thread(sint32 threadIndex)
{ {
SetThreadName("compilePl");
#ifdef _WIN32 #ifdef _WIN32
// one thread runs at normal priority while the others run at lower priority // one thread runs at normal priority while the others run at lower priority
if(threadIndex != 0) if(threadIndex != 0)

View file

@ -464,9 +464,8 @@ VKRObjectFramebuffer* VulkanRenderer::surfaceCopy_getOrCreateFramebuffer(VkCopyS
VKRObjectTextureView* vkObjTextureView = surfaceCopy_createImageView(state.destinationTexture, state.dstSlice, state.dstMip); VKRObjectTextureView* vkObjTextureView = surfaceCopy_createImageView(state.destinationTexture, state.dstSlice, state.dstMip);
// create new framebuffer // create new framebuffer
sint32 effectiveWidth = 0; sint32 effectiveWidth, effectiveHeight;
sint32 effectiveHeight = 0; state.destinationTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, state.dstMip);
LatteTexture_getEffectiveSize(state.destinationTexture, &effectiveWidth, &effectiveHeight, nullptr, state.dstMip);
std::array<VKRObjectTextureView*, 1> fbAttachments; std::array<VKRObjectTextureView*, 1> fbAttachments;
fbAttachments[0] = vkObjTextureView; fbAttachments[0] = vkObjTextureView;
@ -595,15 +594,11 @@ void VulkanRenderer::surfaceCopy_viaDrawcall(LatteTextureVk* srcTextureVk, sint3
// get descriptor set // get descriptor set
VKRObjectDescriptorSet* vkObjDescriptorSet = surfaceCopy_getOrCreateDescriptorSet(copySurfaceState, copySurfacePipelineInfo); VKRObjectDescriptorSet* vkObjDescriptorSet = surfaceCopy_getOrCreateDescriptorSet(copySurfaceState, copySurfacePipelineInfo);
// get extend sint32 dstEffectiveWidth, dstEffectiveHeight;
sint32 effectiveWidth = 0; dstTextureVk->GetEffectiveSize(dstEffectiveWidth, dstEffectiveHeight, texDstMip);
sint32 effectiveHeight = 0;
LatteTexture_getEffectiveSize(dstTextureVk, &effectiveWidth, &effectiveHeight, nullptr, texDstMip);
// get extend sint32 srcEffectiveWidth, srcEffectiveHeight;
sint32 srcEffectiveWidth = 0; srcTextureVk->GetEffectiveSize(srcEffectiveWidth, srcEffectiveHeight, texSrcMip);
sint32 srcEffectiveHeight = 0;
LatteTexture_getEffectiveSize(srcTextureVk, &srcEffectiveWidth, &srcEffectiveHeight, nullptr, texSrcMip);
CopyShaderPushConstantData_t pushConstantData; CopyShaderPushConstantData_t pushConstantData;
@ -768,119 +763,14 @@ bool vkIsBitCompatibleColorDepthFormat(VkFormat format1, VkFormat format2)
return false; return false;
} }
void VulkanRenderer::surfaceCopy_viaBuffer(LatteTextureVk* srcTextureVk, sint32 texSrcMip, sint32 texSrcSlice, LatteTextureVk* dstTextureVk, sint32 texDstMip, sint32 texDstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight)
{
cemu_assert_debug(false); // not used currently
cemu_assert_debug(m_featureControl.mode.useBufferSurfaceCopies);
if (srcTextureVk->dim == Latte::E_DIM::DIM_3D)
{
cemu_assert_debug(false);
return;
}
if (dstTextureVk->dim == Latte::E_DIM::DIM_3D)
{
cemu_assert_debug(false);
return;
}
draw_endRenderPass();
// calculate buffer size required for copy
VkDeviceSize copySize = std::max(srcTextureVk->getAllocation()->getAllocationSize(), dstTextureVk->getAllocation()->getAllocationSize());
// make sure allocated buffer is large enough
if (m_surfaceCopyBuffer == VK_NULL_HANDLE || copySize > m_surfaceCopyBufferSize)
{
if (m_surfaceCopyBuffer != VK_NULL_HANDLE)
{
// free existing buffer
destroyDeviceMemory(m_surfaceCopyBufferMemory);
m_surfaceCopyBufferMemory = VK_NULL_HANDLE;
destroyBuffer(m_surfaceCopyBuffer);
m_surfaceCopyBuffer = VK_NULL_HANDLE;
}
VkDeviceSize allocSize = (copySize + 1024ull * 1024ull - 1ull) & ~(1024ull * 1024ull - 1ull); // align to whole MB
m_surfaceCopyBufferSize = allocSize;
memoryManager->CreateBuffer(m_surfaceCopyBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_surfaceCopyBuffer, m_surfaceCopyBufferMemory);
if (m_surfaceCopyBuffer == VK_NULL_HANDLE)
{
cemuLog_log(LogType::Force, "Vulkan: Failed to allocate surface copy buffer with size {}", allocSize);
return;
}
}
if (m_surfaceCopyBuffer == VK_NULL_HANDLE)
return;
auto vkObjSrcTexture = srcTextureVk->GetImageObj();
auto vkObjDstTexture = dstTextureVk->GetImageObj();
vkObjSrcTexture->flagForCurrentCommandBuffer();
vkObjDstTexture->flagForCurrentCommandBuffer();
VkBufferImageCopy region{};
region.bufferOffset = 0;
region.bufferRowLength = effectiveCopyWidth;
region.bufferImageHeight = effectiveCopyHeight;
if (srcTextureVk->isDepth)
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
else
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.baseArrayLayer = texSrcSlice;
region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel = texSrcMip;
region.imageOffset = { 0,0,0 };
region.imageExtent = { (uint32)effectiveCopyWidth, (uint32)effectiveCopyHeight, 1 };
// make sure all write operations to the src image have finished
barrier_image<SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER, SYNC_OP::ANY_TRANSFER>(srcTextureVk, region.imageSubresource, VK_IMAGE_LAYOUT_GENERAL);
vkCmdCopyImageToBuffer(getCurrentCommandBuffer(), vkObjSrcTexture->m_image, VK_IMAGE_LAYOUT_GENERAL, m_surfaceCopyBuffer, 1, &region);
// copy buffer to image
VkBufferImageCopy imageRegion[2]{};
sint32 imageRegionCount = 0;
// color or depth only copy
imageRegion[0].bufferOffset = 0;
imageRegion[0].imageExtent.width = effectiveCopyWidth;
imageRegion[0].imageExtent.height = effectiveCopyHeight;
imageRegion[0].imageExtent.depth = 1;
imageRegion[0].imageSubresource.mipLevel = texDstMip;
if (dstTextureVk->isDepth)
imageRegion[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
else
imageRegion[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageRegion[0].imageSubresource.baseArrayLayer = texDstSlice;
imageRegion[0].imageSubresource.layerCount = 1;
imageRegionCount = 1;
// make sure the transfer to the buffer finished
barrier_bufferRange<SYNC_OP::ANY_TRANSFER, SYNC_OP::ANY_TRANSFER>(m_surfaceCopyBuffer, 0, VK_WHOLE_SIZE);
// make sure all read and write operations to the dst image have finished
barrier_image<SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER, SYNC_OP::ANY_TRANSFER>(dstTextureVk, imageRegion[0].imageSubresource, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdCopyBufferToImage(m_state.currentCommandBuffer, m_surfaceCopyBuffer, vkObjDstTexture->m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageRegionCount, imageRegion);
// make sure transfer has finished before any other operation
barrier_image<SYNC_OP::ANY_TRANSFER, SYNC_OP::ANY_TRANSFER | SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE>(dstTextureVk, imageRegion[0].imageSubresource, VK_IMAGE_LAYOUT_GENERAL);
}
void VulkanRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) void VulkanRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)
{ {
// scale copy size to effective size // scale copy size to effective size
sint32 effectiveCopyWidth = width; sint32 effectiveCopyWidth = width;
sint32 effectiveCopyHeight = height; sint32 effectiveCopyHeight = height;
LatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0); LatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);
sint32 sourceEffectiveWidth; sint32 sourceEffectiveWidth, sourceEffectiveHeight;
sint32 sourceEffectiveHeight; sourceTexture->GetEffectiveSize(sourceEffectiveWidth, sourceEffectiveHeight, srcMip);
LatteTexture_getEffectiveSize(sourceTexture, &sourceEffectiveWidth, &sourceEffectiveHeight, nullptr, srcMip);
sint32 texSrcMip = srcMip; sint32 texSrcMip = srcMip;
sint32 texSrcSlice = srcSlice; sint32 texSrcSlice = srcSlice;
@ -905,28 +795,7 @@ void VulkanRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* s
return; return;
} }
VkFormat srcFormatVk = srcTextureVk->GetFormat(); surfaceCopy_viaDrawcall(srcTextureVk, texSrcMip, texSrcSlice, dstTextureVk, texDstMip, texDstSlice, effectiveCopyWidth, effectiveCopyHeight);
VkFormat dstFormatVk = dstTextureVk->GetFormat();
if ((srcTextureVk->isDepth && !dstTextureVk->isDepth) ||
!srcTextureVk->isDepth && dstTextureVk->isDepth)
{
// depth to color or
// color to depth
if (m_featureControl.mode.useBufferSurfaceCopies && vkIsBitCompatibleColorDepthFormat(srcFormatVk, dstFormatVk))
surfaceCopy_viaBuffer(srcTextureVk, texSrcMip, texSrcSlice, dstTextureVk, texDstMip, texDstSlice, effectiveCopyWidth, effectiveCopyHeight);
else
surfaceCopy_viaDrawcall(srcTextureVk, texSrcMip, texSrcSlice, dstTextureVk, texDstMip, texDstSlice, effectiveCopyWidth, effectiveCopyHeight);
}
else
{
// depth to depth or
// color to color
if (m_featureControl.mode.useBufferSurfaceCopies && srcFormatVk == dstFormatVk)
surfaceCopy_viaBuffer(srcTextureVk, texSrcMip, texSrcSlice, dstTextureVk, texDstMip, texDstSlice, effectiveCopyWidth, effectiveCopyHeight);
else
surfaceCopy_viaDrawcall(srcTextureVk, texSrcMip, texSrcSlice, dstTextureVk, texDstMip, texDstSlice, effectiveCopyWidth, effectiveCopyHeight);
}
} }
// called whenever a texture is destroyed // called whenever a texture is destroyed
@ -944,9 +813,9 @@ void VulkanRenderer::surfaceCopy_notifyTextureRelease(LatteTextureVk* hostTextur
{ {
if (p) if (p)
{ {
VulkanRenderer::GetInstance()->releaseDestructibleObject(p->vkObjDescriptorSet); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjDescriptorSet);
p->vkObjDescriptorSet = nullptr; p->vkObjDescriptorSet = nullptr;
VulkanRenderer::GetInstance()->releaseDestructibleObject(p->vkObjImageView); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjImageView);
p->vkObjImageView = nullptr; p->vkObjImageView = nullptr;
} }
} }
@ -960,9 +829,9 @@ void VulkanRenderer::surfaceCopy_notifyTextureRelease(LatteTextureVk* hostTextur
{ {
if (p) if (p)
{ {
VulkanRenderer::GetInstance()->releaseDestructibleObject(p->vkObjFramebuffer); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjFramebuffer);
p->vkObjFramebuffer = nullptr; p->vkObjFramebuffer = nullptr;
VulkanRenderer::GetInstance()->releaseDestructibleObject(p->vkObjImageView); VulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjImageView);
p->vkObjImageView = nullptr; p->vkObjImageView = nullptr;
} }
} }

View file

@ -1,3 +1,4 @@
#include <util/helpers/helpers.h>
#include "iosu_odm.h" #include "iosu_odm.h"
#include "config/ActiveSettings.h" #include "config/ActiveSettings.h"
#include "Common/FileStream.h" #include "Common/FileStream.h"
@ -79,6 +80,7 @@ namespace iosu
void ODMServiceThread() void ODMServiceThread()
{ {
SetThreadName("ODMService");
s_msgQueueId = IOS_CreateMessageQueue(_s_msgBuffer.GetPtr(), _s_msgBuffer.GetCount()); s_msgQueueId = IOS_CreateMessageQueue(_s_msgBuffer.GetPtr(), _s_msgBuffer.GetCount());
cemu_assert(!IOS_ResultIsError((IOS_ERROR)s_msgQueueId)); cemu_assert(!IOS_ResultIsError((IOS_ERROR)s_msgQueueId));
IOS_ERROR r = IOS_RegisterResourceManager(s_devicePath.c_str(), s_msgQueueId); IOS_ERROR r = IOS_RegisterResourceManager(s_devicePath.c_str(), s_msgQueueId);

View file

@ -1,3 +1,4 @@
#include <util/helpers/helpers.h>
#include "iosu_pdm.h" #include "iosu_pdm.h"
#include "Cafe/CafeSystem.h" #include "Cafe/CafeSystem.h"
#include "config/ActiveSettings.h" #include "config/ActiveSettings.h"
@ -387,6 +388,7 @@ namespace iosu
void TimeTrackingThread(uint64 titleId) void TimeTrackingThread(uint64 titleId)
{ {
SetThreadName("PlayDiaryThread");
PlayStatsEntry* playStatsEntry = PlayStats_BeginNewTracking(titleId); PlayStatsEntry* playStatsEntry = PlayStats_BeginNewTracking(titleId);
auto startTime = std::chrono::steady_clock::now(); auto startTime = std::chrono::steady_clock::now();

View file

@ -155,6 +155,7 @@ namespace iosu
void IPCService::ServiceThread() void IPCService::ServiceThread()
{ {
SetThreadName("IPCService");
m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount()); m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());
cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId)); cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));
IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId); IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);

View file

@ -1168,7 +1168,7 @@ namespace coreinit
void OSSchedulerCoreEmulationThread(void* _assignedCoreIndex) void OSSchedulerCoreEmulationThread(void* _assignedCoreIndex)
{ {
SetThreadName(fmt::format("OSSchedulerThread[core={}]", (uintptr_t)_assignedCoreIndex).c_str()); SetThreadName(fmt::format("OSSched[core={}]", (uintptr_t)_assignedCoreIndex).c_str());
t_assignedCoreIndex = (sint32)(uintptr_t)_assignedCoreIndex; t_assignedCoreIndex = (sint32)(uintptr_t)_assignedCoreIndex;
#if defined(ARCH_X86_64) #if defined(ARCH_X86_64)
_mm_setcsr(_mm_getcsr() | 0x8000); // flush denormals to zero _mm_setcsr(_mm_getcsr() | 0x8000); // flush denormals to zero

View file

@ -396,16 +396,13 @@ void gx2_load()
osLib_addFunction("gx2", "GX2GetCurrentScanBuffer", gx2Export_GX2GetCurrentScanBuffer); osLib_addFunction("gx2", "GX2GetCurrentScanBuffer", gx2Export_GX2GetCurrentScanBuffer);
// shader stuff // shader stuff
//osLib_addFunction("gx2", "GX2SetVertexShader", gx2Export_GX2SetVertexShader);
osLib_addFunction("gx2", "GX2SetPixelShader", gx2Export_GX2SetPixelShader); osLib_addFunction("gx2", "GX2SetPixelShader", gx2Export_GX2SetPixelShader);
osLib_addFunction("gx2", "GX2SetGeometryShader", gx2Export_GX2SetGeometryShader); osLib_addFunction("gx2", "GX2SetGeometryShader", gx2Export_GX2SetGeometryShader);
osLib_addFunction("gx2", "GX2SetComputeShader", gx2Export_GX2SetComputeShader); osLib_addFunction("gx2", "GX2SetComputeShader", gx2Export_GX2SetComputeShader);
osLib_addFunction("gx2", "GX2SetVertexUniformReg", gx2Export_GX2SetVertexUniformReg);
osLib_addFunction("gx2", "GX2SetVertexUniformBlock", gx2Export_GX2SetVertexUniformBlock); osLib_addFunction("gx2", "GX2SetVertexUniformBlock", gx2Export_GX2SetVertexUniformBlock);
osLib_addFunction("gx2", "GX2RSetVertexUniformBlock", gx2Export_GX2RSetVertexUniformBlock); osLib_addFunction("gx2", "GX2RSetVertexUniformBlock", gx2Export_GX2RSetVertexUniformBlock);
osLib_addFunction("gx2", "GX2SetPixelUniformBlock", gx2Export_GX2SetPixelUniformBlock); osLib_addFunction("gx2", "GX2SetPixelUniformBlock", gx2Export_GX2SetPixelUniformBlock);
osLib_addFunction("gx2", "GX2SetPixelUniformReg", gx2Export_GX2SetPixelUniformReg);
osLib_addFunction("gx2", "GX2SetGeometryUniformBlock", gx2Export_GX2SetGeometryUniformBlock); osLib_addFunction("gx2", "GX2SetGeometryUniformBlock", gx2Export_GX2SetGeometryUniformBlock);
osLib_addFunction("gx2", "GX2SetShaderModeEx", gx2Export_GX2SetShaderModeEx); osLib_addFunction("gx2", "GX2SetShaderModeEx", gx2Export_GX2SetShaderModeEx);

View file

@ -18,11 +18,9 @@ void gx2_load();
void gx2Export_GX2SetPixelShader(PPCInterpreter_t* hCPU); void gx2Export_GX2SetPixelShader(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetGeometryShader(PPCInterpreter_t* hCPU); void gx2Export_GX2SetGeometryShader(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetComputeShader(PPCInterpreter_t* hCPU); void gx2Export_GX2SetComputeShader(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetVertexUniformReg(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetVertexUniformBlock(PPCInterpreter_t* hCPU); void gx2Export_GX2SetVertexUniformBlock(PPCInterpreter_t* hCPU);
void gx2Export_GX2RSetVertexUniformBlock(PPCInterpreter_t* hCPU); void gx2Export_GX2RSetVertexUniformBlock(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetPixelUniformBlock(PPCInterpreter_t* hCPU); void gx2Export_GX2SetPixelUniformBlock(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetPixelUniformReg(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetGeometryUniformBlock(PPCInterpreter_t* hCPU); void gx2Export_GX2SetGeometryUniformBlock(PPCInterpreter_t* hCPU);
void gx2Export_GX2SetShaderModeEx(PPCInterpreter_t* hCPU); void gx2Export_GX2SetShaderModeEx(PPCInterpreter_t* hCPU);
void gx2Export_GX2CalcGeometryShaderInputRingBufferSize(PPCInterpreter_t* hCPU); void gx2Export_GX2CalcGeometryShaderInputRingBufferSize(PPCInterpreter_t* hCPU);

View file

@ -114,7 +114,7 @@ namespace GX2
void GX2RSetStreamOutBuffer(uint32 bufferIndex, GX2StreamOutBuffer* soBuffer) void GX2RSetStreamOutBuffer(uint32 bufferIndex, GX2StreamOutBuffer* soBuffer)
{ {
// seen in CoD: Ghosts // seen in CoD: Ghosts and CoD: Black Ops 2
GX2SetStreamOutBuffer(bufferIndex, soBuffer); GX2SetStreamOutBuffer(bufferIndex, soBuffer);
} }

View file

@ -417,6 +417,37 @@ namespace GX2
} }
} }
void _GX2SubmitUniformReg(uint32 offsetRegBase, uint32 aluRegisterOffset, uint32be* dataWords, uint32 sizeInU32s)
{
if(aluRegisterOffset&0x8000)
{
cemuLog_logDebug(LogType::Force, "_GX2SubmitUniformReg(): Unhandled loop const special case or invalid offset");
return;
}
if((aluRegisterOffset+sizeInU32s) > 0x400)
{
cemuLog_logOnce(LogType::APIErrors, "GX2SetVertexUniformReg values are out of range (offset {} + size {} must be equal or smaller than 0x400)", aluRegisterOffset, sizeInU32s);
}
if( (sizeInU32s&3) != 0)
{
cemuLog_logOnce(LogType::APIErrors, "GX2Set*UniformReg must be called with a size that is a multiple of 4 (size: {:})", sizeInU32s);
sizeInU32s &= ~3;
}
GX2ReserveCmdSpace(2 + sizeInU32s);
gx2WriteGather_submit(pm4HeaderType3(IT_SET_ALU_CONST, 1 + sizeInU32s), offsetRegBase + aluRegisterOffset);
gx2WriteGather_submitU32AsLEArray((uint32*)dataWords, sizeInU32s);
}
void GX2SetVertexUniformReg(uint32 offset, uint32 sizeInU32s, uint32be* values)
{
_GX2SubmitUniformReg(0x400, offset, values, sizeInU32s);
}
void GX2SetPixelUniformReg(uint32 offset, uint32 sizeInU32s, uint32be* values)
{
_GX2SubmitUniformReg(0, offset, values, sizeInU32s);
}
void GX2ShaderInit() void GX2ShaderInit()
{ {
cafeExportRegister("gx2", GX2CalcFetchShaderSizeEx, LogType::GX2); cafeExportRegister("gx2", GX2CalcFetchShaderSizeEx, LogType::GX2);
@ -428,5 +459,8 @@ namespace GX2
cafeExportRegister("gx2", GX2GetPixelShaderStackEntries, LogType::GX2); cafeExportRegister("gx2", GX2GetPixelShaderStackEntries, LogType::GX2);
cafeExportRegister("gx2", GX2SetFetchShader, LogType::GX2); cafeExportRegister("gx2", GX2SetFetchShader, LogType::GX2);
cafeExportRegister("gx2", GX2SetVertexShader, LogType::GX2); cafeExportRegister("gx2", GX2SetVertexShader, LogType::GX2);
cafeExportRegister("gx2", GX2SetVertexUniformReg, LogType::GX2);
cafeExportRegister("gx2", GX2SetPixelUniformReg, LogType::GX2);
} }
} }

View file

@ -270,41 +270,6 @@ void gx2Export_GX2SetComputeShader(PPCInterpreter_t* hCPU)
osLib_returnFromFunction(hCPU, 0); osLib_returnFromFunction(hCPU, 0);
} }
void _GX2SubmitUniformReg(uint32 aluRegisterOffset, MPTR virtualAddress, uint32 count)
{
uint32* dataWords = (uint32*)memory_getPointerFromVirtualOffset(virtualAddress);
GX2ReserveCmdSpace(2 + (count / 0xFF) * 2 + count);
// write PM4 command(s)
uint32 currentRegisterOffset = aluRegisterOffset;
while (count > 0)
{
uint32 subCount = std::min(count, 0xFFu); // a single command can write at most 0xFF values
gx2WriteGather_submit(pm4HeaderType3(IT_SET_ALU_CONST, 1 + subCount),
currentRegisterOffset);
gx2WriteGather_submitU32AsLEArray(dataWords, subCount);
dataWords += subCount;
count -= subCount;
currentRegisterOffset += subCount;
}
}
void gx2Export_GX2SetVertexUniformReg(PPCInterpreter_t* hCPU)
{
cemuLog_log(LogType::GX2, "GX2SetVertexUniformReg(0x{:08x},0x{:x},0x{:08x})", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);
_GX2SubmitUniformReg(hCPU->gpr[3] + 0x400, hCPU->gpr[5], hCPU->gpr[4]);
cemu_assert_debug((hCPU->gpr[3] + hCPU->gpr[4]) <= 0x400);
osLib_returnFromFunction(hCPU, 0);
}
void gx2Export_GX2SetPixelUniformReg(PPCInterpreter_t* hCPU)
{
cemuLog_log(LogType::GX2, "GX2SetPixelUniformReg(0x{:08x},0x{:x},0x{:08x})", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);
_GX2SubmitUniformReg(hCPU->gpr[3], hCPU->gpr[5], hCPU->gpr[4]);
cemu_assert_debug((hCPU->gpr[3] + hCPU->gpr[4]) <= 0x400);
osLib_returnFromFunction(hCPU, 0);
}
void _GX2SubmitUniformBlock(uint32 registerBase, uint32 index, MPTR virtualAddress, uint32 size) void _GX2SubmitUniformBlock(uint32 registerBase, uint32 index, MPTR virtualAddress, uint32 size)
{ {
GX2ReserveCmdSpace(9); GX2ReserveCmdSpace(9);

View file

@ -8,83 +8,14 @@
// AC lib (manages internet connection) // AC lib (manages internet connection)
#define AC_STATUS_FAILED (-1) enum class AC_STATUS : uint32
#define AC_STATUS_OK (0)
void nn_acExport_ConnectAsync(PPCInterpreter_t* hCPU)
{ {
cemuLog_logDebug(LogType::Force, "nn_ac.ConnectAsync();"); FAILED = (uint32)-1,
uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0); OK = 0,
osLib_returnFromFunction(hCPU, nnResultCode); };
}
void nn_acExport_Connect(PPCInterpreter_t* hCPU)
{
cemuLog_logDebug(LogType::Force, "nn_ac.Connect();");
// Terraria expects this (or GetLastErrorCode) to return 0 on success
// investigate on the actual console
// maybe all success codes are always 0 and dont have any of the other fields set?
uint32 nnResultCode = 0;// BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0); // Splatoon freezes if this function fails?
osLib_returnFromFunction(hCPU, nnResultCode);
}
static_assert(TRUE == 1, "TRUE not 1"); static_assert(TRUE == 1, "TRUE not 1");
void nn_acExport_IsApplicationConnected(PPCInterpreter_t* hCPU)
{
//cemuLog_logDebug(LogType::Force, "nn_ac.IsApplicationConnected(0x{:08x})", hCPU->gpr[3]);
ppcDefineParamMEMPTR(connected, uint8, 0);
if (connected)
*connected = TRUE;
//memory_writeU8(hCPU->gpr[3], 1); // always return true regardless of actual online state
const uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
osLib_returnFromFunction(hCPU, nnResultCode);
}
void nn_acExport_GetConnectStatus(PPCInterpreter_t* hCPU)
{
ppcDefineParamMEMPTR(status, uint32, 0);
if (status)
*status = AC_STATUS_OK;
const uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
osLib_returnFromFunction(hCPU, nnResultCode);
}
void nn_acExport_GetLastErrorCode(PPCInterpreter_t* hCPU)
{
//cemuLog_logDebug(LogType::Force, "nn_ac.GetLastErrorCode();");
ppcDefineParamMEMPTR(errorCode, uint32, 0);
if (errorCode)
*errorCode = 0;
const uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
osLib_returnFromFunction(hCPU, nnResultCode);
}
void nn_acExport_GetStatus(PPCInterpreter_t* hCPU)
{
cemuLog_logDebug(LogType::Force, "nn_ac.GetStatus();");
ppcDefineParamMEMPTR(status, uint32, 0);
if (status)
*status = AC_STATUS_OK;
const uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
osLib_returnFromFunction(hCPU, nnResultCode);
}
void nn_acExport_GetConnectResult(PPCInterpreter_t* hCPU)
{
// GetConnectStatus__Q2_2nn2acFPQ3_2nn2ac6Status
cemuLog_logDebug(LogType::Force, "nn_ac.GetConnectResult(0x{:08x})", hCPU->gpr[3]);
ppcDefineParamMEMPTR(result, uint32, 0);
const uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
if (result)
*result = nnResultCode;
osLib_returnFromFunction(hCPU, nnResultCode);
}
void _GetLocalIPAndSubnetMaskFallback(uint32& localIp, uint32& subnetMask) void _GetLocalIPAndSubnetMaskFallback(uint32& localIp, uint32& subnetMask)
{ {
// default to some hardcoded values // default to some hardcoded values
@ -227,37 +158,127 @@ void nnAcExport_IsConfigExisting(PPCInterpreter_t* hCPU)
namespace nn_ac namespace nn_ac
{ {
nnResult Initialize()
{
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
}
nnResult ConnectAsync()
{
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
}
nnResult IsApplicationConnected(uint8be* connected)
{
if (connected)
*connected = TRUE;
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
}
uint32 Connect()
{
// Terraria expects this (or GetLastErrorCode) to return 0 on success
// investigate on the actual console
// maybe all success codes are always 0 and dont have any of the other fields set?
uint32 nnResultCode = 0;// BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0); // Splatoon freezes if this function fails?
return nnResultCode;
}
nnResult GetConnectStatus(betype<AC_STATUS>* status)
{
if (status)
*status = AC_STATUS::OK;
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
}
nnResult GetStatus(betype<AC_STATUS>* status)
{
return GetConnectStatus(status);
}
nnResult GetLastErrorCode(uint32be* errorCode)
{
if (errorCode)
*errorCode = 0;
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
}
nnResult GetConnectResult(uint32be* connectResult)
{
const uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);
if (connectResult)
*connectResult = nnResultCode;
return nnResultCode;
}
static_assert(sizeof(betype<AC_STATUS>) == 4);
static_assert(sizeof(betype<nnResult>) == 4);
nnResult ACInitialize()
{
return Initialize();
}
bool ACIsSuccess(betype<nnResult>* r) bool ACIsSuccess(betype<nnResult>* r)
{ {
return NN_RESULT_IS_SUCCESS(*r) ? 1 : 0; return NN_RESULT_IS_SUCCESS(*r) ? 1 : 0;
} }
nnResult ACGetConnectStatus(uint32be* connectionStatus) bool ACIsFailure(betype<nnResult>* r)
{ {
return NN_RESULT_IS_FAILURE(*r) ? 1 : 0;
}
*connectionStatus = 0; // 0 means connected? nnResult ACGetConnectStatus(betype<AC_STATUS>* connectionStatus)
{
return GetConnectStatus(connectionStatus);
}
return NN_RESULT_SUCCESS; nnResult ACGetStatus(betype<AC_STATUS>* connectionStatus)
{
return GetStatus(connectionStatus);
}
nnResult ACConnectAsync()
{
return ConnectAsync();
}
nnResult ACIsApplicationConnected(uint32be* connectedU32)
{
uint8be connected = 0;
nnResult r = IsApplicationConnected(&connected);
*connectedU32 = connected; // convert to uint32
return r;
} }
void load() void load()
{ {
cafeExportRegisterFunc(Initialize, "nn_ac", "Initialize__Q2_2nn2acFv", LogType::Placeholder);
cafeExportRegisterFunc(Connect, "nn_ac", "Connect__Q2_2nn2acFv", LogType::Placeholder);
cafeExportRegisterFunc(ConnectAsync, "nn_ac", "ConnectAsync__Q2_2nn2acFv", LogType::Placeholder);
cafeExportRegisterFunc(GetConnectResult, "nn_ac", "GetConnectResult__Q2_2nn2acFPQ2_2nn6Result", LogType::Placeholder);
cafeExportRegisterFunc(GetLastErrorCode, "nn_ac", "GetLastErrorCode__Q2_2nn2acFPUi", LogType::Placeholder);
cafeExportRegisterFunc(GetConnectStatus, "nn_ac", "GetConnectStatus__Q2_2nn2acFPQ3_2nn2ac6Status", LogType::Placeholder);
cafeExportRegisterFunc(GetStatus, "nn_ac", "GetStatus__Q2_2nn2acFPQ3_2nn2ac6Status", LogType::Placeholder);
cafeExportRegisterFunc(IsApplicationConnected, "nn_ac", "IsApplicationConnected__Q2_2nn2acFPb", LogType::Placeholder);
// AC also offers C-style wrappers
cafeExportRegister("nn_ac", ACInitialize, LogType::Placeholder);
cafeExportRegister("nn_ac", ACIsSuccess, LogType::Placeholder); cafeExportRegister("nn_ac", ACIsSuccess, LogType::Placeholder);
cafeExportRegister("nn_ac", ACIsFailure, LogType::Placeholder);
cafeExportRegister("nn_ac", ACGetConnectStatus, LogType::Placeholder); cafeExportRegister("nn_ac", ACGetConnectStatus, LogType::Placeholder);
cafeExportRegister("nn_ac", ACGetStatus, LogType::Placeholder);
cafeExportRegister("nn_ac", ACConnectAsync, LogType::Placeholder);
cafeExportRegister("nn_ac", ACIsApplicationConnected, LogType::Placeholder);
} }
} }
void nnAc_load() void nnAc_load()
{ {
osLib_addFunction("nn_ac", "Connect__Q2_2nn2acFv", nn_acExport_Connect);
osLib_addFunction("nn_ac", "ConnectAsync__Q2_2nn2acFv", nn_acExport_ConnectAsync);
osLib_addFunction("nn_ac", "IsApplicationConnected__Q2_2nn2acFPb", nn_acExport_IsApplicationConnected);
osLib_addFunction("nn_ac", "GetConnectStatus__Q2_2nn2acFPQ3_2nn2ac6Status", nn_acExport_GetConnectStatus);
osLib_addFunction("nn_ac", "GetConnectResult__Q2_2nn2acFPQ2_2nn6Result", nn_acExport_GetConnectResult);
osLib_addFunction("nn_ac", "GetLastErrorCode__Q2_2nn2acFPUi", nn_acExport_GetLastErrorCode);
osLib_addFunction("nn_ac", "GetStatus__Q2_2nn2acFPQ3_2nn2ac6Status", nn_acExport_GetStatus);
osLib_addFunction("nn_ac", "GetAssignedAddress__Q2_2nn2acFPUl", nnAcExport_GetAssignedAddress); osLib_addFunction("nn_ac", "GetAssignedAddress__Q2_2nn2acFPUl", nnAcExport_GetAssignedAddress);
osLib_addFunction("nn_ac", "GetAssignedSubnet__Q2_2nn2acFPUl", nnAcExport_GetAssignedSubnet); osLib_addFunction("nn_ac", "GetAssignedSubnet__Q2_2nn2acFPUl", nnAcExport_GetAssignedSubnet);

View file

@ -543,8 +543,6 @@ void nnActExport_GetDefaultAccount(PPCInterpreter_t* hCPU)
void nnActExport_GetSlotNo(PPCInterpreter_t* hCPU) void nnActExport_GetSlotNo(PPCInterpreter_t* hCPU)
{ {
// id of active account // id of active account
// uint8 GetSlotNo(void);
cemuLog_logDebug(LogType::Force, "nn_act.GetSlotNo()");
osLib_returnFromFunction(hCPU, 1); // 1 is the first slot (0 is invalid) osLib_returnFromFunction(hCPU, 1); // 1 is the first slot (0 is invalid)
} }

View file

@ -446,7 +446,6 @@ namespace nsyshid::backend::windows
{ {
sprintf(debugOutput + i * 3, "%02x ", data[i]); sprintf(debugOutput + i * 3, "%02x ", data[i]);
} }
fmt::print("{} Data: {}\n", prefix, debugOutput);
cemuLog_logDebug(LogType::Force, "[{}] Data: {}", prefix, debugOutput); cemuLog_logDebug(LogType::Force, "[{}] Data: {}", prefix, debugOutput);
} }
} // namespace nsyshid::backend::windows } // namespace nsyshid::backend::windows

View file

@ -332,7 +332,6 @@ namespace nsyshid
{ {
sprintf(debugOutput + i * 3, "%02x ", data[i]); sprintf(debugOutput + i * 3, "%02x ", data[i]);
} }
fmt::print("{} Data: {}\n", prefix, debugOutput);
cemuLog_logDebug(LogType::Force, "[{}] Data: {}", prefix, debugOutput); cemuLog_logDebug(LogType::Force, "[{}] Data: {}", prefix, debugOutput);
} }

View file

@ -1,5 +1,6 @@
#include "SaveList.h" #include "SaveList.h"
#include <charconv> #include <charconv>
#include <util/helpers/helpers.h>
std::mutex sSLMutex; std::mutex sSLMutex;
fs::path sSLMLCPath; fs::path sSLMLCPath;
@ -44,6 +45,7 @@ void CafeSaveList::Refresh()
void CafeSaveList::RefreshThreadWorker() void CafeSaveList::RefreshThreadWorker()
{ {
SetThreadName("SaveListWorker");
// clear save list // clear save list
for (auto& itSaveInfo : sSLList) for (auto& itSaveInfo : sSLList)
{ {

View file

@ -258,6 +258,7 @@ void CafeTitleList::AddTitleFromPath(fs::path path)
bool CafeTitleList::RefreshWorkerThread() bool CafeTitleList::RefreshWorkerThread()
{ {
SetThreadName("TitleListWorker");
while (sTLRefreshRequests.load()) while (sTLRefreshRequests.load())
{ {
sTLRefreshRequests.store(0); sTLRefreshRequests.store(0);

View file

@ -50,7 +50,7 @@ struct _FileCacheAsyncWriter
private: private:
void FileCacheThread() void FileCacheThread()
{ {
SetThreadName("fileCache_thread"); SetThreadName("fileCache");
while (true) while (true)
{ {
std::unique_lock lock(m_fileCacheMutex); std::unique_lock lock(m_fileCacheMutex);

View file

@ -7,7 +7,7 @@ enum class LogType : sint32
// note: IDs must be in range 1-64 // note: IDs must be in range 1-64
Force = 63, // always enabled Force = 63, // always enabled
Placeholder = 62, // always disabled Placeholder = 62, // always disabled
APIErrors = Force, // alias for Force. Logs bad parameters or other API errors in OS libs APIErrors = Force, // alias for Force. Logs bad parameters or other API usage mistakes or unintended errors in OS libs
CoreinitFile = 0, CoreinitFile = 0,
GX2 = 1, GX2 = 1,
@ -99,6 +99,8 @@ bool cemuLog_log(LogType type, const T* format, TArgs&&... args)
return cemuLog_log(type, format_str, std::forward<TArgs>(args)...); return cemuLog_log(type, format_str, std::forward<TArgs>(args)...);
} }
#define cemuLog_logOnce(...) { static bool _not_first_call = false; if (!_not_first_call) { _not_first_call = true; cemuLog_log(__VA_ARGS__); } }
// same as cemuLog_log, but only outputs in debug mode // same as cemuLog_log, but only outputs in debug mode
template<typename TFmt, typename ... TArgs> template<typename TFmt, typename ... TArgs>
bool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args) bool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args)
@ -110,6 +112,8 @@ bool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args)
#endif #endif
} }
#define cemuLog_logDebugOnce(...) { static bool _not_first_call = false; if (!_not_first_call) { _not_first_call = true; cemuLog_logDebug(__VA_ARGS__); } }
// cafe lib calls // cafe lib calls
bool cemuLog_advancedPPCLoggingEnabled(); bool cemuLog_advancedPPCLoggingEnabled();

View file

@ -155,6 +155,7 @@ void ExceptionHandler_Init()
action.sa_handler = handler_SIGINT; action.sa_handler = handler_SIGINT;
sigaction(SIGINT, &action, nullptr); sigaction(SIGINT, &action, nullptr);
sigaction(SIGTERM, &action, nullptr);
action.sa_flags = SA_SIGINFO; action.sa_flags = SA_SIGINFO;
action.sa_handler = nullptr; action.sa_handler = nullptr;

View file

@ -36,6 +36,8 @@ typedef struct __GLXFBConfigRec *GLXFBConfig;
#endif #endif
namespace CemuGL
{
#define GLFUNC(__type, __name) extern __type __name; #define GLFUNC(__type, __name) extern __type __name;
#define EGLFUNC(__type, __name) extern __type __name; #define EGLFUNC(__type, __name) extern __type __name;
#include "glFunctions.h" #include "glFunctions.h"
@ -213,6 +215,8 @@ static void glCompressedTextureSubImage3DWrapper(GLenum target, GLuint texture,
glBindTexture(target, originalTexture); glBindTexture(target, originalTexture);
} }
}
using namespace CemuGL;
// this prevents Windows GL.h from being included: // this prevents Windows GL.h from being included:
#define __gl_h_ #define __gl_h_
#define __GL_H__ #define __GL_H__

View file

@ -188,15 +188,20 @@ std::vector<IAudioAPI::DeviceDescriptionPtr> CubebAPI::GetDevices()
return {}; return {};
std::vector<DeviceDescriptionPtr> result; std::vector<DeviceDescriptionPtr> result;
result.reserve(devices.count); result.reserve(devices.count + 1); // Reserve space for the default device
// Add the default device to the list
auto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, "default", L"Default Device");
result.emplace_back(defaultDevice);
for (size_t i = 0; i < devices.count; ++i) for (size_t i = 0; i < devices.count; ++i)
{ {
//const auto& device = devices.device[i]; // const auto& device = devices.device[i];
if (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED) if (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED)
{ {
auto device = std::make_shared<CubebDeviceDescription>(devices.device[i].devid, devices.device[i].device_id, auto device = std::make_shared<CubebDeviceDescription>(devices.device[i].devid, devices.device[i].device_id,
boost::nowide::widen( boost::nowide::widen(
devices.device[i].friendly_name)); devices.device[i].friendly_name));
result.emplace_back(device); result.emplace_back(device);
} }
} }

View file

@ -180,15 +180,20 @@ std::vector<IAudioInputAPI::DeviceDescriptionPtr> CubebInputAPI::GetDevices()
return {}; return {};
std::vector<DeviceDescriptionPtr> result; std::vector<DeviceDescriptionPtr> result;
result.reserve(devices.count); result.reserve(devices.count + 1); // Reserve space for the default device
// Add the default device to the list
auto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, "default", L"Default Device");
result.emplace_back(defaultDevice);
for (size_t i = 0; i < devices.count; ++i) for (size_t i = 0; i < devices.count; ++i)
{ {
//const auto& device = devices.device[i]; // const auto& device = devices.device[i];
if (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED) if (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED)
{ {
auto device = std::make_shared<CubebDeviceDescription>(devices.device[i].devid, devices.device[i].device_id, auto device = std::make_shared<CubebDeviceDescription>(devices.device[i].devid, devices.device[i].device_id,
boost::nowide::widen( boost::nowide::widen(
devices.device[i].friendly_name)); devices.device[i].friendly_name));
result.emplace_back(device); result.emplace_back(device);
} }
} }

View file

@ -174,8 +174,6 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
if (vm.count("nsight")) if (vm.count("nsight"))
s_nsight_mode = vm["nsight"].as<bool>(); s_nsight_mode = vm["nsight"].as<bool>();
if (vm.count("legacy"))
s_force_intel_legacy = vm["legacy"].as<bool>();
if(vm.count("force-interpreter")) if(vm.count("force-interpreter"))
s_force_interpreter = vm["force-interpreter"].as<bool>(); s_force_interpreter = vm["force-interpreter"].as<bool>();

View file

@ -24,7 +24,6 @@ public:
static bool GDBStubEnabled() { return s_enable_gdbstub; } static bool GDBStubEnabled() { return s_enable_gdbstub; }
static bool NSightModeEnabled() { return s_nsight_mode; } static bool NSightModeEnabled() { return s_nsight_mode; }
static bool ForceIntelLegacyEnabled() { return s_force_intel_legacy; }
static bool ForceInterpreter() { return s_force_interpreter; }; static bool ForceInterpreter() { return s_force_interpreter; };
@ -44,7 +43,6 @@ private:
inline static bool s_enable_gdbstub = false; inline static bool s_enable_gdbstub = false;
inline static bool s_nsight_mode = false; inline static bool s_nsight_mode = false;
inline static bool s_force_intel_legacy = false;
inline static bool s_force_interpreter = false; inline static bool s_force_interpreter = false;

View file

@ -59,33 +59,44 @@ bool CemuApp::OnInit()
fs::path user_data_path, config_path, cache_path, data_path; fs::path user_data_path, config_path, cache_path, data_path;
auto standardPaths = wxStandardPaths::Get(); auto standardPaths = wxStandardPaths::Get();
fs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath())); fs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));
#ifdef PORTABLE
#if MACOS_BUNDLE // Try a portable path first, if it exists.
exePath = exePath.parent_path().parent_path().parent_path(); user_data_path = config_path = cache_path = data_path = exePath.parent_path() / "portable";
#if BOOST_OS_MACOS
// If run from an app bundle, use its parent directory.
fs::path appPath = exePath.parent_path().parent_path().parent_path();
if (appPath.extension() == ".app")
user_data_path = config_path = cache_path = data_path = appPath.parent_path() / "portable";
#endif #endif
user_data_path = config_path = cache_path = data_path = exePath.parent_path();
#else if (!fs::exists(user_data_path))
SetAppName("Cemu");
wxString appName=GetAppName();
#if BOOST_OS_LINUX
standardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG);
auto getEnvDir = [&](const wxString& varName, const wxString& defaultValue)
{ {
wxString dir; #if BOOST_OS_WINDOWS
if (!wxGetEnv(varName, &dir) || dir.empty()) user_data_path = config_path = cache_path = data_path = exePath.parent_path();
return defaultValue; #else
return dir; SetAppName("Cemu");
}; wxString appName=GetAppName();
wxString homeDir=wxFileName::GetHomeDir(); #if BOOST_OS_LINUX
user_data_path = (getEnvDir(wxS("XDG_DATA_HOME"), homeDir + wxS("/.local/share")) + "/" + appName).ToStdString(); standardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG);
config_path = (getEnvDir(wxS("XDG_CONFIG_HOME"), homeDir + wxS("/.config")) + "/" + appName).ToStdString(); auto getEnvDir = [&](const wxString& varName, const wxString& defaultValue)
#else {
user_data_path = config_path = standardPaths.GetUserDataDir().ToStdString(); wxString dir;
#endif if (!wxGetEnv(varName, &dir) || dir.empty())
data_path = standardPaths.GetDataDir().ToStdString(); return defaultValue;
cache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString(); return dir;
cache_path /= appName.ToStdString(); };
wxString homeDir=wxFileName::GetHomeDir();
user_data_path = (getEnvDir(wxS("XDG_DATA_HOME"), homeDir + wxS("/.local/share")) + "/" + appName).ToStdString();
config_path = (getEnvDir(wxS("XDG_CONFIG_HOME"), homeDir + wxS("/.config")) + "/" + appName).ToStdString();
#else
user_data_path = config_path = standardPaths.GetUserDataDir().ToStdString();
#endif #endif
data_path = standardPaths.GetDataDir().ToStdString();
cache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString();
cache_path /= appName.ToStdString();
#endif
}
auto failed_write_access = ActiveSettings::LoadOnce(exePath, user_data_path, config_path, cache_path, data_path); auto failed_write_access = ActiveSettings::LoadOnce(exePath, user_data_path, config_path, cache_path, data_path);
for (auto&& path : failed_write_access) for (auto&& path : failed_write_access)
wxMessageBox(formatWxString(_("Cemu can't write to {}!"), wxString::FromUTF8(_pathToUtf8(path))), wxMessageBox(formatWxString(_("Cemu can't write to {}!"), wxString::FromUTF8(_pathToUtf8(path))),

View file

@ -1019,8 +1019,11 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
default: default:
cemu_assert_debug(false); cemu_assert_debug(false);
} }
m_game_list->DeleteCachedStrings(); if (m_game_list)
m_game_list->ReloadGameEntries(false); {
m_game_list->DeleteCachedStrings();
m_game_list->ReloadGameEntries(false);
}
g_config.Save(); g_config.Save();
} }
@ -1485,6 +1488,19 @@ void MainWindow::OnKeyUp(wxKeyEvent& event)
g_window_info.has_screenshot_request = true; // async screenshot request g_window_info.has_screenshot_request = true; // async screenshot request
} }
void MainWindow::OnKeyDown(wxKeyEvent& event)
{
if ((event.AltDown() && event.GetKeyCode() == WXK_F4) ||
(event.CmdDown() && event.GetKeyCode() == 'Q'))
{
Close(true);
}
else
{
event.Skip();
}
}
void MainWindow::OnChar(wxKeyEvent& event) void MainWindow::OnChar(wxKeyEvent& event)
{ {
if (swkbd_hasKeyboardInputHook()) if (swkbd_hasKeyboardInputHook())
@ -1590,6 +1606,7 @@ void MainWindow::CreateCanvas()
// key events // key events
m_render_canvas->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this); m_render_canvas->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this);
m_render_canvas->Bind(wxEVT_KEY_DOWN, &MainWindow::OnKeyDown, this);
m_render_canvas->Bind(wxEVT_CHAR, &MainWindow::OnChar, this); m_render_canvas->Bind(wxEVT_CHAR, &MainWindow::OnChar, this);
m_render_canvas->SetDropTarget(new wxAmiiboDropTarget(this)); m_render_canvas->SetDropTarget(new wxAmiiboDropTarget(this));
@ -2145,6 +2162,14 @@ void MainWindow::RecreateMenu()
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE, _("&Portuguese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::PT); optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE, _("&Portuguese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::PT);
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN, _("&Russian"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::RU); optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN, _("&Russian"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::RU);
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, _("&Taiwanese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::TW); optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, _("&Taiwanese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::TW);
if(IsGameLaunched())
{
auto items = optionsConsoleLanguageMenu->GetMenuItems();
for (auto& item : items)
{
item->Enable(false);
}
}
// options submenu // options submenu
wxMenu* optionsMenu = new wxMenu(); wxMenu* optionsMenu = new wxMenu();

View file

@ -124,6 +124,7 @@ public:
void OnSetWindowTitle(wxCommandEvent& event); void OnSetWindowTitle(wxCommandEvent& event);
void OnKeyUp(wxKeyEvent& event); void OnKeyUp(wxKeyEvent& event);
void OnKeyDown(wxKeyEvent& event);
void OnChar(wxKeyEvent& event); void OnChar(wxKeyEvent& event);
void OnToolsInput(wxCommandEvent& event); void OnToolsInput(wxCommandEvent& event);

View file

@ -17,6 +17,8 @@
#include <wx/imagpng.h> #include <wx/imagpng.h>
#include <wx/string.h> #include <wx/string.h>
#include <wx/utils.h> #include <wx/utils.h>
#include <wx/clipbrd.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp> #include <boost/tokenizer.hpp>
@ -546,7 +548,12 @@ enum ContextMenuEntries
kContextMenuStyleList, kContextMenuStyleList,
kContextMenuStyleIcon, kContextMenuStyleIcon,
kContextMenuStyleIconSmall, kContextMenuStyleIconSmall,
kContextMenuCreateShortcut
kContextMenuCreateShortcut,
kContextMenuCopyTitleName,
kContextMenuCopyTitleId,
kContextMenuCopyTitleImage
}; };
void wxGameList::OnContextMenu(wxContextMenuEvent& event) void wxGameList::OnContextMenu(wxContextMenuEvent& event)
{ {
@ -591,6 +598,10 @@ void wxGameList::OnContextMenu(wxContextMenuEvent& event)
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS #if BOOST_OS_LINUX || BOOST_OS_WINDOWS
menu.Append(kContextMenuCreateShortcut, _("&Create shortcut")); menu.Append(kContextMenuCreateShortcut, _("&Create shortcut"));
#endif #endif
menu.AppendSeparator();
menu.Append(kContextMenuCopyTitleName, _("&Copy Title Name"));
menu.Append(kContextMenuCopyTitleId, _("&Copy Title ID"));
menu.Append(kContextMenuCopyTitleImage, _("&Copy Title Image"));
menu.AppendSeparator(); menu.AppendSeparator();
} }
} }
@ -711,10 +722,44 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
break; break;
} }
case kContextMenuCreateShortcut: case kContextMenuCreateShortcut:
{
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS #if BOOST_OS_LINUX || BOOST_OS_WINDOWS
CreateShortcut(gameInfo); CreateShortcut(gameInfo);
#endif #endif
break; break;
}
case kContextMenuCopyTitleName:
{
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(gameInfo.GetTitleName()));
wxTheClipboard->Close();
}
break;
}
case kContextMenuCopyTitleId:
{
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(fmt::format("{:016x}", gameInfo.GetBaseTitleId())));
wxTheClipboard->Close();
}
break;
}
case kContextMenuCopyTitleImage:
{
if (wxTheClipboard->Open())
{
int icon_large;
int icon_small;
if (!QueryIconForTitle(title_id, icon_large, icon_small))
break;
auto icon = m_image_list->GetBitmap(icon_large);
wxTheClipboard->SetData(new wxBitmapDataObject(icon));
wxTheClipboard->Close();
}
break;
}
} }
} }
} }
@ -1042,7 +1087,7 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
const auto region_text = fmt::format("{}", gameInfo.GetRegion()); const auto region_text = fmt::format("{}", gameInfo.GetRegion());
SetItem(index, ColumnRegion, wxGetTranslation(region_text)); SetItem(index, ColumnRegion, wxGetTranslation(region_text));
SetItem(index, ColumnTitleID, fmt::format("{:016x}", titleId)); SetItem(index, ColumnTitleID, fmt::format("{:016x}", baseTitleId));
} }
else if (m_style == Style::kIcons) else if (m_style == Style::kIcons)
{ {
@ -1149,6 +1194,7 @@ void wxGameList::RemoveCache(const std::list<fs::path>& cachePaths, const std::s
void wxGameList::AsyncWorkerThread() void wxGameList::AsyncWorkerThread()
{ {
SetThreadName("GameListWorker");
while (m_async_worker_active) while (m_async_worker_active)
{ {
m_async_task_count.decrementWithWait(); m_async_task_count.decrementWithWait();

View file

@ -1143,7 +1143,7 @@ bool wxTitleManagerList::SortFunc(int column, const Type_t& v1, const Type_t& v2
// check column: title id -> type -> path // check column: title id -> type -> path
if (column == ColumnTitleId) if (column == ColumnTitleId)
{ {
// ensure strong ordering -> use type since only one entry should be now (should be changed if every save for every user is displayed spearately?) // ensure strong ordering -> use type since only one entry should be now (should be changed if every save for every user is displayed separately?)
if (entry1.title_id == entry2.title_id) if (entry1.title_id == entry2.title_id)
return SortFunc(ColumnType, v1, v2); return SortFunc(ColumnType, v1, v2);
@ -1159,7 +1159,7 @@ bool wxTitleManagerList::SortFunc(int column, const Type_t& v1, const Type_t& v2
} }
else if (column == ColumnType) else if (column == ColumnType)
{ {
if(std::underlying_type_t<EntryType>(entry1.type) == std::underlying_type_t<EntryType>(entry2.type)) if(entry1.type == entry2.type)
return SortFunc(-1, v1, v2); return SortFunc(-1, v1, v2);
return std::underlying_type_t<EntryType>(entry1.type) < std::underlying_type_t<EntryType>(entry2.type); return std::underlying_type_t<EntryType>(entry1.type) < std::underlying_type_t<EntryType>(entry2.type);
@ -1178,6 +1178,13 @@ bool wxTitleManagerList::SortFunc(int column, const Type_t& v1, const Type_t& v2
return std::underlying_type_t<EntryType>(entry1.region) < std::underlying_type_t<EntryType>(entry2.region); return std::underlying_type_t<EntryType>(entry1.region) < std::underlying_type_t<EntryType>(entry2.region);
} }
else if (column == ColumnFormat)
{
if(entry1.format == entry2.format)
return SortFunc(ColumnType, v1, v2);
return std::underlying_type_t<EntryType>(entry1.format) < std::underlying_type_t<EntryType>(entry2.format);
}
return false; return false;
} }

View file

@ -37,7 +37,7 @@ void _wxLaunch()
void gui_create() void gui_create()
{ {
SetThreadName("MainThread"); SetThreadName("cemu");
#if BOOST_OS_WINDOWS #if BOOST_OS_WINDOWS
// on Windows wxWidgets there is a bug where wxDirDialog->ShowModal will deadlock in Windows internals somehow // on Windows wxWidgets there is a bug where wxDirDialog->ShowModal will deadlock in Windows internals somehow
// moving the UI thread off the main thread fixes this // moving the UI thread off the main thread fixes this
@ -93,10 +93,6 @@ void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps)
const char* graphicMode = "[Generic]"; const char* graphicMode = "[Generic]";
if (LatteGPUState.glVendor == GLVENDOR_AMD) if (LatteGPUState.glVendor == GLVENDOR_AMD)
graphicMode = "[AMD GPU]"; graphicMode = "[AMD GPU]";
else if (LatteGPUState.glVendor == GLVENDOR_INTEL_LEGACY)
graphicMode = "[Intel GPU - Legacy]";
else if (LatteGPUState.glVendor == GLVENDOR_INTEL_NOLEGACY)
graphicMode = "[Intel GPU]";
else if (LatteGPUState.glVendor == GLVENDOR_INTEL) else if (LatteGPUState.glVendor == GLVENDOR_INTEL)
graphicMode = "[Intel GPU]"; graphicMode = "[Intel GPU]";
else if (LatteGPUState.glVendor == GLVENDOR_NVIDIA) else if (LatteGPUState.glVendor == GLVENDOR_NVIDIA)

View file

@ -245,18 +245,13 @@ static void check_vk_result(VkResult err)
static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage) static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)
{ {
VulkanRenderer* vkRenderer = VulkanRenderer::GetInstance(); ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
vkDeviceWaitIdle(v->Device); // make sure previously created buffer is not in use anymore
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err; VkResult err;
if (buffer != VK_NULL_HANDLE) if (buffer != VK_NULL_HANDLE)
{ vkDestroyBuffer(v->Device, buffer, v->Allocator);
vkRenderer->destroyBuffer(buffer);
}
if (buffer_memory != VK_NULL_HANDLE) if (buffer_memory != VK_NULL_HANDLE)
{ vkFreeMemory(v->Device, buffer_memory, v->Allocator);
vkRenderer->destroyDeviceMemory(buffer_memory);
}
VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment; VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;
VkBufferCreateInfo buffer_info = {}; VkBufferCreateInfo buffer_info = {};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;

View file

@ -934,7 +934,7 @@ std::optional<glm::ivec2> InputManager::get_right_down_mouse_info(bool* is_pad)
void InputManager::update_thread() void InputManager::update_thread()
{ {
SetThreadName("InputManager::update_thread"); SetThreadName("Input_update");
while (!m_update_thread_shutdown.load(std::memory_order::relaxed)) while (!m_update_thread_shutdown.load(std::memory_order::relaxed))
{ {
std::shared_lock lock(m_mutex); std::shared_lock lock(m_mutex);

View file

@ -250,7 +250,7 @@ MotionSample DSUControllerProvider::get_motion_sample(uint8_t index) const
void DSUControllerProvider::reader_thread() void DSUControllerProvider::reader_thread()
{ {
SetThreadName("DSUControllerProvider::reader_thread"); SetThreadName("DSU-reader");
bool first_read = true; bool first_read = true;
while (m_running.load(std::memory_order_relaxed)) while (m_running.load(std::memory_order_relaxed))
{ {
@ -383,7 +383,7 @@ void DSUControllerProvider::reader_thread()
void DSUControllerProvider::writer_thread() void DSUControllerProvider::writer_thread()
{ {
SetThreadName("DSUControllerProvider::writer_thread"); SetThreadName("DSU-writer");
while (m_running.load(std::memory_order_relaxed)) while (m_running.load(std::memory_order_relaxed))
{ {
std::unique_lock lock(m_writer_mutex); std::unique_lock lock(m_writer_mutex);

View file

@ -124,7 +124,7 @@ MotionSample SDLControllerProvider::motion_sample(int diid)
void SDLControllerProvider::event_thread() void SDLControllerProvider::event_thread()
{ {
SetThreadName("SDLControllerProvider::event_thread"); SetThreadName("SDL_events");
while (m_running.load(std::memory_order_relaxed)) while (m_running.load(std::memory_order_relaxed))
{ {
SDL_Event event{}; SDL_Event event{};

View file

@ -143,7 +143,7 @@ WiimoteControllerProvider::WiimoteState WiimoteControllerProvider::get_state(siz
void WiimoteControllerProvider::reader_thread() void WiimoteControllerProvider::reader_thread()
{ {
SetThreadName("WiimoteControllerProvider::reader_thread"); SetThreadName("Wiimote-reader");
std::chrono::steady_clock::time_point lastCheck = {}; std::chrono::steady_clock::time_point lastCheck = {};
while (m_running.load(std::memory_order_relaxed)) while (m_running.load(std::memory_order_relaxed))
{ {
@ -878,7 +878,7 @@ void WiimoteControllerProvider::set_motion_plus(size_t index, bool state)
void WiimoteControllerProvider::writer_thread() void WiimoteControllerProvider::writer_thread()
{ {
SetThreadName("WiimoteControllerProvider::writer_thread"); SetThreadName("Wiimote-writer");
while (m_running.load(std::memory_order_relaxed)) while (m_running.load(std::memory_order_relaxed))
{ {
std::unique_lock writer_lock(m_writer_mutex); std::unique_lock writer_lock(m_writer_mutex);

View file

@ -155,7 +155,9 @@ void SetThreadName(const char* name)
#elif BOOST_OS_MACOS #elif BOOST_OS_MACOS
pthread_setname_np(name); pthread_setname_np(name);
#else #else
pthread_setname_np(pthread_self(), name); if(std::strlen(name) > 15)
cemuLog_log(LogType::Force, "Truncating thread name {} because it was longer than 15 characters", name);
pthread_setname_np(pthread_self(), std::string{name}.substr(0,15).c_str());
#endif #endif
} }