mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-12 01:36:58 +00:00
Merge branch 'main' into metal
This commit is contained in:
commit
bdecf3c00a
99 changed files with 3886 additions and 2698 deletions
39
.github/workflows/build.yml
vendored
39
.github/workflows/build.yml
vendored
|
|
@ -13,10 +13,22 @@ on:
|
|||
env:
|
||||
VCPKG_ROOT: "${{github.workspace}}/dependencies/vcpkg"
|
||||
VCPKG_BINARY_SOURCES: 'clear;nuget,GitHub,readwrite'
|
||||
VCPKG_FORCE_DOWNLOADED_BINARIES: true
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
runs-on: ubuntu-22.04
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
arch: x64
|
||||
- os: ubuntu-22.04-arm
|
||||
arch: arm
|
||||
|
||||
name: build-ubuntu-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -41,11 +53,6 @@ jobs:
|
|||
sudo apt update -qq
|
||||
sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libudev-dev nasm ninja-build libbluetooth-dev
|
||||
|
||||
- name: "Setup cmake"
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
with:
|
||||
cmake-version: '3.29.0'
|
||||
|
||||
- name: "Bootstrap vcpkg"
|
||||
run: |
|
||||
bash ./dependencies/vcpkg/bootstrap-vcpkg.sh
|
||||
|
|
@ -78,11 +85,21 @@ jobs:
|
|||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
name: cemu-bin-linux-${{ matrix.arch }}
|
||||
path: ./bin/Cemu
|
||||
|
||||
build-appimage:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
arch: x64
|
||||
- os: ubuntu-22.04-arm
|
||||
arch: arm
|
||||
|
||||
name: build-appimage-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: build-ubuntu
|
||||
steps:
|
||||
- name: Checkout Upstream Repo
|
||||
|
|
@ -90,7 +107,7 @@ jobs:
|
|||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
name: cemu-bin-linux-${{ matrix.arch }}
|
||||
path: bin
|
||||
|
||||
- name: "Install system dependencies"
|
||||
|
|
@ -102,12 +119,12 @@ jobs:
|
|||
run: |
|
||||
export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH"
|
||||
export DEPLOY_GTK_VERSION=3
|
||||
dist/linux/appimage.sh
|
||||
dist/linux/appimage.sh ${{ runner.arch }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cemu-appimage-x64
|
||||
name: cemu-appimage-${{ matrix.arch }}
|
||||
path: artifacts
|
||||
|
||||
build-windows:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ project(wxwidgets-example)
|
|||
add_executable(main WIN32 popup.cpp)
|
||||
|
||||
find_package(wxWidgets REQUIRED)
|
||||
target_compile_features(main PRIVATE cxx_std_11)
|
||||
target_compile_definitions(main PRIVATE ${wxWidgets_DEFINITIONS} "$<$<CONFIG:DEBUG>:${wxWidgets_DEFINITIONS_DEBUG}>")
|
||||
target_include_directories(main PRIVATE ${wxWidgets_INCLUDE_DIRS})
|
||||
target_link_libraries(main PRIVATE ${wxWidgets_LIBRARIES})
|
||||
|
|
@ -13,6 +14,7 @@ add_executable(main2 WIN32 popup.cpp)
|
|||
|
||||
find_package(wxWidgets CONFIG REQUIRED)
|
||||
target_link_libraries(main2 PRIVATE wx::core wx::base)
|
||||
target_compile_features(main2 PRIVATE cxx_std_11)
|
||||
|
||||
option(USE_WXRC "Use the wxrc resource compiler" ON)
|
||||
if(USE_WXRC)
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp
|
||||
index 2b9e0d7f7e..7eab8b37df 100644
|
||||
--- a/src/msw/listctrl.cpp
|
||||
+++ b/src/msw/listctrl.cpp
|
||||
@@ -3110,6 +3110,11 @@ bool HandleSubItemPrepaint(wxListCtrl* listctrl, LPNMLVCUSTOMDRAW pLVCD, HFONT h
|
||||
|
||||
if ( it.iImage != -1 )
|
||||
{
|
||||
+ if ( !listctrl->HasCheckBoxes() )
|
||||
+ {
|
||||
+ rc.left -= 6;
|
||||
+ }
|
||||
+
|
||||
const int yImage = rc.top + ((rc.bottom - rc.top) / 2 - hImage / 2);
|
||||
ImageList_Draw(himl, it.iImage, hdc, rc.left, yImage,
|
||||
nmcd.uItemState & CDIS_SELECTED ? ILD_SELECTED
|
||||
@@ -3235,7 +3240,7 @@ void HandleItemPaint(wxListCtrl* listctrl, LPNMLVCUSTOMDRAW pLVCD, HFONT hfont)
|
||||
// do not draw item background colour under the checkbox/image
|
||||
RECT rcIcon;
|
||||
wxGetListCtrlItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, LVIR_ICON, rcIcon);
|
||||
- if ( !::IsRectEmpty(&rcIcon) )
|
||||
+ if ( !::IsRectEmpty(&rcIcon) && listctrl->HasCheckBoxes() )
|
||||
rc.left = rcIcon.right + listctrl->FromDIP(GAP_BETWEEN_CHECKBOX_AND_TEXT);
|
||||
}
|
||||
|
||||
|
|
@ -1,39 +1,45 @@
|
|||
diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake
|
||||
index f044d22d4d..48fc5ad072 100644
|
||||
index 4ed7b264ef..195d776aeb 100644
|
||||
--- a/build/cmake/init.cmake
|
||||
+++ b/build/cmake/init.cmake
|
||||
@@ -198,7 +198,7 @@ if(WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
-if(WIN32_MSVC_NAMING)
|
||||
+if(0)
|
||||
@@ -201,11 +201,11 @@ endif()
|
||||
wx_get_install_dir(include)
|
||||
if(WIN32_MSVC_NAMING)
|
||||
if(wxBUILD_SHARED)
|
||||
set(lib_suffix "_dll")
|
||||
- set(lib_suffix "_dll")
|
||||
+ # set(lib_suffix "_dll")
|
||||
else()
|
||||
- set(lib_suffix "_lib")
|
||||
+ # set(lib_suffix "_lib")
|
||||
endif()
|
||||
- set(wxPLATFORM_LIB_DIR "${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}${lib_suffix}")
|
||||
+ # set(wxPLATFORM_LIB_DIR "${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}${lib_suffix}")
|
||||
set(wxINSTALL_INCLUDE_DIR "${include_dir}")
|
||||
else()
|
||||
wx_get_flavour(lib_flavour "-")
|
||||
diff --git a/build/cmake/install.cmake b/build/cmake/install.cmake
|
||||
index a373983043..2e1ace7bf9 100644
|
||||
index cbbefdebe9..8f2759d5ad 100644
|
||||
--- a/build/cmake/install.cmake
|
||||
+++ b/build/cmake/install.cmake
|
||||
@@ -63,7 +63,7 @@ else()
|
||||
|
||||
install(DIRECTORY DESTINATION "bin")
|
||||
@@ -66,7 +66,7 @@ else()
|
||||
wx_get_install_platform_dir(runtime)
|
||||
install(DIRECTORY DESTINATION "${runtime_dir}")
|
||||
install(CODE "execute_process( \
|
||||
- COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
||||
+ COMMAND ${CMAKE_COMMAND} -E copy \
|
||||
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/wx/config/${wxBUILD_FILE_ID}\" \
|
||||
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/wx-config\" \
|
||||
\"${CMAKE_INSTALL_PREFIX}/${library_dir}/wx/config/${wxBUILD_FILE_ID}\" \
|
||||
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${runtime_dir}/wx-config\" \
|
||||
)"
|
||||
diff --git a/build/cmake/utils/CMakeLists.txt b/build/cmake/utils/CMakeLists.txt
|
||||
index 15f4339ef9..f93849e025 100644
|
||||
index 608351ac42..d8110f9148 100644
|
||||
--- a/build/cmake/utils/CMakeLists.txt
|
||||
+++ b/build/cmake/utils/CMakeLists.txt
|
||||
@@ -39,7 +39,7 @@ if(wxUSE_XRC)
|
||||
@@ -40,7 +40,7 @@ if(wxUSE_XRC)
|
||||
|
||||
# Don't use wx_install() here to preserve escaping.
|
||||
install(CODE "execute_process( \
|
||||
- COMMAND ${CMAKE_COMMAND} -E create_symlink \
|
||||
+ COMMAND ${CMAKE_COMMAND} -E copy \
|
||||
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/${wxrc_output_name}${EXE_SUFFIX}\" \
|
||||
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/wxrc${EXE_SUFFIX}\" \
|
||||
\"${CMAKE_INSTALL_PREFIX}/${runtime_dir}/${wxrc_output_name}${EXE_SUFFIX}\" \
|
||||
\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${runtime_dir}/wxrc${EXE_SUFFIX}\" \
|
||||
)"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
diff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in
|
||||
index b251109..60cf762 100644
|
||||
index 2f3a735d92..c134900764 100644
|
||||
--- a/build/cmake/wxWidgetsConfig.cmake.in
|
||||
+++ b/build/cmake/wxWidgetsConfig.cmake.in
|
||||
@@ -1,5 +1,8 @@
|
||||
@PACKAGE_INIT@
|
||||
@@ -155,6 +155,7 @@ foreach(libname @wxLIB_TARGETS@)
|
||||
endforeach()
|
||||
|
||||
+include(CMakeFindDependencyMacro)
|
||||
include(CMakeFindDependencyMacro)
|
||||
+find_dependency(NanoSVG CONFIG)
|
||||
+
|
||||
cmake_policy(PUSH)
|
||||
# Set policies to prevent warnings
|
||||
if(POLICY CMP0057)
|
||||
|
||||
if(TARGET wx::wxnet AND @wxUSE_WEBREQUEST_CURL@)
|
||||
# make sure CURL targets are available:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO wxWidgets/wxWidgets
|
||||
REF "v${VERSION}"
|
||||
SHA512 8ad17582c4ba721ffe76ada4bb8bd7bc4b050491220aca335fd0506a51354fb789d5bc3d965f0f459dc81784d6427c88272e2acc2099cddf73730231b5a16f62
|
||||
REF "bfd436b"
|
||||
SHA512 bd3fd6d0d0db3b6fa34eceae1119e21ffd2f62221dcd249f8b8b82a6e65d83a05101e4e1e4ca9b9c4d7937add73b113bb029b03b05d2c3d87d17c1922d800a24
|
||||
HEAD_REF master
|
||||
PATCHES
|
||||
install-layout.patch
|
||||
|
|
@ -12,9 +12,26 @@ vcpkg_from_github(
|
|||
fix-pcre2.patch
|
||||
gtk3-link-libraries.patch
|
||||
sdl2.patch
|
||||
fix-dark-mode-offset.patch
|
||||
)
|
||||
|
||||
# Submodule dependencies
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH lexilla_SOURCE_PATH
|
||||
REPO wxWidgets/lexilla
|
||||
REF "27c20a6ae5eebf418debeac0166052ed6fb653bc"
|
||||
SHA512 7e5de7f664509473b691af8261fca34c2687772faca7260eeba5f2984516e6f8edf88c27192e056c9dda996e2ad2c20f6d1dff1c4bd2f3c0d74852cb50ca424a
|
||||
HEAD_REF wx
|
||||
)
|
||||
file(COPY "${lexilla_SOURCE_PATH}/" DESTINATION "${SOURCE_PATH}/src/stc/lexilla")
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH scintilla_SOURCE_PATH
|
||||
REPO wxWidgets/scintilla
|
||||
REF "0b90f31ced23241054e8088abb50babe9a44ae67"
|
||||
SHA512 db1f3007f4bd8860fad0817b6cf87980a4b713777025128cf5caea8d6d17b6fafe23fd22ff6886d7d5a420f241d85b7502b85d7e52b4ddb0774edc4b0a0203e7
|
||||
HEAD_REF wx
|
||||
)
|
||||
file(COPY "${scintilla_SOURCE_PATH}/" DESTINATION "${SOURCE_PATH}/src/stc/scintilla")
|
||||
|
||||
vcpkg_check_features(
|
||||
OUT_FEATURE_OPTIONS FEATURE_OPTIONS
|
||||
FEATURES
|
||||
|
|
@ -52,14 +69,20 @@ if(VCPKG_TARGET_IS_WINDOWS)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if("webview" IN_LIST FEATURES AND VCPKG_LIBRARY_LINKAGE STREQUAL "static")
|
||||
list(APPEND OPTIONS -DwxUSE_WEBVIEW_EDGE_STATIC=ON)
|
||||
endif()
|
||||
|
||||
vcpkg_find_acquire_program(PKGCONFIG)
|
||||
|
||||
# This may be set to ON by users in a custom triplet.
|
||||
# The use of 'wxUSE_STL' and 'WXWIDGETS_USE_STD_CONTAINERS' (ON or OFF) are not API compatible
|
||||
# which is why they must be set in a custom triplet rather than a port feature.
|
||||
# The use of 'WXWIDGETS_USE_STD_CONTAINERS' (ON or OFF) is not API compatible
|
||||
# which is why it must be set in a custom triplet rather than a port feature.
|
||||
# For backwards compatibility, we also replace 'wxUSE_STL' (which no longer
|
||||
# exists) with 'wxUSE_STD_STRING_CONV_IN_WXSTRING' which still exists and was
|
||||
# set by `wxUSE_STL` previously.
|
||||
if(NOT DEFINED WXWIDGETS_USE_STL)
|
||||
set(WXWIDGETS_USE_STL OFF)
|
||||
set(WXWIDGETS_USE_STD_STRING_CONV_IN_WXSTRING OFF)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED WXWIDGETS_USE_STD_CONTAINERS)
|
||||
|
|
@ -70,19 +93,18 @@ vcpkg_cmake_configure(
|
|||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
OPTIONS
|
||||
${FEATURE_OPTIONS}
|
||||
-DwxUSE_STC=OFF
|
||||
-DwxUSE_REGEX=sys
|
||||
-DwxUSE_ZLIB=sys
|
||||
-DwxUSE_EXPAT=sys
|
||||
-DwxUSE_LIBJPEG=sys
|
||||
-DwxUSE_LIBPNG=sys
|
||||
-DwxUSE_LIBTIFF=sys
|
||||
-DwxUSE_LIBWEBP=sys
|
||||
-DwxUSE_NANOSVG=sys
|
||||
-DwxUSE_LIBWEBP=sys
|
||||
-DwxUSE_GLCANVAS=ON
|
||||
-DwxUSE_LIBGNOMEVFS=OFF
|
||||
-DwxUSE_LIBNOTIFY=OFF
|
||||
-DwxUSE_STD_STRING_CONV_IN_WXSTRING=${WXWIDGETS_USE_STD_STRING_CONV_IN_WXSTRING}
|
||||
-DwxUSE_STD_STRING_CONV_IN_WXSTRING=${WXWIDGETS_USE_STL}
|
||||
-DwxUSE_STD_CONTAINERS=${WXWIDGETS_USE_STD_CONTAINERS}
|
||||
-DwxUSE_UIACTIONSIMULATOR=OFF
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_GSPELL=ON
|
||||
|
|
@ -101,7 +123,7 @@ vcpkg_cmake_configure(
|
|||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/wxWidgets)
|
||||
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/wxWidgets-3.3)
|
||||
|
||||
# The CMake export is not ready for use: It lacks a config file.
|
||||
file(REMOVE_RECURSE
|
||||
|
|
@ -126,6 +148,11 @@ vcpkg_copy_pdbs()
|
|||
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/include/msvc")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/lib/mswu")
|
||||
if(VCPKG_BUILD_TYPE STREQUAL "release")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib/mswud")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE INCLUDES "${CURRENT_PACKAGES_DIR}/include/*.h")
|
||||
if(EXISTS "${CURRENT_PACKAGES_DIR}/lib/mswu/wx/setup.h")
|
||||
list(APPEND INCLUDES "${CURRENT_PACKAGES_DIR}/lib/mswu/wx/setup.h")
|
||||
|
|
@ -191,12 +218,30 @@ endif()
|
|||
|
||||
if("example" IN_LIST FEATURES)
|
||||
file(INSTALL
|
||||
"${CMAKE_CURRENT_LIST_DIR}/example/CMakeLists.txt"
|
||||
"${SOURCE_PATH}/samples/popup/popup.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/minimal_example/CMakeLists.txt"
|
||||
"${SOURCE_PATH}/samples/minimal/minimal.cpp"
|
||||
"${SOURCE_PATH}/samples/sample.xpm"
|
||||
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/example"
|
||||
"${SOURCE_PATH}/samples/sample.rc"
|
||||
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/minimal_example"
|
||||
)
|
||||
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/example/popup.cpp" "../sample.xpm" "sample.xpm")
|
||||
|
||||
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/minimal_example/minimal.cpp" "../sample.xpm" "sample.xpm")
|
||||
endif()
|
||||
|
||||
if("example" IN_LIST FEATURES)
|
||||
file(INSTALL
|
||||
"${CMAKE_CURRENT_LIST_DIR}/listctrl_example/CMakeLists.txt"
|
||||
"${SOURCE_PATH}/samples/listctrl/listtest.cpp"
|
||||
"${SOURCE_PATH}/samples/listctrl/listtest.h"
|
||||
"${SOURCE_PATH}/samples/listctrl/listtest.rc"
|
||||
"${SOURCE_PATH}/samples/sample.xpm"
|
||||
"${SOURCE_PATH}/samples/sample.rc"
|
||||
"${SOURCE_PATH}/samples/listctrl/bitmaps"
|
||||
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example"
|
||||
)
|
||||
|
||||
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example/listtest.cpp" "../sample.xpm" "sample.xpm")
|
||||
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example/listtest.rc" "../sample.rc" "sample.rc")
|
||||
endif()
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake
|
||||
index 5447d33..f5440b4 100644
|
||||
index 4ed7b264ef..9abf7c9d5d 100644
|
||||
--- a/build/cmake/init.cmake
|
||||
+++ b/build/cmake/init.cmake
|
||||
@@ -530,7 +530,9 @@ if(wxUSE_GUI)
|
||||
@@ -667,7 +667,9 @@ if(wxUSE_GUI)
|
||||
endif()
|
||||
|
||||
if(wxUSE_SOUND AND wxUSE_LIBSDL AND UNIX AND NOT APPLE)
|
||||
|
|
@ -12,12 +12,12 @@ index 5447d33..f5440b4 100644
|
|||
+ set(SDL2_LIBRARY SDL2::SDL2 CACHE INTERNAL "")
|
||||
if(NOT SDL2_FOUND)
|
||||
find_package(SDL)
|
||||
endif()
|
||||
mark_as_advanced(SDL_INCLUDE_DIR SDLMAIN_LIBRARY)
|
||||
diff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in
|
||||
index 60cf762..202a8c3 100644
|
||||
index c134900764..7bcb691074 100644
|
||||
--- a/build/cmake/wxWidgetsConfig.cmake.in
|
||||
+++ b/build/cmake/wxWidgetsConfig.cmake.in
|
||||
@@ -2,6 +2,9 @@
|
||||
@@ -156,6 +156,9 @@ endforeach()
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(NanoSVG CONFIG)
|
||||
|
|
@ -25,5 +25,5 @@ index 60cf762..202a8c3 100644
|
|||
+ find_dependency(SDL2 CONFIG)
|
||||
+endif()
|
||||
|
||||
cmake_policy(PUSH)
|
||||
# Set policies to prevent warnings
|
||||
if(TARGET wx::wxnet AND @wxUSE_WEBREQUEST_CURL@)
|
||||
# make sure CURL targets are available:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ set(WX_ROOT_DIR "${_vcpkg_wx_root}" CACHE INTERNAL "")
|
|||
unset(_vcpkg_wx_root)
|
||||
|
||||
if(WIN32)
|
||||
# Find all libs with "32" infix which is unknown to FindwxWidgets.cmake
|
||||
# Find all libs with "33" infix which is unknown to FindwxWidgets.cmake
|
||||
function(z_vcpkg_wxwidgets_find_base_library BASENAME)
|
||||
find_library(WX_${BASENAME}d wx${BASENAME}33ud NAMES wx${BASENAME}d PATHS "${wxWidgets_ROOT_DIR}/debug/lib" NO_DEFAULT_PATH)
|
||||
find_library(WX_${BASENAME} wx${BASENAME}33u NAMES wx${BASENAME} PATHS "${wxWidgets_ROOT_DIR}/lib" NO_DEFAULT_PATH REQUIRED)
|
||||
|
|
|
|||
16
dist/linux/appimage.sh
vendored
16
dist/linux/appimage.sh
vendored
|
|
@ -1,20 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ "$1" == 'X64' ]; then CPU_ARCH="x86_64"; else CPU_ARCH="aarch64"; fi
|
||||
|
||||
if [[ -z "${GITHUB_WORKSPACE}" ]]; then
|
||||
export GITHUB_WORKSPACE="."
|
||||
fi
|
||||
|
||||
curl -sSfLO "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||
curl -sSfLO "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-"${CPU_ARCH}".AppImage"
|
||||
chmod a+x linuxdeploy*.AppImage
|
||||
curl -sSfL https://github.com"$(curl https://github.com/probonopd/go-appimage/releases/expanded_assets/continuous | grep "mkappimage-.*-x86_64.AppImage" | head -n 1 | cut -d '"' -f 2)" -o mkappimage.AppImage
|
||||
curl -sSfL https://github.com"$(curl https://github.com/probonopd/go-appimage/releases/expanded_assets/continuous | grep "mkappimage-.*-"${CPU_ARCH}".AppImage" | head -n 1 | cut -d '"' -f 2)" -o mkappimage.AppImage
|
||||
chmod a+x mkappimage.AppImage
|
||||
curl -sSfLO "https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh"
|
||||
chmod a+x linuxdeploy-plugin-gtk.sh
|
||||
curl -sSfLO "https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh"
|
||||
chmod a+x linuxdeploy-plugin-checkrt.sh
|
||||
|
||||
if [[ ! -e /usr/lib/x86_64-linux-gnu ]]; then
|
||||
sed -i 's#lib\/x86_64-linux-gnu#lib64#g' linuxdeploy-plugin-gtk.sh
|
||||
if [[ ! -e /usr/lib/"${CPU_ARCH}"-linux-gnu ]]; then
|
||||
sed -i 's#lib\/"${CPU_ARCH}"-linux-gnu#lib64#g' linuxdeploy-plugin-gtk.sh
|
||||
fi
|
||||
|
||||
mkdir -p AppDir/usr/bin
|
||||
|
|
@ -32,11 +34,11 @@ cp -r bin/* AppDir/usr/share/Cemu
|
|||
mv AppDir/usr/share/Cemu/Cemu AppDir/usr/bin/
|
||||
chmod +x AppDir/usr/bin/Cemu
|
||||
|
||||
cp /usr/lib/x86_64-linux-gnu/{libsepol.so.1,libffi.so.7,libpcre.so.3,libGLU.so.1,libthai.so.0} AppDir/usr/lib
|
||||
cp /usr/lib/"${CPU_ARCH}"-linux-gnu/{libsepol.so.1,libffi.so.7,libpcre.so.3,libGLU.so.1,libthai.so.0} AppDir/usr/lib
|
||||
|
||||
export UPD_INFO="gh-releases-zsync|cemu-project|Cemu|ci|Cemu.AppImage.zsync"
|
||||
export NO_STRIP=1
|
||||
./linuxdeploy-x86_64.AppImage --appimage-extract-and-run \
|
||||
./linuxdeploy-"${CPU_ARCH}".AppImage --appimage-extract-and-run \
|
||||
--appdir="${GITHUB_WORKSPACE}"/AppDir/ \
|
||||
-d "${GITHUB_WORKSPACE}"/AppDir/info.cemu.Cemu.desktop \
|
||||
-i "${GITHUB_WORKSPACE}"/AppDir/info.cemu.Cemu.png \
|
||||
|
|
@ -54,4 +56,4 @@ echo -e "export LC_ALL=C\nexport FONTCONFIG_PATH=/etc/fonts" >> AppDir/apprun-ho
|
|||
VERSION="${GITVERSION}" ./mkappimage.AppImage --appimage-extract-and-run "${GITHUB_WORKSPACE}"/AppDir
|
||||
|
||||
mkdir -p "${GITHUB_WORKSPACE}"/artifacts/
|
||||
mv Cemu-"${GITVERSION}"-x86_64.AppImage "${GITHUB_WORKSPACE}"/artifacts/
|
||||
mv Cemu-"${GITVERSION}"-"${CPU_ARCH}".AppImage "${GITHUB_WORKSPACE}"/artifacts/
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ target_link_libraries(CemuBin PRIVATE
|
|||
CemuGui
|
||||
CemuInput
|
||||
CemuUtil
|
||||
OpenGL::GL
|
||||
SDL2::SDL2
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -238,8 +238,6 @@ add_library(CemuCafe
|
|||
IOSU/legacy/iosu_acp.h
|
||||
IOSU/legacy/iosu_act.cpp
|
||||
IOSU/legacy/iosu_act.h
|
||||
IOSU/legacy/iosu_boss.cpp
|
||||
IOSU/legacy/iosu_boss.h
|
||||
IOSU/legacy/iosu_crypto.cpp
|
||||
IOSU/legacy/iosu_crypto.h
|
||||
IOSU/legacy/iosu_fpd.cpp
|
||||
|
|
@ -252,6 +250,10 @@ add_library(CemuCafe
|
|||
IOSU/legacy/iosu_nim.h
|
||||
IOSU/nn/iosu_nn_service.cpp
|
||||
IOSU/nn/iosu_nn_service.h
|
||||
IOSU/nn/boss/boss_common.cpp
|
||||
IOSU/nn/boss/boss_common.h
|
||||
IOSU/nn/boss/boss_service.cpp
|
||||
IOSU/nn/boss/boss_service.h
|
||||
IOSU/PDM/iosu_pdm.cpp
|
||||
IOSU/PDM/iosu_pdm.h
|
||||
IOSU/ODM/iosu_odm.cpp
|
||||
|
|
@ -418,6 +420,7 @@ add_library(CemuCafe
|
|||
OS/libs/nn_ccr/nn_ccr.h
|
||||
OS/libs/nn_cmpt/nn_cmpt.cpp
|
||||
OS/libs/nn_cmpt/nn_cmpt.h
|
||||
OS/libs/nn_client_service.h
|
||||
OS/libs/nn_common.h
|
||||
OS/libs/nn_ec/nn_ec.cpp
|
||||
OS/libs/nn_ec/nn_ec.h
|
||||
|
|
@ -618,28 +621,17 @@ else()
|
|||
endif()
|
||||
|
||||
target_link_libraries(CemuCafe PRIVATE
|
||||
CemuAudio
|
||||
CemuCommon
|
||||
CemuComponents
|
||||
CemuConfig
|
||||
CemuGui
|
||||
CemuInput
|
||||
CemuResource
|
||||
CemuUtil
|
||||
imguiImpl
|
||||
Boost::headers
|
||||
Boost::nowide
|
||||
CURL::libcurl
|
||||
fmt::fmt
|
||||
${glslang_target}
|
||||
ih264d
|
||||
OpenSSL::Crypto
|
||||
OpenSSL::SSL
|
||||
PNG::PNG
|
||||
pugixml::pugixml
|
||||
ZArchive::zarchive
|
||||
imguiImpl
|
||||
pugixml::pugixml
|
||||
ZLIB::ZLIB
|
||||
zstd::zstd
|
||||
CURL::libcurl
|
||||
ih264d
|
||||
${glslang_target}
|
||||
PUBLIC
|
||||
OpenSSL::SSL
|
||||
)
|
||||
|
||||
if (ENABLE_WAYLAND)
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@
|
|||
#include "Cafe/IOSU/legacy/iosu_crypto.h"
|
||||
#include "Cafe/IOSU/legacy/iosu_mcp.h"
|
||||
#include "Cafe/IOSU/legacy/iosu_acp.h"
|
||||
#include "Cafe/IOSU/legacy/iosu_boss.h"
|
||||
#include "Cafe/IOSU/legacy/iosu_nim.h"
|
||||
#include "Cafe/IOSU/PDM/iosu_pdm.h"
|
||||
#include "Cafe/IOSU/ccr_nfc/iosu_ccr_nfc.h"
|
||||
#include "Cafe/IOSU/nn/boss/boss_service.h"
|
||||
|
||||
// IOSU initializer functions
|
||||
#include "Cafe/IOSU/kernel/iosu_kernel.h"
|
||||
|
|
@ -561,6 +561,7 @@ namespace CafeSystem
|
|||
iosu::fpd::GetModule(),
|
||||
iosu::pdm::GetModule(),
|
||||
iosu::ccr_nfc::GetModule(),
|
||||
iosu::boss::GetModule()
|
||||
};
|
||||
|
||||
// initialize all subsystems which are persistent and don't depend on a game running
|
||||
|
|
@ -599,7 +600,6 @@ namespace CafeSystem
|
|||
iosu::iosuMcp_init();
|
||||
iosu::mcp::Init();
|
||||
iosu::iosuAcp_init();
|
||||
iosu::boss_init();
|
||||
iosu::nim::Initialize();
|
||||
iosu::odm::Initialize();
|
||||
// init Cafe OS
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@ struct LatteGPUState_t
|
|||
uint32 contextControl1;
|
||||
// optional features
|
||||
bool allowFramebufferSizeOptimization{false}; // allow using scissor box as size hint to determine non-padded rendertarget size
|
||||
// draw context
|
||||
struct
|
||||
{
|
||||
uint32 numInstances;
|
||||
}drawContext;
|
||||
// stats
|
||||
uint32 frameCounter;
|
||||
uint32 flipCounter; // increased by one everytime a vsync + flip happens
|
||||
|
|
@ -54,6 +49,8 @@ struct LatteGPUState_t
|
|||
// temporary (replace with proper solution later)
|
||||
bool tvBufferUsesSRGB;
|
||||
bool drcBufferUsesSRGB;
|
||||
float tvGamma = 0.0f;
|
||||
float drcGamma = 0.0f;
|
||||
// draw state
|
||||
bool activeShaderHasError; // if try, at least one currently bound shader stage has an error and cannot be used for drawing
|
||||
bool repeatTextureInitialization; // if set during rendertarget or texture initialization, repeat the process (textures likely have been invalidated)
|
||||
|
|
|
|||
|
|
@ -62,16 +62,7 @@ public:
|
|||
{
|
||||
uint32 baseVertex = LatteGPUState.contextRegister[mmSQ_VTX_BASE_VTX_LOC];
|
||||
uint32 baseInstance = LatteGPUState.contextRegister[mmSQ_VTX_START_INST_LOC];
|
||||
uint32 numInstances = LatteGPUState.drawContext.numInstances;
|
||||
if (numInstances == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
if (GetAsyncKeyState('B'))
|
||||
{
|
||||
cemuLog_force("[executeDraw] {} Count {} BaseVertex {} BaseInstance {}", m_isFirstDraw?"Init":"Fast", count, baseVertex, baseInstance);
|
||||
}
|
||||
*/
|
||||
uint32 numInstances = LatteGPUState.contextNew.VGT_DMA_NUM_INSTANCES.get_NUM_INSTANCES();
|
||||
|
||||
if (!isAutoIndex)
|
||||
{
|
||||
|
|
@ -391,7 +382,10 @@ LatteCMDPtr LatteCP_itIndexType(LatteCMDPtr cmd, uint32 nWords)
|
|||
LatteCMDPtr LatteCP_itNumInstances(LatteCMDPtr cmd, uint32 nWords)
|
||||
{
|
||||
cemu_assert_debug(nWords == 1);
|
||||
LatteGPUState.drawContext.numInstances = LatteReadCMD();
|
||||
uint32 numInstances = LatteReadCMD();
|
||||
if (numInstances == 0)
|
||||
numInstances = 1;
|
||||
LatteGPUState.contextNew.VGT_DMA_NUM_INSTANCES.set_NUM_INSTANCES(numInstances);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
|
@ -690,9 +684,6 @@ LatteCMDPtr LatteCP_itDrawIndexAuto(LatteCMDPtr cmd, uint32 nWords, DrawPassCont
|
|||
cemu_assert_debug(nWords == 2);
|
||||
uint32 count = LatteReadCMD();
|
||||
uint32 ukn = LatteReadCMD();
|
||||
|
||||
if (LatteGPUState.drawContext.numInstances == 0)
|
||||
return cmd;
|
||||
LatteGPUState.currentDrawCallTick = GetTickCount();
|
||||
// todo - better way to identify compute drawcalls
|
||||
if ((LatteGPUState.contextRegister[mmSQ_CONFIG] >> 24) == 0xE4)
|
||||
|
|
@ -750,13 +741,7 @@ LatteCMDPtr LatteCP_itDrawImmediate(LatteCMDPtr cmd, uint32 nWords, DrawPassCont
|
|||
cemuLog_log(LogType::Force, "itDrawImmediate - Unsupported index type");
|
||||
return cmd;
|
||||
}
|
||||
// verify packet size
|
||||
if (nWords != (2 + numIndexU32s))
|
||||
debugBreakpoint();
|
||||
|
||||
uint32 baseVertex = LatteGPUState.contextRegister[mmSQ_VTX_BASE_VTX_LOC];
|
||||
uint32 baseInstance = LatteGPUState.contextRegister[mmSQ_VTX_START_INST_LOC];
|
||||
uint32 numInstances = LatteGPUState.drawContext.numInstances;
|
||||
cemu_assert_debug(nWords == (2 + numIndexU32s)); // verify packet size
|
||||
|
||||
drawPassCtx.executeDraw(count, false, _tempIndexArrayMPTR);
|
||||
return cmd;
|
||||
|
|
|
|||
|
|
@ -120,16 +120,6 @@ uint8* LatteTextureLoader_getInputLinearOptimized(LatteTextureLoaderCtx* texture
|
|||
|
||||
#define LatteTextureLoader_getInputLinearOptimized_(__textureLoader,__x,__y,__stepX,__stepY,__bpp,__sliceIndex,__numSlices,__sample,__pitch,__height) (textureLoader->inputData+((__x/__stepX) + __pitch * (__y/__stepY) + (__sliceIndex + __numSlices * __sample) * __height * __pitch)*(__bpp/8))
|
||||
|
||||
float SRGB_to_RGB(float cs)
|
||||
{
|
||||
float cl;
|
||||
if (cs <= 0.04045f)
|
||||
cl = cs / 12.92f;
|
||||
else
|
||||
cl = powf(((cs + 0.055f) / 1.055f), 2.4f);
|
||||
return cl;
|
||||
}
|
||||
|
||||
void decodeBC1Block(uint8* inputData, float* output4x4RGBA)
|
||||
{
|
||||
// read colors
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ void Latte_LoadInitialRegisters()
|
|||
{
|
||||
LatteGPUState.contextNew.CB_TARGET_MASK.set_MASK(0xFFFFFFFF);
|
||||
LatteGPUState.contextNew.VGT_MULTI_PRIM_IB_RESET_INDX.set_RESTART_INDEX(0xFFFFFFFF);
|
||||
LatteGPUState.contextNew.VGT_DMA_NUM_INSTANCES.set_NUM_INSTANCES(1);
|
||||
LatteGPUState.contextRegister[Latte::REGADDR::PA_CL_CLIP_CNTL] = 0;
|
||||
*(float*)&LatteGPUState.contextRegister[mmDB_DEPTH_CLEAR] = 1.0f;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,6 +445,7 @@ namespace Latte
|
|||
VGT_DMA_INDEX_TYPE = 0xA29F, // todo - verify offset
|
||||
|
||||
VGT_PRIMITIVEID_EN = 0xA2A1,
|
||||
VGT_DMA_NUM_INSTANCES = 0xA2A2,
|
||||
|
||||
VGT_MULTI_PRIM_IB_RESET_EN = 0xA2A5,
|
||||
|
||||
|
|
@ -977,6 +978,11 @@ float get_##__regname() const \
|
|||
LATTE_BITFIELD_BOOL(PRIMITIVEID_EN, 0);
|
||||
};
|
||||
|
||||
struct LATTE_VGT_DMA_NUM_INSTANCES : LATTEREG // 0xA2A2
|
||||
{
|
||||
LATTE_BITFIELD_FULL_TYPED(NUM_INSTANCES, uint32);
|
||||
};
|
||||
|
||||
struct LATTE_VGT_MULTI_PRIM_IB_RESET_EN : LATTEREG // 0xA2A5
|
||||
{
|
||||
LATTE_BITFIELD_BOOL(RESET_EN, 0);
|
||||
|
|
@ -1541,7 +1547,7 @@ struct LatteContextRegister
|
|||
/* +0x28A7C */ Latte::LATTE_VGT_DMA_INDEX_TYPE VGT_DMA_INDEX_TYPE;
|
||||
/* +0x28A80 */ uint32 ukn28A80;
|
||||
/* +0x28A84 */ Latte::LATTE_VGT_PRIMITIVEID_EN VGT_PRIMITIVEID_EN;
|
||||
/* +0x28A88 */ uint32 ukn28A88;
|
||||
/* +0x28A88 */ Latte::LATTE_VGT_DMA_NUM_INSTANCES VGT_DMA_NUM_INSTANCES;
|
||||
/* +0x28A8C */ uint32 ukn28A8C;
|
||||
/* +0x28A90 */ uint32 ukn28A90;
|
||||
/* +0x28A94 */ Latte::LATTE_VGT_MULTI_PRIM_IB_RESET_EN VGT_MULTI_PRIM_IB_RESET_EN;
|
||||
|
|
@ -1629,6 +1635,7 @@ static_assert(offsetof(LatteContextRegister, PA_SC_GENERIC_SCISSOR_TL) == Latte:
|
|||
static_assert(offsetof(LatteContextRegister, PA_SC_GENERIC_SCISSOR_BR) == Latte::REGADDR::PA_SC_GENERIC_SCISSOR_BR * 4);
|
||||
static_assert(offsetof(LatteContextRegister, VGT_MULTI_PRIM_IB_RESET_INDX) == Latte::REGADDR::VGT_MULTI_PRIM_IB_RESET_INDX * 4);
|
||||
static_assert(offsetof(LatteContextRegister, VGT_PRIMITIVEID_EN) == Latte::REGADDR::VGT_PRIMITIVEID_EN * 4);
|
||||
static_assert(offsetof(LatteContextRegister, VGT_DMA_NUM_INSTANCES) == Latte::REGADDR::VGT_DMA_NUM_INSTANCES * 4);
|
||||
static_assert(offsetof(LatteContextRegister, VGT_MULTI_PRIM_IB_RESET_EN) == Latte::REGADDR::VGT_MULTI_PRIM_IB_RESET_EN * 4);
|
||||
static_assert(offsetof(LatteContextRegister, VGT_INSTANCE_STEP_RATE_0) == Latte::REGADDR::VGT_INSTANCE_STEP_RATE_0 * 4);
|
||||
static_assert(offsetof(LatteContextRegister, VGT_INSTANCE_STEP_RATE_1) == Latte::REGADDR::VGT_INSTANCE_STEP_RATE_1 * 4);
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||
shader_unbind(RendererShader::ShaderType::kGeometry);
|
||||
shader_bind(shader->GetVertexShader());
|
||||
shader_bind(shader->GetFragmentShader());
|
||||
shader->SetUniformParameters(*texView, {imageWidth, imageHeight});
|
||||
shader->SetUniformParameters(*texView, {imageWidth, imageHeight}, padView);
|
||||
|
||||
// set viewport
|
||||
glViewportIndexedf(0, imageX, imageY, imageWidth, imageHeight);
|
||||
|
|
@ -620,13 +620,11 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, useLinearTexFilter ? GL_LINEAR : GL_NEAREST);
|
||||
texViewGL->samplerState.filterMag = 0xFFFFFFFF;
|
||||
|
||||
if ((!padView && !LatteGPUState.tvBufferUsesSRGB) || (padView && !LatteGPUState.drcBufferUsesSRGB))
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
uint16 indexData[6] = { 0,1,2,3,4,5 };
|
||||
glDrawRangeElements(GL_TRIANGLES, 0, 5, 6, GL_UNSIGNED_SHORT, indexData);
|
||||
|
||||
if ((!padView && !LatteGPUState.tvBufferUsesSRGB) || (padView && !LatteGPUState.drcBufferUsesSRGB))
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
// unbind texture
|
||||
|
|
|
|||
|
|
@ -227,6 +227,16 @@ sint32 RendererShaderGL::GetUniformLocation(const char* name)
|
|||
return glGetUniformLocation(m_program, name);
|
||||
}
|
||||
|
||||
void RendererShaderGL::SetUniform1i(sint32 location, sint32 value)
|
||||
{
|
||||
glProgramUniform1i(m_program, location, value);
|
||||
}
|
||||
|
||||
void RendererShaderGL::SetUniform1f(sint32 location, float value)
|
||||
{
|
||||
glProgramUniform1f(m_program, location, value);
|
||||
}
|
||||
|
||||
void RendererShaderGL::SetUniform2fv(sint32 location, void* data, sint32 count)
|
||||
{
|
||||
glProgramUniform2fv(m_program, location, count, (const GLfloat*)data);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ public:
|
|||
GLuint GetShaderObject() const { cemu_assert_debug(m_isCompiled); return m_shader_object; }
|
||||
|
||||
sint32 GetUniformLocation(const char* name) override;
|
||||
|
||||
void SetUniform1i(sint32 location, sint32 value) override;
|
||||
void SetUniform1f(sint32 location, float value) override;
|
||||
void SetUniform2fv(sint32 location, void* data, sint32 count) override;
|
||||
void SetUniform4iv(sint32 location, void* data, sint32 count) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#include "Cafe/HW/Latte/Renderer/RendererOuputShader.h"
|
||||
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
const std::string RendererOutputShader::s_copy_shader_source =
|
||||
R"(
|
||||
void main()
|
||||
void outputShader()
|
||||
{
|
||||
colorOut0 = vec4(texture(textureSrc, passUV).rgb,1.0);
|
||||
}
|
||||
|
|
@ -62,7 +63,7 @@ vec4 bcFilter(vec2 uv, vec4 texelSize)
|
|||
mix(sample1, sample0, sx), sy);
|
||||
}
|
||||
|
||||
void main(){
|
||||
void outputShader(){
|
||||
vec4 texelSize = vec4( 1.0 / textureSrcResolution.xy, textureSrcResolution.xy);
|
||||
colorOut0 = vec4(bcFilter(passUV, texelSize).rgb,1.0);
|
||||
}
|
||||
|
|
@ -172,7 +173,7 @@ vec3 BicubicHermiteTexture(vec2 uv, vec4 texelSize)
|
|||
return CubicHermite(CP0X, CP1X, CP2X, CP3X, frac.y);
|
||||
}
|
||||
|
||||
void main(){
|
||||
void outputShader(){
|
||||
vec4 texelSize = vec4( 1.0 / textureSrcResolution.xy, textureSrcResolution.xy);
|
||||
colorOut0 = vec4(BicubicHermiteTexture(passUV, texelSize), 1.0);
|
||||
}
|
||||
|
|
@ -267,14 +268,20 @@ RendererOutputShader::RendererOutputShader(const std::string& vertex_source, con
|
|||
m_uniformLocations[0].m_loc_textureSrcResolution = m_vertex_shader->GetUniformLocation("textureSrcResolution");
|
||||
m_uniformLocations[0].m_loc_nativeResolution = m_vertex_shader->GetUniformLocation("nativeResolution");
|
||||
m_uniformLocations[0].m_loc_outputResolution = m_vertex_shader->GetUniformLocation("outputResolution");
|
||||
m_uniformLocations[0].m_loc_applySRGBEncoding = m_vertex_shader->GetUniformLocation("applySRGBEncoding");
|
||||
m_uniformLocations[0].m_loc_targetGamma = m_fragment_shader->GetUniformLocation("targetGamma");
|
||||
m_uniformLocations[0].m_loc_displayGamma = m_fragment_shader->GetUniformLocation("displayGamma");
|
||||
|
||||
m_uniformLocations[1].m_loc_textureSrcResolution = m_fragment_shader->GetUniformLocation("textureSrcResolution");
|
||||
m_uniformLocations[1].m_loc_nativeResolution = m_fragment_shader->GetUniformLocation("nativeResolution");
|
||||
m_uniformLocations[1].m_loc_outputResolution = m_fragment_shader->GetUniformLocation("outputResolution");
|
||||
m_uniformLocations[1].m_loc_applySRGBEncoding = m_fragment_shader->GetUniformLocation("applySRGBEncoding");
|
||||
m_uniformLocations[1].m_loc_targetGamma = m_fragment_shader->GetUniformLocation("targetGamma");
|
||||
m_uniformLocations[1].m_loc_displayGamma = m_fragment_shader->GetUniformLocation("displayGamma");
|
||||
}
|
||||
}
|
||||
|
||||
void RendererOutputShader::SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& output_res) const
|
||||
void RendererOutputShader::SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& output_res, const bool padView) const
|
||||
{
|
||||
sint32 effectiveWidth, effectiveHeight;
|
||||
texture_view.baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0);
|
||||
|
|
@ -300,6 +307,22 @@ void RendererOutputShader::SetUniformParameters(const LatteTextureView& texture_
|
|||
res[1] = (float)output_res.y;
|
||||
shader->SetUniform2fv(locations.m_loc_outputResolution, res, 1);
|
||||
}
|
||||
|
||||
if (locations.m_loc_applySRGBEncoding != -1)
|
||||
{
|
||||
shader->SetUniform1i(locations.m_loc_applySRGBEncoding, padView ? LatteGPUState.drcBufferUsesSRGB : LatteGPUState.tvBufferUsesSRGB);
|
||||
}
|
||||
|
||||
if (locations.m_loc_targetGamma != -1)
|
||||
{
|
||||
shader->SetUniform1f(locations.m_loc_targetGamma, padView ? ActiveSettings::GetDRCGamma() : ActiveSettings::GetTVGamma());
|
||||
}
|
||||
|
||||
if (locations.m_loc_displayGamma != -1)
|
||||
{
|
||||
shader->SetUniform1f(locations.m_loc_displayGamma, GetConfig().userDisplayGamma);
|
||||
}
|
||||
|
||||
};
|
||||
setUniforms(m_vertex_shader.get(), m_uniformLocations[0]);
|
||||
setUniforms(m_fragment_shader.get(), m_uniformLocations[1]);
|
||||
|
|
@ -460,16 +483,52 @@ layout(push_constant) uniform pc {
|
|||
vec2 textureSrcResolution;
|
||||
vec2 nativeResolution;
|
||||
vec2 outputResolution;
|
||||
bool applySRGBEncoding; // true = app requested sRGB encoding
|
||||
float targetGamma;
|
||||
float displayGamma;
|
||||
};
|
||||
#else
|
||||
uniform vec2 textureSrcResolution;
|
||||
uniform vec2 nativeResolution;
|
||||
uniform vec2 outputResolution;
|
||||
uniform bool applySRGBEncoding;
|
||||
uniform float targetGamma;
|
||||
uniform float displayGamma;
|
||||
#endif
|
||||
|
||||
layout(location = 0) smooth in vec2 passUV;
|
||||
layout(binding = 0) uniform sampler2D textureSrc;
|
||||
layout(location = 0) out vec4 colorOut0;
|
||||
|
||||
float sRGBEncode(float linear)
|
||||
{
|
||||
if(linear <= 0.0031308)
|
||||
return 12.92f * linear;
|
||||
else
|
||||
return 1.055f * pow(linear, 1.0f / 2.4f) - 0.055f;
|
||||
|
||||
}
|
||||
|
||||
vec3 sRGBEncode(vec3 linear)
|
||||
{
|
||||
return vec3(sRGBEncode(linear.r), sRGBEncode(linear.g), sRGBEncode(linear.b));
|
||||
}
|
||||
|
||||
// fwd. declaration
|
||||
void outputShader();
|
||||
void main()
|
||||
{
|
||||
outputShader(); // sets colorOut0
|
||||
if(applySRGBEncoding)
|
||||
colorOut0 = vec4(sRGBEncode(colorOut0.rgb), 1.0f);
|
||||
|
||||
if (displayGamma > 0.0f)
|
||||
colorOut0 = pow(colorOut0, vec4(targetGamma / displayGamma) );
|
||||
else
|
||||
colorOut0 = vec4( sRGBEncode( pow(colorOut0.rgb, vec3(targetGamma)) ), 1.0f);
|
||||
|
||||
}
|
||||
|
||||
)" + shaderSrc;
|
||||
}
|
||||
void RendererOutputShader::InitializeStatic()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public:
|
|||
RendererOutputShader(const std::string& vertex_source, const std::string& fragment_source);
|
||||
virtual ~RendererOutputShader() = default;
|
||||
|
||||
void SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& output_res) const;
|
||||
void SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& output_res, const bool padView) const;
|
||||
|
||||
RendererShader* GetVertexShader() const
|
||||
{
|
||||
|
|
@ -56,6 +56,9 @@ protected:
|
|||
sint32 m_loc_textureSrcResolution = -1;
|
||||
sint32 m_loc_nativeResolution = -1;
|
||||
sint32 m_loc_outputResolution = -1;
|
||||
sint32 m_loc_applySRGBEncoding = -1;
|
||||
sint32 m_loc_targetGamma = -1;
|
||||
sint32 m_loc_displayGamma = -1;
|
||||
} m_uniformLocations[2]{};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ public:
|
|||
|
||||
virtual sint32 GetUniformLocation(const char* name) = 0;
|
||||
|
||||
virtual void SetUniform1i(sint32 location, sint32 value) = 0;
|
||||
virtual void SetUniform1f(sint32 location, float value) = 0;
|
||||
virtual void SetUniform2fv(sint32 location, void* data, sint32 count) = 0;
|
||||
virtual void SetUniform4iv(sint32 location, void* data, sint32 count) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ LatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM di
|
|||
if (vkCreateImage(m_vkr->GetLogicalDevice(), &imageInfo, nullptr, &vkObjTex->m_image) != VK_SUCCESS)
|
||||
m_vkr->UnrecoverableError("Failed to create texture image");
|
||||
|
||||
if (m_vkr->IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT)
|
||||
if (m_vkr->IsDebugMarkersEnabled())
|
||||
{
|
||||
VkDebugUtilsObjectNameInfoEXT objName{};
|
||||
objName.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
|
|
|
|||
|
|
@ -232,6 +232,16 @@ sint32 RendererShaderVk::GetUniformLocation(const char* name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void RendererShaderVk::SetUniform1i(sint32 location, sint32 value)
|
||||
{
|
||||
cemu_assert_suspicious();
|
||||
}
|
||||
|
||||
void RendererShaderVk::SetUniform1f(sint32 location, float value)
|
||||
{
|
||||
cemu_assert_suspicious();
|
||||
}
|
||||
|
||||
void RendererShaderVk::SetUniform2fv(sint32 location, void* data, sint32 count)
|
||||
{
|
||||
cemu_assert_suspicious();
|
||||
|
|
@ -261,7 +271,7 @@ void RendererShaderVk::CreateVkShaderModule(std::span<uint32> spirvBuffer)
|
|||
}
|
||||
|
||||
// set debug name
|
||||
if (vkr->IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT)
|
||||
if (vkr->IsDebugMarkersEnabled())
|
||||
{
|
||||
VkDebugUtilsObjectNameInfoEXT objName{};
|
||||
objName.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
|
|
@ -282,8 +292,10 @@ void RendererShaderVk::FinishCompilation()
|
|||
|
||||
void RendererShaderVk::CompileInternal(bool isRenderThread)
|
||||
{
|
||||
const bool compileWithDebugInfo = ((VulkanRenderer*)g_renderer.get())->IsTracingToolEnabled();
|
||||
|
||||
// try to retrieve SPIR-V module from cache
|
||||
if (s_isLoadingShadersVk && (m_isGameShader && !m_isGfxPackShader) && s_spirvCache)
|
||||
if (s_isLoadingShadersVk && (m_isGameShader && !m_isGfxPackShader) && s_spirvCache && !compileWithDebugInfo)
|
||||
{
|
||||
cemu_assert_debug(m_baseHash != 0);
|
||||
uint64 h1, h2;
|
||||
|
|
@ -319,21 +331,12 @@ void RendererShaderVk::CompileInternal(bool isRenderThread)
|
|||
Shader.setStrings(&cstr, 1);
|
||||
Shader.setEnvInput(glslang::EShSourceGlsl, state, glslang::EShClientVulkan, 100);
|
||||
Shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetClientVersion::EShTargetVulkan_1_1);
|
||||
|
||||
Shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetLanguageVersion::EShTargetSpv_1_3);
|
||||
|
||||
TBuiltInResource Resources = GetDefaultBuiltInResource();
|
||||
std::string PreprocessedGLSL;
|
||||
|
||||
VulkanRenderer* vkr = (VulkanRenderer*)g_renderer.get();
|
||||
|
||||
EShMessages messagesPreprocess;
|
||||
if (vkr->IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT)
|
||||
messagesPreprocess = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules | EShMsgDebugInfo);
|
||||
else
|
||||
messagesPreprocess = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
|
||||
|
||||
glslang::TShader::ForbidIncluder Includer;
|
||||
TBuiltInResource Resources = GetDefaultBuiltInResource();
|
||||
EShMessages messagesPreprocess = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
|
||||
if (!Shader.preprocess(&Resources, 450, ENoProfile, false, false, messagesPreprocess, &PreprocessedGLSL, Includer))
|
||||
{
|
||||
cemuLog_log(LogType::Force, fmt::format("GLSL Preprocessing Failed For {:016x}_{:016x}: \"{}\"", m_baseHash, m_auxHash, Shader.getInfoLog()));
|
||||
|
|
@ -341,14 +344,9 @@ void RendererShaderVk::CompileInternal(bool isRenderThread)
|
|||
return;
|
||||
}
|
||||
|
||||
EShMessages messagesParseLink;
|
||||
if (vkr->IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT)
|
||||
messagesParseLink = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules | EShMsgDebugInfo);
|
||||
else
|
||||
messagesParseLink = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
|
||||
|
||||
const char* PreprocessedCStr = PreprocessedGLSL.c_str();
|
||||
Shader.setStrings(&PreprocessedCStr, 1);
|
||||
EShMessages messagesParseLink = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
|
||||
if (!Shader.parse(&Resources, 100, false, messagesParseLink))
|
||||
{
|
||||
cemuLog_log(LogType::Force, fmt::format("GLSL parsing failed for {:016x}_{:016x}: \"{}\"", m_baseHash, m_auxHash, Shader.getInfoLog()));
|
||||
|
|
@ -382,9 +380,17 @@ void RendererShaderVk::CompileInternal(bool isRenderThread)
|
|||
|
||||
glslang::SpvOptions spvOptions;
|
||||
spvOptions.disableOptimizer = false;
|
||||
spvOptions.generateDebugInfo = (vkr->IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT);
|
||||
spvOptions.validate = false;
|
||||
spvOptions.optimizeSize = true;
|
||||
if (compileWithDebugInfo)
|
||||
{
|
||||
spvOptions.generateDebugInfo = true;
|
||||
spvOptions.emitNonSemanticShaderDebugInfo = true;
|
||||
spvOptions.emitNonSemanticShaderDebugSource = true;
|
||||
|
||||
Shader.addSourceText(m_glslCode.c_str(), (uint32)m_glslCode.size());
|
||||
Shader.setSourceFile(fmt::format("shader_{:016x}_{:016x}.glsl", m_baseHash, m_auxHash).c_str());
|
||||
}
|
||||
|
||||
//auto beginTime = benchmarkTimer_start();
|
||||
|
||||
|
|
@ -393,7 +399,8 @@ void RendererShaderVk::CompileInternal(bool isRenderThread)
|
|||
//double timeDur = benchmarkTimer_stop(beginTime);
|
||||
//forceLogRemoveMe_printf("Shader GLSL-to-SPIRV compilation took %lfms Size %08x", timeDur, spirvBuffer.size()*4);
|
||||
|
||||
if (s_spirvCache && m_isGameShader && m_isGfxPackShader == false)
|
||||
// store in cache, unless it got compiled with debug info or is a modified shader from a gfx pack
|
||||
if (s_spirvCache && m_isGameShader && m_isGfxPackShader == false && !compileWithDebugInfo)
|
||||
{
|
||||
uint64 h1, h2;
|
||||
GenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ public:
|
|||
static void Shutdown();
|
||||
|
||||
sint32 GetUniformLocation(const char* name) override;
|
||||
void SetUniform1i(sint32 location, sint32 value) override;
|
||||
void SetUniform1f(sint32 location, float value) override;
|
||||
void SetUniform2fv(sint32 location, void* data, sint32 count) override;
|
||||
void SetUniform4iv(sint32 location, void* data, sint32 count) override;
|
||||
VkShaderModule& GetShaderModule() { return m_shader_module; }
|
||||
|
|
|
|||
|
|
@ -318,20 +318,10 @@ VkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurf
|
|||
return{ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
|
||||
for (const auto& format : formats)
|
||||
{
|
||||
bool useSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
|
||||
|
||||
if (useSRGB)
|
||||
{
|
||||
if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return format;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return formats[0];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ struct SwapchainInfoVk
|
|||
bool mainWindow{};
|
||||
|
||||
bool m_shouldRecreate = false;
|
||||
bool m_usesSRGB = false;
|
||||
VSync m_vsyncState = VSync::Immediate;
|
||||
bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
||||
|
||||
|
|
|
|||
|
|
@ -446,8 +446,6 @@ VulkanRenderer::VulkanRenderer()
|
|||
}
|
||||
|
||||
CheckDeviceExtensionSupport(m_physicalDevice, m_featureControl); // todo - merge this with GetDeviceFeatures and separate from IsDeviceSuitable?
|
||||
if (m_featureControl.debugMarkersSupported)
|
||||
cemuLog_log(LogType::Force, "Debug: Frame debugger attached, will use vkDebugMarkerSetObjectNameEXT");
|
||||
|
||||
DetermineVendor();
|
||||
GetDeviceFeatures();
|
||||
|
|
@ -582,10 +580,14 @@ VulkanRenderer::VulkanRenderer()
|
|||
debugCallback.pfnUserCallback = &DebugUtilsCallback;
|
||||
|
||||
vkCreateDebugUtilsMessengerEXT(m_instance, &debugCallback, nullptr, &m_debugCallback);
|
||||
|
||||
cemuLog_log(LogType::Force, "Debug: Vulkan validation layer enabled, vkCreateDebugUtilsMessengerEXT will be used to log validation errors");
|
||||
}
|
||||
|
||||
if (m_featureControl.instanceExtensions.debug_utils)
|
||||
cemuLog_log(LogType::Force, "Using available debug function: vkCreateDebugUtilsMessengerEXT()");
|
||||
if (this->IsTracingToolEnabled())
|
||||
cemuLog_log(LogType::Force, "Debug: Tracing tool detected, will recompile all shaders with debug info enabled. This disables the SPIR-V cache.");
|
||||
if (this->IsDebugMarkersEnabled())
|
||||
cemuLog_log(LogType::Force, "Debug: Detected tool capable of using debug markers, will use vkDebugMarkerSetObjectNameEXT to identify Vulkan objects");
|
||||
|
||||
// set initial viewport and scissor box size
|
||||
m_state.currentViewport.width = 4;
|
||||
|
|
@ -612,6 +614,8 @@ VulkanRenderer::VulkanRenderer()
|
|||
m_uniformVarBufferMemoryIsCoherent = true; // unified memory
|
||||
else if (memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory))
|
||||
m_uniformVarBufferMemoryIsCoherent = true;
|
||||
else if (memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory))
|
||||
m_uniformVarBufferMemoryIsCoherent = true;
|
||||
else
|
||||
{
|
||||
memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory);
|
||||
|
|
@ -624,7 +628,10 @@ VulkanRenderer::VulkanRenderer()
|
|||
m_uniformVarBufferPtr = (uint8*)bufferPtr;
|
||||
|
||||
// texture readback buffer
|
||||
memoryManager->CreateBuffer(TEXTURE_READBACK_SIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_textureReadbackBuffer, m_textureReadbackBufferMemory);
|
||||
if (!memoryManager->CreateBuffer(TEXTURE_READBACK_SIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_textureReadbackBuffer, m_textureReadbackBufferMemory))
|
||||
{
|
||||
memoryManager->CreateBuffer(TEXTURE_READBACK_SIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_textureReadbackBuffer, m_textureReadbackBufferMemory);
|
||||
}
|
||||
bufferPtr = nullptr;
|
||||
vkMapMemory(m_logicalDevice, m_textureReadbackBufferMemory, 0, VK_WHOLE_SIZE, 0, &bufferPtr);
|
||||
m_textureReadbackBufferPtr = (uint8*)bufferPtr;
|
||||
|
|
@ -633,7 +640,10 @@ VulkanRenderer::VulkanRenderer()
|
|||
memoryManager->CreateBuffer(LatteStreamout_GetRingBufferSize(), VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | (m_featureControl.mode.useTFEmulationViaSSBO ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0), 0, m_xfbRingBuffer, m_xfbRingBufferMemory);
|
||||
|
||||
// occlusion query result buffer
|
||||
memoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults);
|
||||
if (!memoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults))
|
||||
{
|
||||
memoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults);
|
||||
}
|
||||
bufferPtr = nullptr;
|
||||
vkMapMemory(m_logicalDevice, m_occlusionQueries.memoryQueryResults, 0, VK_WHOLE_SIZE, 0, &bufferPtr);
|
||||
m_occlusionQueries.ptrQueryResults = (uint64*)bufferPtr;
|
||||
|
|
@ -1256,8 +1266,9 @@ bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device,
|
|||
// dynamic rendering doesn't provide any benefits for us right now. Driver implementations are very unoptimized as of Feb 2022
|
||||
info.deviceExtensions.present_wait = isExtensionAvailable(VK_KHR_PRESENT_WAIT_EXTENSION_NAME) && isExtensionAvailable(VK_KHR_PRESENT_ID_EXTENSION_NAME);
|
||||
|
||||
// check for framedebuggers
|
||||
info.debugMarkersSupported = false;
|
||||
// check for validation layers and frame debuggers
|
||||
info.usingDebugMarkerTool = false;
|
||||
info.usingTracingTool = false;
|
||||
if (info.deviceExtensions.tooling_info && vkGetPhysicalDeviceToolPropertiesEXT)
|
||||
{
|
||||
uint32_t toolCount = 0;
|
||||
|
|
@ -1268,8 +1279,10 @@ bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device,
|
|||
{
|
||||
for (auto& itr : toolProperties)
|
||||
{
|
||||
if ((itr.purposes & VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT) != 0)
|
||||
info.debugMarkersSupported = true;
|
||||
if ((itr.purposes & VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT) != 0 && info.instanceExtensions.debug_utils && vkSetDebugUtilsObjectNameEXT)
|
||||
info.usingDebugMarkerTool = true;
|
||||
if ((itr.purposes & VK_TOOL_PURPOSE_TRACING_BIT) != 0)
|
||||
info.usingTracingTool = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2590,7 +2603,6 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet
|
|||
uint64 hash = 0;
|
||||
hash += (uint64)vertexRendererShader;
|
||||
hash += (uint64)fragmentRendererShader;
|
||||
hash += (uint64)(chainInfo.m_usesSRGB);
|
||||
hash += ((uint64)padView) << 1;
|
||||
|
||||
const auto it = m_backbufferBlitPipelineCache.find(hash);
|
||||
|
|
@ -2660,6 +2672,8 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet
|
|||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.offset = 0,
|
||||
.size = 3 * sizeof(float) * 2 // 3 vec2's
|
||||
+ 4 // + 1 VkBool32
|
||||
+ 4 * 2 // + 2 float
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
|
|
@ -2771,10 +2785,6 @@ bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
|
|||
if(chainInfo.m_vsyncState != configValue)
|
||||
stateChanged = true;
|
||||
|
||||
const bool latteBufferUsesSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
|
||||
if (chainInfo.m_usesSRGB != latteBufferUsesSRGB)
|
||||
stateChanged = true;
|
||||
|
||||
int width, height;
|
||||
if (mainWindow)
|
||||
WindowSystem::GetWindowPhysSize(width, height);
|
||||
|
|
@ -2799,7 +2809,6 @@ bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
|
|||
|
||||
chainInfo.m_shouldRecreate = false;
|
||||
chainInfo.m_vsyncState = configValue;
|
||||
chainInfo.m_usesSRGB = latteBufferUsesSRGB;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3046,24 +3055,35 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||
|
||||
vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &descriptSet, 0, nullptr);
|
||||
|
||||
|
||||
// update push constants
|
||||
Vector2f pushData[3];
|
||||
struct
|
||||
{
|
||||
Vector2f vecs[3];
|
||||
VkBool32 applySRGBEncoding;
|
||||
float targetGamma;
|
||||
float displayGamma;
|
||||
} pushData;
|
||||
|
||||
// textureSrcResolution
|
||||
sint32 effectiveWidth, effectiveHeight;
|
||||
texView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0);
|
||||
pushData[0] = {(float)effectiveWidth, (float)effectiveHeight};
|
||||
pushData.vecs[0] = {(float)effectiveWidth, (float)effectiveHeight};
|
||||
|
||||
// nativeResolution
|
||||
pushData[1] = {
|
||||
pushData.vecs[1] = {
|
||||
(float)texViewVk->baseTexture->width,
|
||||
(float)texViewVk->baseTexture->height,
|
||||
};
|
||||
|
||||
// outputResolution
|
||||
pushData[2] = {(float)imageWidth,(float)imageHeight};
|
||||
pushData.vecs[2] = {(float)imageWidth,(float)imageHeight};
|
||||
|
||||
vkCmdPushConstants(m_state.currentCommandBuffer, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float) * 2 * 3, &pushData);
|
||||
pushData.applySRGBEncoding = padView ? LatteGPUState.drcBufferUsesSRGB : LatteGPUState.tvBufferUsesSRGB;
|
||||
pushData.targetGamma = padView ? ActiveSettings::GetDRCGamma() : ActiveSettings::GetTVGamma();
|
||||
pushData.displayGamma = GetConfig().userDisplayGamma;
|
||||
|
||||
vkCmdPushConstants(m_state.currentCommandBuffer, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(pushData), &pushData);
|
||||
|
||||
vkCmdDraw(m_state.currentCommandBuffer, 6, 1, 0, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -481,7 +481,8 @@ private:
|
|||
uint32 nonCoherentAtomSize = 256;
|
||||
}limits;
|
||||
|
||||
bool debugMarkersSupported{ false }; // frame debugger is attached
|
||||
bool usingDebugMarkerTool{ false }; // validation layer or other tool capable of handling debug markers is used
|
||||
bool usingTracingTool{ false }; // frame debugger or other API replaying tool is used
|
||||
bool disableMultithreadedCompilation{ false }; // for old nvidia drivers
|
||||
|
||||
}m_featureControl{};
|
||||
|
|
@ -937,7 +938,8 @@ private:
|
|||
public:
|
||||
bool GetDisableMultithreadedCompilation() const { return m_featureControl.disableMultithreadedCompilation; }
|
||||
bool HasSPRIVRoundingModeRTE32() const { return m_featureControl.shaderFloatControls.shaderRoundingModeRTEFloat32; }
|
||||
bool IsDebugUtilsEnabled() const { return m_featureControl.debugMarkersSupported && m_featureControl.instanceExtensions.debug_utils; }
|
||||
bool IsDebugMarkersEnabled() const { return m_featureControl.usingDebugMarkerTool; }
|
||||
bool IsTracingToolEnabled() const { return m_featureControl.usingTracingTool; }
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ void compilePipelineThread_queue(PipelineCompiler* v)
|
|||
bool VulkanRenderer::IsAsyncPipelineAllowed(uint32 numIndices)
|
||||
{
|
||||
// frame debuggers dont handle async well (as of 2020)
|
||||
if (IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT)
|
||||
if (IsTracingToolEnabled())
|
||||
return false;
|
||||
|
||||
CachedFBOVk* currentFBO = m_state.activeFBO;
|
||||
|
|
|
|||
|
|
@ -659,7 +659,10 @@ namespace iosu
|
|||
for (uint32 i = 0; i < numIn + numOut; i++)
|
||||
{
|
||||
if (vec[i].baseVirt == nullptr && vec[i].size != 0)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "IPC Ioctlv failed because baseVirt is null but size is not 0");
|
||||
return IOS_ERROR_INVALID;
|
||||
}
|
||||
// todo - check for valid pointer range
|
||||
vec[i].basePhys = vec[i].baseVirt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -782,7 +782,7 @@ namespace iosu
|
|||
public:
|
||||
AcpMainService() : iosu::nn::IPCService("/dev/acp_main") {}
|
||||
|
||||
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
|
||||
nnResult ServiceCall(IPCServiceCall& serviceCall) override
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported service call to /dev/acp_main");
|
||||
cemu_assert_unimplemented();
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ namespace iosu
|
|||
public:
|
||||
ActService() : iosu::nn::IPCService("/dev/act") {}
|
||||
|
||||
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
|
||||
nnResult ServiceCall(IPCServiceCall& serviceCall) override
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported service call to /dev/act");
|
||||
cemu_assert_unimplemented();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,54 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "iosu_ioctl.h"
|
||||
|
||||
// custom dev/boss protocol (Cemu only)
|
||||
#define IOSU_BOSS_REQUEST_CEMU (0xEE)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 requestCode;
|
||||
// input
|
||||
uint32 accountId;
|
||||
char* taskId;
|
||||
bool bool_parameter;
|
||||
uint64 titleId;
|
||||
uint32 timeout;
|
||||
uint32 waitState;
|
||||
uint32 uk1;
|
||||
void* settings;
|
||||
|
||||
// output
|
||||
uint32 returnCode; // ACP return value
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 exec_count;
|
||||
uint32 result;
|
||||
} u32;
|
||||
struct
|
||||
{
|
||||
uint32 exec_count;
|
||||
uint64 result;
|
||||
} u64;
|
||||
};
|
||||
}iosuBossCemuRequest_t;
|
||||
|
||||
#define IOSU_NN_BOSS_TASK_RUN (0x01)
|
||||
#define IOSU_NN_BOSS_TASK_GET_CONTENT_LENGTH (0x02)
|
||||
#define IOSU_NN_BOSS_TASK_GET_PROCESSED_LENGTH (0x03)
|
||||
#define IOSU_NN_BOSS_TASK_GET_HTTP_STATUS_CODE (0x04)
|
||||
#define IOSU_NN_BOSS_TASK_GET_TURN_STATE (0x05)
|
||||
#define IOSU_NN_BOSS_TASK_WAIT (0x06)
|
||||
#define IOSU_NN_BOSS_TASK_REGISTER (0x07)
|
||||
#define IOSU_NN_BOSS_TASK_IS_REGISTERED (0x08)
|
||||
#define IOSU_NN_BOSS_TASK_REGISTER_FOR_IMMEDIATE_RUN (0x09)
|
||||
#define IOSU_NN_BOSS_TASK_UNREGISTER (0x0A)
|
||||
#define IOSU_NN_BOSS_TASK_START_SCHEDULING (0x0B)
|
||||
#define IOSU_NN_BOSS_TASK_STOP_SCHEDULING (0x0C)
|
||||
|
||||
namespace iosu
|
||||
{
|
||||
void boss_init();
|
||||
}
|
||||
0
src/Cafe/IOSU/nn/boss/boss_common.cpp
Normal file
0
src/Cafe/IOSU/nn/boss/boss_common.cpp
Normal file
431
src/Cafe/IOSU/nn/boss/boss_common.h
Normal file
431
src/Cafe/IOSU/nn/boss/boss_common.h
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
#pragma once
|
||||
#include "Common/CafeString.h"
|
||||
|
||||
namespace nn::boss
|
||||
{
|
||||
typedef uint32 BossResult;
|
||||
|
||||
struct VTableEntry
|
||||
{
|
||||
uint16be offsetA{0};
|
||||
uint16be offsetB{0};
|
||||
MEMPTR<void> ptr;
|
||||
};
|
||||
static_assert(sizeof(VTableEntry) == 8);
|
||||
|
||||
struct TitleId
|
||||
{
|
||||
uint64be u64{};
|
||||
|
||||
static bool IsValid(TitleId* _thisptr);
|
||||
static TitleId* ctorDefault(TitleId* _thisptr);
|
||||
static TitleId* ctorFromTitleId(TitleId* _thisptr, uint64 titleId); // __ct__Q3_2nn4boss7TitleIDFUL
|
||||
static TitleId* ctorCopy(TitleId* _thisptr, TitleId* titleId); // __ct__Q3_2nn4boss7TitleIDFRCQ3_2nn4boss7TitleID
|
||||
static bool operator_ne(TitleId* _thisptr, TitleId* titleId);
|
||||
|
||||
};
|
||||
static_assert(sizeof(TitleId) == 8);
|
||||
|
||||
struct TaskId
|
||||
{
|
||||
CafeString<8> id;
|
||||
|
||||
TaskId() = default;
|
||||
TaskId(const char* taskId) { id.assign(taskId); }
|
||||
|
||||
static TaskId* ctorDefault(TaskId* _thisptr);
|
||||
static TaskId* ctorFromString(TaskId* _thisptr, const char* taskId);
|
||||
|
||||
//auto operator<=>(const TaskId& other) const = default;
|
||||
std::strong_ordering operator<=>(const TaskId& other) const noexcept {
|
||||
return id <=> other.id; // Delegate to CafeString's operator<=>
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(TaskId) == 8);
|
||||
|
||||
struct Title
|
||||
{
|
||||
uint32be accountId{}; // 0x00
|
||||
TitleId titleId{}; // 0x8
|
||||
MEMPTR<void> vTablePtr{}; // 0x10
|
||||
|
||||
struct VTable
|
||||
{
|
||||
VTableEntry rtti;
|
||||
VTableEntry dtor;
|
||||
};
|
||||
static inline SysAllocator<VTable> s_titleVTable;
|
||||
|
||||
static Title* ctor(Title* _this);
|
||||
static void dtor(Title* _this, uint32 options);
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(sizeof(Title) == 0x18);
|
||||
|
||||
struct DirectoryName
|
||||
{
|
||||
CafeString<8> name2;
|
||||
|
||||
static DirectoryName* ctor(DirectoryName* _thisptr);
|
||||
static const char* operator_const_char(DirectoryName* _thisptr);
|
||||
};
|
||||
static_assert(sizeof(DirectoryName) == 8);
|
||||
|
||||
struct BossAccount // the actual class name is "Account" and while the boss namespace helps us separate this from Account(.h) we use an alternative name to avoid confusion
|
||||
{
|
||||
struct VTable
|
||||
{
|
||||
VTableEntry rtti;
|
||||
VTableEntry dtor;
|
||||
};
|
||||
static inline SysAllocator<VTable> s_VTable;
|
||||
|
||||
uint32be accountId;
|
||||
MEMPTR<void> vTablePtr;
|
||||
|
||||
static BossAccount* ctor(BossAccount* _this, uint32 accountId);
|
||||
static void dtor(BossAccount* _this, uint32 options);
|
||||
static void InitVTable();
|
||||
|
||||
};
|
||||
static_assert(sizeof(BossAccount) == 8);
|
||||
|
||||
enum class TaskWaitState : uint32 // for Task::Wait()
|
||||
{
|
||||
Done = 1,
|
||||
};
|
||||
|
||||
enum class TaskTurnState : uint32
|
||||
{
|
||||
Ukn = 0,
|
||||
Stopped = 1,
|
||||
Ready = 4,
|
||||
Running = 6,
|
||||
Done = 7, // how does this differ from DoneSuccess?
|
||||
DoneSuccess = 16,
|
||||
DoneError = 17
|
||||
};
|
||||
|
||||
enum class TaskState : uint8
|
||||
{
|
||||
Initial = 0,
|
||||
Stopped = 1,
|
||||
Ready = 4, // waiting for turn to run
|
||||
Running = 6,
|
||||
Done = 7,
|
||||
};
|
||||
|
||||
enum class TaskType : uint16
|
||||
{
|
||||
NbdlTaskSetting = 2,
|
||||
RawDlTaskSetting_1 = 1,
|
||||
RawDlTaskSetting_3 = 3,
|
||||
RawDlTaskSetting_9 = 9,
|
||||
RawUlTaskSetting = 4,
|
||||
PlayLogUploadTaskSetting = 5,
|
||||
PlayReportSetting = 6,
|
||||
DataStoreDownloadSetting = 8,
|
||||
NbdlDataListTaskSetting = 10
|
||||
};
|
||||
|
||||
struct TaskSettingCore // the setting struct as used by IOSU
|
||||
{
|
||||
struct LifeTime
|
||||
{
|
||||
uint32be high;
|
||||
uint32be low;
|
||||
};
|
||||
|
||||
uint32be persistentId;
|
||||
uint32be ukn04;
|
||||
uint32be ukn08;
|
||||
uint32be ukn0C;
|
||||
uint32be ukn10;
|
||||
uint32be ukn14;
|
||||
uint32be ukn18;
|
||||
uint32be ukn1C;
|
||||
TaskId taskId; // +0x20
|
||||
betype<TaskType> taskType; // +0x28
|
||||
uint8be priority; // +0x2A
|
||||
uint8be mode; // +0x2B
|
||||
uint8be permission; // +0x2C
|
||||
uint16be intervalA; // +0x2E
|
||||
uint32be intervalB; // +0x30
|
||||
uint32be unk34; // +0x34 - could be padding
|
||||
LifeTime lifeTime; // +0x38 - this is a 64bit value, but the whole struct has a size of 0x1004 and doesnt preserve the alignment in an array. Its probably handled as two 32bit values?
|
||||
uint8be httpProtocol; // +0x40
|
||||
uint8be internalClientCert; // +0x41
|
||||
uint16be httpOption; // +0x42
|
||||
uint8 ukn44[0x48 - 0x44]; // padding?
|
||||
CafeString<256> url; // +0x48
|
||||
CafeString<64> lastModifiedTime; // +0x148
|
||||
uint8be internalCaCert[3]; // +0x188
|
||||
uint8 ukn18B; // +0x18B - padding?
|
||||
uint32be httpTimeout; // +0x18C
|
||||
CafeString<128> caCert[3]; // +0x190 - 3 entries, each 0x80 bytes
|
||||
CafeString<128> clientCertName; // +0x310
|
||||
CafeString<128> clientCertKey; // +0x390
|
||||
struct HttpHeader
|
||||
{
|
||||
CafeString<32> name; // +0x00
|
||||
CafeString<64> value; // +0x20
|
||||
};
|
||||
HttpHeader httpHeaders[3]; // +0x410
|
||||
CafeString<96> httpQueryString; // +0x530
|
||||
CafeString<512> serviceToken; // +0x590
|
||||
|
||||
uint8 ukn790[0x7C0 - 0x790];
|
||||
// after 0x7C0 the task-specific fields seem to start?
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32be optionValue; // +0x7C0
|
||||
CafeString<32> largeHttpHeaderKey; // +0x7C4
|
||||
CafeString<512> largeHttpHeaderValue; // +0x7E4
|
||||
}rawUl; // RawUlTaskSetting
|
||||
struct
|
||||
{
|
||||
uint32be optionValue; // +0x7C0
|
||||
CafeString<32> largeHttpHeaderKey; // +0x7C4
|
||||
CafeString<512> largeHttpHeaderValue; // +0x7E4
|
||||
// inherits the above values from RawUlTaskSetting
|
||||
// the play report fields are too large to fit into the available space, so instead they are passed via their own system call that attaches it to the task. See PlayReportSetting::RegisterPreprocess
|
||||
}playReportSetting;
|
||||
struct
|
||||
{
|
||||
uint8be newArrival; // +0x7C0
|
||||
uint8be led; // +0x7C1
|
||||
uint8be ukn7C2[6]; // +0x7C2 - padding?
|
||||
CafeString<8> bossDirectory; // +0x7C8
|
||||
CafeString<32> fileName; // +0x7D0 Not 100% sure this is fileName
|
||||
}rawDl; // RawDlTaskSetting
|
||||
struct
|
||||
{
|
||||
CafeString<32> bossCode; // +0x7C0
|
||||
CafeString<8> bossDirectory; // +0x7E0
|
||||
uint32be ukn7E8;
|
||||
uint32be ukn7EC;
|
||||
uint32be directorySizeLimitHigh; // +0x7F0
|
||||
uint32be directorySizeLimitLow; // +0x7F4
|
||||
CafeString<32> fileName; // +0x7F8
|
||||
// more fields here...
|
||||
}nbdl;
|
||||
struct
|
||||
{
|
||||
uint8 finalPadding[0xC00 - 0x7C0];
|
||||
}paddedBlock;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(TaskSettingCore) == 0xC00);
|
||||
|
||||
struct TaskSetting : public TaskSettingCore
|
||||
{
|
||||
uint8 paddingC00[0x1000 - 0xC00];
|
||||
MEMPTR<void> vTablePtr; // +0x1000
|
||||
|
||||
struct VTableTaskSetting
|
||||
{
|
||||
VTableEntry rtti;
|
||||
VTableEntry dtor;
|
||||
VTableEntry RegisterPreprocess; // todo - double check the offset
|
||||
VTableEntry unk1;
|
||||
};
|
||||
static inline SysAllocator<VTableTaskSetting> s_VTable;
|
||||
|
||||
static TaskSetting* ctor(TaskSetting* _thisptr);
|
||||
static void dtor(TaskSetting* _this, uint32 options);
|
||||
static bool IsPrivileged(TaskSetting* _thisptr);
|
||||
static void InitializeSetting(TaskSetting* _thisptr);
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(offsetof(TaskSetting, priority) == 0x2A);
|
||||
static_assert(offsetof(TaskSetting, mode) == 0x2B);
|
||||
static_assert(offsetof(TaskSetting, permission) == 0x2C);
|
||||
static_assert(offsetof(TaskSetting, intervalA) == 0x2E);
|
||||
static_assert(offsetof(TaskSetting, intervalB) == 0x30);
|
||||
static_assert(offsetof(TaskSetting, lifeTime) == 0x38);
|
||||
static_assert(offsetof(TaskSetting, httpProtocol) == 0x40);
|
||||
static_assert(offsetof(TaskSetting, internalClientCert) == 0x41);
|
||||
static_assert(offsetof(TaskSetting, httpOption) == 0x42);
|
||||
static_assert(offsetof(TaskSetting, url) == 0x48);
|
||||
static_assert(offsetof(TaskSetting, lastModifiedTime) == 0x148);
|
||||
static_assert(offsetof(TaskSetting, internalCaCert) == 0x188);
|
||||
static_assert(offsetof(TaskSetting, httpTimeout) == 0x18C);
|
||||
static_assert(offsetof(TaskSetting, caCert) == 0x190);
|
||||
static_assert(offsetof(TaskSetting, clientCertName) == 0x310);
|
||||
static_assert(offsetof(TaskSetting, clientCertKey) == 0x390);
|
||||
static_assert(offsetof(TaskSetting, httpHeaders) == 0x410);
|
||||
static_assert(offsetof(TaskSetting, httpQueryString) == 0x530);
|
||||
static_assert(offsetof(TaskSetting, serviceToken) == 0x590);
|
||||
// rawUl
|
||||
static_assert(offsetof(TaskSetting, rawUl.optionValue) == 0x7C0);
|
||||
static_assert(offsetof(TaskSetting, rawUl.largeHttpHeaderKey) == 0x7C4);
|
||||
static_assert(offsetof(TaskSetting, rawUl.largeHttpHeaderValue) == 0x7E4);
|
||||
// rawDl
|
||||
static_assert(offsetof(TaskSetting, rawDl.newArrival) == 0x7C0);
|
||||
static_assert(offsetof(TaskSetting, rawDl.bossDirectory) == 0x7C8);
|
||||
static_assert(offsetof(TaskSetting, rawDl.fileName) == 0x7D0);
|
||||
// nbdl
|
||||
static_assert(offsetof(TaskSetting, nbdl.bossCode) == 0x7C0);
|
||||
static_assert(offsetof(TaskSetting, nbdl.bossDirectory) == 0x7E0);
|
||||
|
||||
static_assert(offsetof(TaskSetting, vTablePtr) == 0x1000);
|
||||
static_assert(sizeof(TaskSetting) == 0x1004);
|
||||
|
||||
/* NetTaskSetting */
|
||||
|
||||
struct NetTaskSetting : TaskSetting
|
||||
{
|
||||
struct VTableNetTaskSetting : public VTableTaskSetting
|
||||
{ };
|
||||
static inline SysAllocator<VTableNetTaskSetting> s_VTable;
|
||||
|
||||
static NetTaskSetting* ctor(NetTaskSetting* _thisptr);
|
||||
static BossResult AddCaCert(NetTaskSetting* _thisptr, const char* name);
|
||||
static BossResult SetServiceToken(NetTaskSetting* _thisptr, const uint8* serviceToken);
|
||||
static BossResult AddInternalCaCert(NetTaskSetting* _thisptr, char certId);
|
||||
static void SetInternalClientCert(NetTaskSetting* _thisptr, char certId);
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(sizeof(NetTaskSetting) == 0x1004);
|
||||
|
||||
/* NbdlTaskSetting */
|
||||
|
||||
struct NbdlTaskSetting : NetTaskSetting
|
||||
{
|
||||
struct VTableNbdlTaskSetting : public VTableNetTaskSetting
|
||||
{
|
||||
VTableEntry rttiNetTaskSetting; // unknown
|
||||
};
|
||||
static_assert(sizeof(VTableNbdlTaskSetting) == 8*5);
|
||||
static inline SysAllocator<VTableNbdlTaskSetting> s_VTable;
|
||||
|
||||
static NbdlTaskSetting* ctor(NbdlTaskSetting* _thisptr);
|
||||
static BossResult Initialize(NbdlTaskSetting* _thisptr, const char* bossCode, uint64 directorySizeLimit, const char* bossDirectory);
|
||||
static BossResult SetFileName(NbdlTaskSetting* _thisptr, const char* fileName);
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(sizeof(NbdlTaskSetting) == 0x1004);
|
||||
|
||||
/* RawUlTaskSetting */
|
||||
|
||||
struct RawUlTaskSetting : NetTaskSetting
|
||||
{
|
||||
uint32be ukRaw1; // 0x1004
|
||||
uint32be ukRaw2; // 0x1008
|
||||
uint32be ukRaw3; // 0x100C
|
||||
uint8 rawSpace[0x200]; // 0x1010
|
||||
|
||||
struct VTableRawUlTaskSetting : public VTableNetTaskSetting
|
||||
{
|
||||
VTableEntry rttiNetTaskSetting; // unknown
|
||||
};
|
||||
static_assert(sizeof(VTableRawUlTaskSetting) == 8*5);
|
||||
static inline SysAllocator<VTableRawUlTaskSetting> s_VTable;
|
||||
|
||||
static RawUlTaskSetting* ctor(RawUlTaskSetting* _thisptr);
|
||||
static void dtor(RawUlTaskSetting* _this, uint32 options);
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(sizeof(RawUlTaskSetting) == 0x1210);
|
||||
|
||||
/* RawDlTaskSetting */
|
||||
struct RawDlTaskSetting : NetTaskSetting
|
||||
{
|
||||
struct VTableRawDlTaskSetting : public VTableNetTaskSetting
|
||||
{
|
||||
VTableEntry rttiNetTaskSetting; // unknown
|
||||
};
|
||||
static_assert(sizeof(VTableRawDlTaskSetting) == 8*5);
|
||||
static inline SysAllocator<VTableRawDlTaskSetting> s_VTable;
|
||||
|
||||
static RawDlTaskSetting* ctor(RawDlTaskSetting* _thisptr);
|
||||
static BossResult Initialize(RawDlTaskSetting* _thisptr, const char* url, bool newArrival, bool led, const char* fileName, const char* bossDirectory);
|
||||
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(sizeof(RawDlTaskSetting) == 0x1004);
|
||||
|
||||
/* PlayReportSetting */
|
||||
|
||||
struct PlayReportSetting : RawUlTaskSetting
|
||||
{
|
||||
MEMPTR<uint8> ukn1210_ptr; // 0x1210
|
||||
uint32be ukn1214_size; // 0x1214
|
||||
uint32be ukPlay3; // 0x1218
|
||||
uint32be ukPlay4; // 0x121C
|
||||
|
||||
struct VTablePlayReportSetting : public VTableRawUlTaskSetting
|
||||
{};
|
||||
static_assert(sizeof(VTablePlayReportSetting) == 8*5);
|
||||
static inline SysAllocator<VTablePlayReportSetting> s_VTable;
|
||||
|
||||
static PlayReportSetting* ctor(PlayReportSetting* _this);
|
||||
static void dtor(PlayReportSetting* _this, uint32 options);
|
||||
static void Initialize(PlayReportSetting* _this, uint8* ptr, uint32 size);
|
||||
static bool Set(PlayReportSetting* _this, const char* keyname, uint32 value);
|
||||
static void InitVTable();
|
||||
};
|
||||
static_assert(sizeof(PlayReportSetting) == 0x1220);
|
||||
|
||||
/* Storage */
|
||||
enum class StorageKind : uint32
|
||||
{
|
||||
StorageNbdl = 0,
|
||||
StorageRawDl = 1,
|
||||
};
|
||||
|
||||
struct DataName
|
||||
{
|
||||
CafeString<32> name;
|
||||
|
||||
static DataName* ctor(DataName* _this); // __ct__Q3_2nn4boss8DataNameFv
|
||||
static const char* operator_const_char(DataName* _this); // __opPCc__Q3_2nn4boss8DataNameCFv
|
||||
|
||||
const char* c_str() const
|
||||
{
|
||||
return name.c_str();
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(DataName) == 32);
|
||||
|
||||
/* IPC commands for /dev/boss */
|
||||
enum class BossCommandId : uint32
|
||||
{
|
||||
// task operations
|
||||
TaskIsRegistered = 0x69,
|
||||
TaskRegisterA = 0x6A,
|
||||
TaskRegisterForImmediateRunA = 0x6B,
|
||||
TaskUnregister = 0x6D,
|
||||
TaskRun = 0x78,
|
||||
TaskStartScheduling = 0x77,
|
||||
TaskStopScheduling = 0x79,
|
||||
TaskWaitA = 0x7A,
|
||||
TaskGetHttpStatusCodeA = 0x7C,
|
||||
TaskGetTurnState = 0x7E,
|
||||
TaskGetContentLength = 0x82,
|
||||
TaskGetProcessedLength = 0x83,
|
||||
// storage operations
|
||||
StorageExist = 0x87,
|
||||
StorageGetDataList = 0xB0,
|
||||
// NsData operations
|
||||
NsDataExist = 0x90,
|
||||
NsDataRead = 0x93,
|
||||
NsDataGetSize = 0x96,
|
||||
NsDataDeleteFile = 0xA7,
|
||||
NsDataDeleteFileWithHistory = 0xA8,
|
||||
NsFinalize = 0xB3,
|
||||
// Title operations
|
||||
TitleSetNewArrivalFlag = 0x9E,
|
||||
|
||||
// most (if not all?) opcodes seem to have a secondary form with an additional titleId parameter in the high range around 0x150 and serviceId 1
|
||||
|
||||
// unknown commands
|
||||
UknA7 = 0xA5,
|
||||
DeleteDataRelated = 0xA6,
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
1431
src/Cafe/IOSU/nn/boss/boss_service.cpp
Normal file
1431
src/Cafe/IOSU/nn/boss/boss_service.cpp
Normal file
File diff suppressed because it is too large
Load diff
7
src/Cafe/IOSU/nn/boss/boss_service.h
Normal file
7
src/Cafe/IOSU/nn/boss/boss_service.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
|
||||
namespace iosu::boss
|
||||
{
|
||||
IOSUModule* GetModule();
|
||||
}
|
||||
|
|
@ -188,18 +188,43 @@ namespace iosu
|
|||
else if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)
|
||||
{
|
||||
uint32 requestId = cmd->args[0];
|
||||
uint32 numIn = cmd->args[1];
|
||||
uint32 numOut = cmd->args[2];
|
||||
uint32 numOut = cmd->args[1];
|
||||
uint32 numIn = cmd->args[2];
|
||||
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();
|
||||
IPCIoctlVector* vecIn = vec + numIn;
|
||||
IPCIoctlVector* vecOut = vec + 0;
|
||||
IPCIoctlVector* vecOut = vec + 0; // out buffers come first
|
||||
IPCIoctlVector* vecIn = vec + numOut;
|
||||
|
||||
cemu_assert(numIn > 0 && numOut > 0);
|
||||
cemu_assert(vecIn->size >= 80 && !vecIn->basePhys.IsNull());
|
||||
|
||||
IPCServiceRequest* serviceRequest = MEMPTR<IPCServiceRequest>(vecIn->basePhys).GetPtr();
|
||||
IPCServiceResponse* serviceResponse = MEMPTR<IPCServiceResponse>(vecOut->basePhys).GetPtr();
|
||||
IPCServiceRequestHeader* serviceRequest = MEMPTR<IPCServiceRequestHeader>(vecIn->basePhys).GetPtr();
|
||||
IPCServiceResponseHeader* serviceResponse = MEMPTR<IPCServiceResponseHeader>(vecOut->basePhys).GetPtr();
|
||||
|
||||
IOSDevHandle clientHandle = 0; // todo
|
||||
IPCServiceCall serviceCall(clientHandle, serviceRequest->serviceId, serviceRequest->commandId);
|
||||
|
||||
#if 0
|
||||
// log all buffers
|
||||
cemuLog_log(LogType::Force, "IPC ServiceCall. In: {}, Out: {}, ServiceId: {}, CommandId: {} (0x{:x})", numIn, numOut, serviceRequest->serviceId, serviceRequest->commandId, serviceRequest->commandId);
|
||||
for (size_t i = 0; i <numOut+numIn; i++)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "");
|
||||
cemuLog_log(LogType::Force, "Buffer {} - BasePhys: {}, Size: {}", i, vec[i].basePhys, vec[i].size);
|
||||
cemuLog_logHexDump(LogType::Force, MEMPTR<uint8>(vec[i].basePhys).GetPtr(), vec[i].size, 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
// parameter and response data is appended directly after the headers, so we add the streams without the headers
|
||||
serviceCall.AddInputStream(MEMPTR<uint8>(vecIn[0].basePhys).GetPtr() + sizeof(IPCServiceRequestHeader), vecIn[0].size - sizeof(IPCServiceRequestHeader));
|
||||
serviceCall.AddOutputStream(MEMPTR<uint8>(vecOut[0].basePhys).GetPtr() + sizeof(IPCServiceResponseHeader), vecOut[0].size - sizeof(IPCServiceResponseHeader));
|
||||
// add remaining input/output buffers
|
||||
for (size_t i = 1; i < numIn; i++)
|
||||
serviceCall.AddInputStream(MEMPTR<uint8>(vecIn[i].basePhys).GetPtr(), vecIn[i].size);
|
||||
for (size_t i = 1; i < numOut; i++)
|
||||
serviceCall.AddOutputStream(MEMPTR<uint8>(vecOut[i].basePhys).GetPtr(), vecOut[i].size);
|
||||
|
||||
serviceResponse->nnResultCode = (uint32)ServiceCall(serviceCall);
|
||||
|
||||
serviceResponse->nnResultCode = (uint32)ServiceCall(serviceRequest->serviceId, nullptr, nullptr);
|
||||
IOS_ResourceReply(cmd, IOS_ERROR_OK);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ namespace iosu
|
|||
SysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;
|
||||
};
|
||||
|
||||
struct IPCServiceRequest
|
||||
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, /dev/acp_main, /dev/boss and most nn services
|
||||
class IPCService
|
||||
{
|
||||
struct IPCServiceRequestHeader
|
||||
{
|
||||
uint32be ukn00;
|
||||
uint32be serviceId;
|
||||
|
|
@ -81,17 +84,228 @@ namespace iosu
|
|||
uint32be commandId;
|
||||
};
|
||||
|
||||
static_assert(sizeof(IPCServiceRequest) == 0x10);
|
||||
static_assert(sizeof(IPCServiceRequestHeader) == 0x10);
|
||||
|
||||
struct IPCServiceResponse
|
||||
struct IPCServiceResponseHeader
|
||||
{
|
||||
uint32be nnResultCode;
|
||||
};
|
||||
|
||||
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, /dev/acp_main, ?
|
||||
class IPCService
|
||||
public:
|
||||
class IPCParameterStream // input stream for parameters
|
||||
{
|
||||
public:
|
||||
IPCParameterStream() = default;
|
||||
IPCParameterStream(void* data, uint32 size) : m_data((uint8_t*)data), m_size(size) {}
|
||||
|
||||
template<typename T>
|
||||
T ReadParameter(bool& hasError)
|
||||
{
|
||||
hasError = false;
|
||||
if (m_readIndex + sizeof(T) > m_size)
|
||||
{
|
||||
hasError = true;
|
||||
return T{};
|
||||
}
|
||||
T value;
|
||||
memcpy(&value, &m_data[m_readIndex], sizeof(T));
|
||||
m_readIndex += sizeof(T);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8* GetData() { return m_data; }
|
||||
uint32 GetSize() const { return m_size; }
|
||||
|
||||
private:
|
||||
uint8* m_data{nullptr};
|
||||
uint32 m_size{0};
|
||||
uint32 m_readIndex{0};
|
||||
};
|
||||
|
||||
class IPCResponseStream // output stream for response data
|
||||
{
|
||||
public:
|
||||
IPCResponseStream() = default;
|
||||
IPCResponseStream(void* data, uint32 size) : m_data((uint8*)data), m_size(size) {}
|
||||
|
||||
template<typename T>
|
||||
void Write(const T& value)
|
||||
{
|
||||
if (m_writtenSize + sizeof(T) > m_size)
|
||||
{
|
||||
m_hasError = true;
|
||||
return;
|
||||
}
|
||||
memcpy(&m_data[m_writtenSize], &value, sizeof(T));
|
||||
m_writtenSize += sizeof(T);
|
||||
}
|
||||
|
||||
uint8* GetData() { return m_data; }
|
||||
uint32 GetSize() const { return m_size; }
|
||||
|
||||
private:
|
||||
uint8* m_data{nullptr};
|
||||
uint32 m_writtenSize{0};
|
||||
uint32 m_size{0};
|
||||
bool m_hasError{false};
|
||||
};
|
||||
|
||||
class IPCServiceCall
|
||||
{
|
||||
struct LargeBufferHeader
|
||||
{
|
||||
uint32be alignedSize; // size of the aligned (middle) part of the buffer
|
||||
uint8be ukn4;
|
||||
uint8be ukn5;
|
||||
uint8be headSize;
|
||||
uint8be tailSize;
|
||||
};
|
||||
static_assert(sizeof(LargeBufferHeader) == 8);
|
||||
public:
|
||||
struct UnalignedBuffer
|
||||
{
|
||||
UnalignedBuffer(bool isOutput, std::span<uint8> head, std::span<uint8> middle, std::span<uint8> tail) : m_isOutput(isOutput)
|
||||
{
|
||||
headPtr = head.data();
|
||||
headSize = (uint32)head.size();
|
||||
middlePtr = middle.data();
|
||||
middleSize = (uint32)middle.size();
|
||||
tailPtr = tail.data();
|
||||
tailSize = (uint32)tail.size();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T ReadType()
|
||||
{
|
||||
cemu_assert(!m_isOutput);
|
||||
T v;
|
||||
memcpy((uint8_t*)&v, headPtr, headSize);
|
||||
memcpy((uint8_t*)&v + headSize, middlePtr, middleSize);
|
||||
memcpy((uint8_t*)&v + headSize + middleSize, tailPtr, tailSize);
|
||||
return v;
|
||||
}
|
||||
|
||||
void WriteData(void* data, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
cemu_assert(m_isOutput);
|
||||
cemu_assert((headSize + middleSize + tailSize) >= size);
|
||||
size_t bytesToCopy = std::min<size_t>(size, headSize);
|
||||
memcpy(headPtr, data, bytesToCopy);
|
||||
size -= bytesToCopy;
|
||||
if (size > 0)
|
||||
{
|
||||
bytesToCopy = std::min<size_t>(size, middleSize);
|
||||
memcpy(middlePtr, (uint8_t*)data + headSize, bytesToCopy);
|
||||
size -= bytesToCopy;
|
||||
}
|
||||
if (size > 0)
|
||||
{
|
||||
bytesToCopy = std::min<size_t>(size, tailSize);
|
||||
memcpy(tailPtr, (uint8_t*)data + headSize + middleSize, bytesToCopy);
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return headSize + middleSize + tailSize;
|
||||
}
|
||||
|
||||
private:
|
||||
void* headPtr;
|
||||
uint32 headSize;
|
||||
void* middlePtr; // aligned
|
||||
uint32 middleSize;
|
||||
void* tailPtr;
|
||||
uint32 tailSize;
|
||||
bool m_isOutput;
|
||||
};
|
||||
|
||||
IPCServiceCall(IOSDevHandle clientHandle, uint32 serviceId, uint32 commandId) : m_clientHandle(clientHandle), m_serviceId(serviceId), m_commandId(commandId)
|
||||
{
|
||||
}
|
||||
|
||||
void AddInputStream(void* data, uint32 size)
|
||||
{
|
||||
cemu_assert(m_paramStreamArraySize < 4);
|
||||
m_paramStreamArray[m_paramStreamArraySize++] = IPCParameterStream(data, size);
|
||||
}
|
||||
|
||||
void AddOutputStream(void* data, uint32 size)
|
||||
{
|
||||
cemu_assert(m_responseStreamArraySize < 4);
|
||||
m_responseStreamArray[m_responseStreamArraySize++] = IPCResponseStream(data, size);
|
||||
}
|
||||
|
||||
uint32 GetServiceId() const
|
||||
{
|
||||
return m_serviceId;
|
||||
}
|
||||
|
||||
uint32 GetCommandId() const
|
||||
{
|
||||
return m_commandId;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ReadParameter()
|
||||
{
|
||||
// read only from stream 0 for now
|
||||
return m_paramStreamArray[0].ReadParameter<T>(m_hasError);
|
||||
}
|
||||
|
||||
UnalignedBuffer ReadUnalignedInputBufferInfo()
|
||||
{
|
||||
// how large/unaligned buffers work:
|
||||
// Instead of appending the data into the parameter stream, there are two separate buffers created:
|
||||
// 1. A ioctl vector that points directly to the aligned part of the original buffer. Both the pointer and the size are aligned
|
||||
// 2. A ioctl vector with an allocated up-to-128byte buffer that holds any unaligned head or tail data (e.g. anything that isn't occupying the full 64 byte alignment)
|
||||
// The buffer layout is then also serialized into the parameter stream
|
||||
LargeBufferHeader header = ReadParameter<LargeBufferHeader>();
|
||||
// get aligned buffer part
|
||||
void* alignedBuffer = m_paramStreamArray[m_inputBufferIndex+0].GetData();
|
||||
cemu_assert(m_paramStreamArray[m_inputBufferIndex+0].GetSize() == header.alignedSize);
|
||||
// get head and tail buffer parts
|
||||
uint8* unalignedDataBuffer = m_paramStreamArray[m_inputBufferIndex+1].GetData();
|
||||
cemu_assert((header.headSize + header.tailSize) <= m_paramStreamArray[m_inputBufferIndex+1].GetSize());
|
||||
UnalignedBuffer largeBuffer(false, {(uint8*)unalignedDataBuffer, header.headSize}, {(uint8*)alignedBuffer, header.alignedSize}, {(uint8*)unalignedDataBuffer + header.headSize, header.tailSize});
|
||||
m_inputBufferIndex += 2; // if there is no unaligned data then are both buffers still present?
|
||||
return largeBuffer;
|
||||
}
|
||||
|
||||
UnalignedBuffer ReadUnalignedOutputBufferInfo()
|
||||
{
|
||||
LargeBufferHeader header = ReadParameter<LargeBufferHeader>();
|
||||
// get aligned buffer part
|
||||
void* alignedBuffer = m_responseStreamArray[m_outputBufferIndex+0].GetData();
|
||||
cemu_assert(m_responseStreamArray[m_outputBufferIndex+0].GetSize() == header.alignedSize);
|
||||
// get head and tail buffer parts
|
||||
uint8* unalignedDataBuffer = m_responseStreamArray[m_outputBufferIndex+1].GetData();
|
||||
cemu_assert((header.headSize + header.tailSize) <= m_responseStreamArray[m_outputBufferIndex+1].GetSize());
|
||||
UnalignedBuffer largeBuffer(true, {(uint8*)unalignedDataBuffer, header.headSize}, {(uint8*)alignedBuffer, header.alignedSize}, {(uint8*)unalignedDataBuffer + header.headSize, header.tailSize});
|
||||
m_outputBufferIndex += 2; // if there is no unaligned data then are both buffers still present?
|
||||
return largeBuffer;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void WriteResponse(const T& value)
|
||||
{
|
||||
m_responseStreamArray[0].Write<T>(value);
|
||||
}
|
||||
|
||||
private:
|
||||
IOSDevHandle m_clientHandle;
|
||||
uint32 m_serviceId;
|
||||
uint32 m_commandId;
|
||||
IPCParameterStream m_paramStreamArray[4]{};
|
||||
size_t m_paramStreamArraySize{0};
|
||||
IPCResponseStream m_responseStreamArray[4]{};
|
||||
size_t m_responseStreamArraySize{0};
|
||||
bool m_hasError{false};
|
||||
sint8 m_inputBufferIndex{1};
|
||||
sint8 m_outputBufferIndex{1};
|
||||
};
|
||||
|
||||
IPCService(std::string_view devicePath) : m_devicePath(devicePath) {};
|
||||
virtual ~IPCService() {};
|
||||
|
||||
|
|
@ -105,7 +319,7 @@ namespace iosu
|
|||
|
||||
}
|
||||
|
||||
virtual nnResult ServiceCall(uint32 serviceId, void* request, void* response)
|
||||
virtual nnResult ServiceCall(IPCServiceCall& serviceCall)
|
||||
{
|
||||
cemu_assert_unimplemented();
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -206,8 +206,12 @@ namespace GX2
|
|||
|
||||
void GX2SetTVGamma(float gamma)
|
||||
{
|
||||
if (abs(gamma - 1.0f) > 0.01f)
|
||||
cemuLog_logDebug(LogType::Force, "TV gamma set to {} which is not supported", gamma);
|
||||
LatteGPUState.tvGamma = (1.0f - gamma);
|
||||
}
|
||||
|
||||
void GX2SetDRCGamma(float gamma)
|
||||
{
|
||||
LatteGPUState.drcGamma = (1.0f - gamma);
|
||||
}
|
||||
|
||||
bool GX2GetLastFrame(uint32 deviceId, GX2Texture* textureOut)
|
||||
|
|
@ -307,6 +311,7 @@ namespace GX2
|
|||
|
||||
cafeExportRegister("gx2", GX2SetTVBuffer, LogType::GX2);
|
||||
cafeExportRegister("gx2", GX2SetTVGamma, LogType::GX2);
|
||||
cafeExportRegister("gx2", GX2SetDRCGamma, LogType::GX2);
|
||||
|
||||
cafeExportRegister("gx2", GX2GetLastFrame, LogType::GX2);
|
||||
cafeExportRegister("gx2", GX2GetLastFrameGammaA, LogType::GX2);
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ void gx2Surface_GX2CopySurface(GX2Surface* srcSurface, uint32 srcMip, uint32 src
|
|||
|
||||
if( dstMipWidth != srcMipWidth || dstMipHeight != srcMipHeight )
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
cemuLog_logDebugOnce(LogType::Force, "GX2CopySurface: Mismatching mip resolution");
|
||||
return;
|
||||
}
|
||||
// handle format
|
||||
|
|
|
|||
|
|
@ -1 +1,6 @@
|
|||
void nnAc_load();
|
||||
|
||||
namespace nn_ac
|
||||
{
|
||||
nnResult IsApplicationConnected(uint8be* connected);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
261
src/Cafe/OS/libs/nn_client_service.h
Normal file
261
src/Cafe/OS/libs/nn_client_service.h
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
#pragma once
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_IPC.h"
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
class IPCServiceClient
|
||||
{
|
||||
public:
|
||||
class IPCServiceCall
|
||||
{
|
||||
struct IOVectorBuffer
|
||||
{
|
||||
IOVectorBuffer() = default;
|
||||
IOVectorBuffer(uint8* ptr, uint32 size, bool isExternalBuffer = false) : ptr(ptr), size(size), isExternalBuffer(isExternalBuffer) {}
|
||||
|
||||
uint8* ptr;
|
||||
uint32 size;
|
||||
bool isExternalBuffer{false}; // buffer provided by caller
|
||||
};
|
||||
public:
|
||||
IPCServiceCall(IPCServiceClient& client, uint32 serviceId, uint32 commandId) : m_client(client)
|
||||
{
|
||||
// allocate a parameter and response buffer
|
||||
IPCBuffer* cmdBuf = client.AllocateCommandBuffer();
|
||||
m_paramBuffers.emplace_back(cmdBuf->data, sizeof(IPCBuffer));
|
||||
cmdBuf = client.AllocateCommandBuffer();
|
||||
m_responseBuffers.emplace_back(cmdBuf->data, sizeof(IPCBuffer));
|
||||
// write the request header
|
||||
WriteParam<uint32be>(0); // ukn00
|
||||
WriteParam<uint32be>(serviceId); // serviceId
|
||||
WriteParam<uint32be>(0); // ukn08
|
||||
WriteParam<uint32be>(commandId); // commandId
|
||||
}
|
||||
|
||||
~IPCServiceCall()
|
||||
{
|
||||
for (auto& buf : m_paramBuffers)
|
||||
{
|
||||
if (buf.isExternalBuffer)
|
||||
continue;
|
||||
m_client.ReleaseCommandBuffer((IPCBuffer*)buf.ptr);
|
||||
}
|
||||
for (auto& buf : m_responseBuffers)
|
||||
{
|
||||
if (buf.isExternalBuffer)
|
||||
continue;
|
||||
m_client.ReleaseCommandBuffer((IPCBuffer*)buf.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
IPCServiceCall(const IPCServiceCall&) = delete;
|
||||
IPCServiceCall& operator=(const IPCServiceCall&) = delete;
|
||||
|
||||
template<typename T>
|
||||
void WriteParam(const T& value)
|
||||
{
|
||||
cemu_assert(m_paramWriteIndex + sizeof(T) <= m_paramBuffers[0].size);
|
||||
memcpy(m_paramBuffers[0].ptr + m_paramWriteIndex, &value, sizeof(T));
|
||||
m_paramWriteIndex += sizeof(T);
|
||||
}
|
||||
|
||||
// ptr and size defines an input buffer (PPC->IOSU)
|
||||
void WriteParamBuffer(MEMPTR<void> ptr, uint32 size)
|
||||
{
|
||||
WriteInOutBuffer(MEMPTR<uint8>(ptr), size, false);
|
||||
}
|
||||
|
||||
// ptr and size defines an output buffer (IOSU->PPC)
|
||||
void WriteResponseBuffer(MEMPTR<void> ptr, uint32 size)
|
||||
{
|
||||
WriteInOutBuffer(MEMPTR<uint8>(ptr), size, true);
|
||||
}
|
||||
|
||||
nnResult Submit()
|
||||
{
|
||||
StackAllocator<IPCIoctlVector, 16> vectorArray;
|
||||
uint32 ioVecCount = m_paramBuffers.size() + m_responseBuffers.size();
|
||||
cemu_assert(ioVecCount <= 16);
|
||||
// output buffers come first
|
||||
for (size_t i = 0; i < m_responseBuffers.size(); ++i)
|
||||
{
|
||||
vectorArray[i].baseVirt = MEMPTR<uint8>(m_responseBuffers[i].ptr);
|
||||
vectorArray[i].basePhys = nullptr;
|
||||
vectorArray[i].size = m_responseBuffers[i].size;
|
||||
}
|
||||
// input buffers
|
||||
for (size_t i = 0; i < m_paramBuffers.size(); ++i)
|
||||
{
|
||||
vectorArray[m_responseBuffers.size() + i].baseVirt = MEMPTR<uint8>(m_paramBuffers[i].ptr);
|
||||
vectorArray[m_responseBuffers.size() + i].basePhys = nullptr;
|
||||
vectorArray[m_responseBuffers.size() + i].size = m_paramBuffers[i].size;
|
||||
}
|
||||
IOS_ERROR r = coreinit::IOS_Ioctlv(m_client.GetDevHandle(), 0, m_responseBuffers.size(), m_paramBuffers.size(), vectorArray.GetPointer());
|
||||
if ( (r&0x80000000) != 0)
|
||||
{
|
||||
cemu_assert_unimplemented(); // todo - handle submission errors
|
||||
}
|
||||
uint32be resultCode = ReadResponse<uint32be>();
|
||||
if (!NN_RESULT_IS_FAILURE((uint32)resultCode))
|
||||
{
|
||||
for (auto& bufCopy : m_bufferCopiesOut)
|
||||
{
|
||||
memcpy(bufCopy.dst, bufCopy.src, bufCopy.size);
|
||||
}
|
||||
}
|
||||
return static_cast<nnResult>(resultCode);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ReadResponse()
|
||||
{
|
||||
cemu_assert(m_responseReadIndex + sizeof(T) <= m_responseBuffers[0].size);
|
||||
T value;
|
||||
memcpy(&value, m_responseBuffers[0].ptr + m_responseReadIndex, sizeof(T));
|
||||
m_responseReadIndex += sizeof(T);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
struct BufferCopyOut
|
||||
{
|
||||
BufferCopyOut(void* dst, void* src, uint32 size) : dst(dst), src(src), size(size) {}
|
||||
|
||||
void* dst;
|
||||
void* src;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
void WriteInOutBuffer(MEMPTR<uint8> ptr, uint32 size, bool isOutput)
|
||||
{
|
||||
uint32 headSize = (0x40 - (ptr.GetMPTR()&0x3F))&0x3F;
|
||||
headSize = std::min<uint32>(headSize, size);
|
||||
uint32 alignedSize = size - headSize;
|
||||
uint32 tailSize = alignedSize - (alignedSize&~0x3F);
|
||||
alignedSize -= tailSize;
|
||||
// verify
|
||||
cemu_assert_debug(headSize + alignedSize + tailSize == size);
|
||||
cemu_assert_debug(alignedSize == 0 || ((ptr.GetMPTR()+headSize)&0x3F) == 0);
|
||||
cemu_assert_debug(tailSize == 0 || ((ptr.GetMPTR()+headSize+alignedSize)&0x3F) == 0);
|
||||
|
||||
if (isOutput)
|
||||
cemu_assert(m_responseBuffers.size()+2 <= m_responseBuffers.capacity());
|
||||
else
|
||||
cemu_assert(m_paramBuffers.size()+2 <= m_paramBuffers.capacity());
|
||||
IOVectorBuffer alignedBuffer;
|
||||
alignedBuffer.ptr = ptr + headSize;
|
||||
alignedBuffer.size = alignedSize;
|
||||
alignedBuffer.isExternalBuffer = true;
|
||||
if (isOutput)
|
||||
m_responseBuffers.emplace_back(alignedBuffer);
|
||||
else
|
||||
m_paramBuffers.emplace_back(alignedBuffer);
|
||||
IPCBuffer* headAndTailBuffer = m_client.AllocateCommandBuffer();
|
||||
IOVectorBuffer headAndTail;
|
||||
headAndTail.ptr = headAndTailBuffer->data + (0x40 - headSize);
|
||||
headAndTail.size = 128 - (0x40 - headSize);
|
||||
headAndTail.isExternalBuffer = false;
|
||||
if (headSize > 0)
|
||||
{
|
||||
if (isOutput)
|
||||
m_bufferCopiesOut.emplace_back(ptr, headAndTailBuffer->data + 0x40 - headSize, headSize);
|
||||
else
|
||||
memcpy(headAndTailBuffer->data + 0x40 - headSize, ptr, headSize);
|
||||
}
|
||||
if (tailSize > 0)
|
||||
{
|
||||
if (isOutput)
|
||||
m_bufferCopiesOut.emplace_back(ptr + headSize + alignedSize, headAndTailBuffer->data + 0x40, tailSize);
|
||||
else
|
||||
memcpy(headAndTailBuffer->data + 0x40, ptr + headSize + alignedSize, tailSize);
|
||||
}
|
||||
if (isOutput)
|
||||
m_responseBuffers.emplace_back(headAndTail);
|
||||
else
|
||||
m_paramBuffers.emplace_back(headAndTail);
|
||||
// serialize into parameter stream
|
||||
WriteParam<uint32be>(alignedSize);
|
||||
WriteParam<uint8be>(0); // ukn4
|
||||
WriteParam<uint8be>(0); // ukn5
|
||||
WriteParam<uint8be>((uint8)headSize);
|
||||
WriteParam<uint8be>((uint8)tailSize);
|
||||
}
|
||||
|
||||
IPCServiceClient& m_client;
|
||||
boost::container::static_vector<IOVectorBuffer, 8> m_paramBuffers;
|
||||
boost::container::static_vector<IOVectorBuffer, 8> m_responseBuffers;
|
||||
sint32 m_paramWriteIndex{0};
|
||||
sint32 m_responseReadIndex{0};
|
||||
boost::container::static_vector<BufferCopyOut, 16> m_bufferCopiesOut;
|
||||
};
|
||||
|
||||
IPCServiceClient()
|
||||
{
|
||||
}
|
||||
|
||||
~IPCServiceClient()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void Initialize(std::string_view devicePath, uint8_t* buffer, uint32_t bufferSize)
|
||||
{
|
||||
m_devicePath = devicePath;
|
||||
m_buffer = buffer;
|
||||
m_bufferSize = bufferSize;
|
||||
|
||||
static_assert(sizeof(IPCBuffer) == 256);
|
||||
size_t numCommandBuffers = m_bufferSize / sizeof(IPCBuffer);
|
||||
|
||||
m_commandBuffersFree.resize(numCommandBuffers);
|
||||
for (size_t i = 0; i < numCommandBuffers; ++i)
|
||||
{
|
||||
m_commandBuffersFree[i] = reinterpret_cast<IPCBuffer*>(m_buffer + i * sizeof(IPCBuffer));
|
||||
}
|
||||
m_clientHandle = coreinit::IOS_Open(m_devicePath.c_str(), 0);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
if (m_clientHandle != 0)
|
||||
{
|
||||
coreinit::IOS_Close(m_clientHandle);
|
||||
m_clientHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
IPCServiceCall Begin(uint32_t serviceId, uint32_t commandId)
|
||||
{
|
||||
return IPCServiceCall(*this, serviceId, commandId);
|
||||
}
|
||||
|
||||
IOSDevHandle GetDevHandle() const
|
||||
{
|
||||
cemu_assert(m_clientHandle != 0);
|
||||
return m_clientHandle;
|
||||
}
|
||||
private:
|
||||
struct IPCBuffer
|
||||
{
|
||||
uint8 data[256];
|
||||
};
|
||||
|
||||
IPCBuffer* AllocateCommandBuffer()
|
||||
{
|
||||
cemu_assert(m_commandBuffersFree.size() > 0);
|
||||
IPCBuffer* buf = m_commandBuffersFree.back();
|
||||
m_commandBuffersFree.pop_back();
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ReleaseCommandBuffer(IPCBuffer* buffer)
|
||||
{
|
||||
m_commandBuffersFree.emplace_back(buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_devicePath;
|
||||
IOSDevHandle m_clientHandle{0};
|
||||
uint8_t* m_buffer{nullptr};
|
||||
uint32_t m_bufferSize{0};
|
||||
std::vector<IPCBuffer*> m_commandBuffersFree;
|
||||
};
|
||||
|
|
@ -763,6 +763,9 @@ namespace nsyshid::backend::libusb
|
|||
int DeviceLibusb::ClaimAllInterfaces(uint8 config_num)
|
||||
{
|
||||
const int ret = DoForEachInterface(m_config_descriptors, config_num, [this](uint8 i) {
|
||||
// On macos detaching would fail without root or entitlement.
|
||||
// We assume user is using GCAdapterDriver and therefore don't want to detach anything
|
||||
#if !defined(__APPLE__)
|
||||
if (libusb_kernel_driver_active(this->m_libusbHandle, i))
|
||||
{
|
||||
const int ret2 = libusb_detach_kernel_driver(this->m_libusbHandle, i);
|
||||
|
|
@ -773,6 +776,7 @@ namespace nsyshid::backend::libusb
|
|||
return ret2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return libusb_claim_interface(this->m_libusbHandle, i);
|
||||
});
|
||||
if (ret < LIBUSB_SUCCESS)
|
||||
|
|
|
|||
|
|
@ -43,17 +43,8 @@ set_property(TARGET CemuComponents PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$
|
|||
target_include_directories(CemuComponents PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuComponents PRIVATE
|
||||
CemuCafe
|
||||
CemuCommon
|
||||
CemuConfig
|
||||
CemuGui
|
||||
CemuUtil
|
||||
Boost::headers
|
||||
CURL::libcurl
|
||||
OpenSSL::Crypto
|
||||
OpenSSL::SSL
|
||||
pugixml::pugixml
|
||||
ZLIB::ZLIB
|
||||
)
|
||||
|
||||
# PUBLIC because fmt/format.h is included in ExpressionParser/ExpressionParser.h
|
||||
|
|
|
|||
|
|
@ -224,6 +224,24 @@ bool cemuLog_log(LogType type, std::u8string_view text)
|
|||
return cemuLog_log(type, s);
|
||||
}
|
||||
|
||||
void cemuLog_logHexDump(LogType type, const void* data, size_t size, size_t lineSize)
|
||||
{
|
||||
const uint8* dataU8 = static_cast<const uint8*>(data);
|
||||
std::vector<char> hexLine;
|
||||
hexLine.resize(6 + lineSize * 3 + 1, ' ');
|
||||
for (size_t i = 0; i < size; i += lineSize)
|
||||
{
|
||||
sprintf(hexLine.data(), "%04X: ", (int)i);
|
||||
size_t remainingSize = std::min<size_t>(lineSize, size - i);
|
||||
for (size_t j=0; j<remainingSize; j++)
|
||||
sprintf(hexLine.data() + 6 + j * 3, "%02X ", dataU8[j]);
|
||||
dataU8 += remainingSize;
|
||||
if (remainingSize == lineSize)
|
||||
hexLine.resize(6 + remainingSize * 3 + 1);
|
||||
cemuLog_log(type, hexLine.data());
|
||||
}
|
||||
}
|
||||
|
||||
void cemuLog_waitForFlush()
|
||||
{
|
||||
cemuLog_createLogFile(false);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ bool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args)
|
|||
|
||||
#define cemuLog_logDebugOnce(...) { static bool _not_first_call = false; if (!_not_first_call) { _not_first_call = true; cemuLog_logDebug(__VA_ARGS__); } }
|
||||
|
||||
// utility function for logging binary data as a hex dump
|
||||
void cemuLog_logHexDump(LogType type, const void* data, size_t size, size_t lineSize = 16);
|
||||
|
||||
// cafe lib calls
|
||||
bool cemuLog_advancedPPCLoggingEnabled();
|
||||
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ const char* ppcAssembler_getInstructionName(uint32 ppcAsmOp)
|
|||
case PPCASM_OP_PS_NMSUB: return "PS_NMSUB";
|
||||
|
||||
case PPCASM_OP_FMR: return "FMR";
|
||||
case PPCASM_OP_FABS: return "FABS";
|
||||
case PPCASM_OP_FNEG: return "FNEG";
|
||||
case PPCASM_OP_FRSP: return "FRSP";
|
||||
case PPCASM_OP_FRSQRTE: return "FRSQRTE";
|
||||
|
|
@ -1325,6 +1326,7 @@ PPCInstructionDef ppcInstructionTable[] =
|
|||
{PPCASM_OP_FCMPO, 0, 63, 32|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_X_FP_CMP, FLG_DEFAULT, 0, 0, nullptr },
|
||||
{PPCASM_OP_FNEG, 0, 63, 40|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },
|
||||
{PPCASM_OP_FMR, 0, 63, 72|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },
|
||||
{PPCASM_OP_FABS, 0, 63, 264|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -3194,6 +3196,13 @@ void ppcAsmTestDisassembler()
|
|||
checkOpFPR(0, 7);
|
||||
checkOpFPR(1, 12);
|
||||
|
||||
// FABS
|
||||
_testAsm(0xFC200A10, "fabs f1, f1");
|
||||
disassemble(0xFC200A10, PPCASM_OP_FABS);
|
||||
checkOperandMask(true, true);
|
||||
checkOpFPR(0, 1);
|
||||
checkOpFPR(1, 1);
|
||||
|
||||
// FCTIWZ
|
||||
_testAsm(0xFD80401E, "fctiwz f12, f8");
|
||||
disassemble(0xFD80401E, PPCASM_OP_FCTIWZ);
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ enum PPCASM_OP
|
|||
|
||||
// FP
|
||||
PPCASM_OP_FMR,
|
||||
PPCASM_OP_FABS,
|
||||
PPCASM_OP_FNEG,
|
||||
PPCASM_OP_FRSP,
|
||||
PPCASM_OP_FRSQRTE,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ CURLcode _sslctx_function_NUS(CURL* curl, void* sslctx, void* param)
|
|||
{
|
||||
cemuLog_log(LogType::Force, "Invalid CA certificate (102)");
|
||||
}
|
||||
if (iosuCrypto_addCACertificate(sslctx, 0x69) == false)
|
||||
if (iosuCrypto_addCACertificate(sslctx, 105) == false)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Invalid CA certificate (105)");
|
||||
}
|
||||
|
|
@ -79,7 +79,6 @@ CURLcode _sslctx_function_OLIVE(CURL* curl, void* sslctx, void* param)
|
|||
cemuLog_log(LogType::Force, "Olive client certificate error");
|
||||
}
|
||||
|
||||
// NSSLAddServerPKIGroups(sslCtx, 3, &x, &y);
|
||||
{
|
||||
std::vector<sint16> certGroups = {
|
||||
100, 101, 102, 103, 104, 105,
|
||||
|
|
@ -99,6 +98,32 @@ CURLcode _sslctx_function_OLIVE(CURL* curl, void* sslctx, void* param)
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode _sslctx_function_CUSTOM(CURL* curl, void* sslctx, void* param)
|
||||
{
|
||||
CurlRequestHelper* requestHelper = (CurlRequestHelper*)param;
|
||||
for (auto& caCertId : requestHelper->GetCaCertIds())
|
||||
{
|
||||
if (iosuCrypto_addCACertificate(sslctx, caCertId) == false)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Invalid CA certificate ({})", caCertId);
|
||||
}
|
||||
}
|
||||
for (auto& clientCertId : requestHelper->GetClientCertIds())
|
||||
{
|
||||
if (iosuCrypto_addCACertificate(sslctx, clientCertId) == false)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Invalid client certificate ({})", clientCertId);
|
||||
}
|
||||
}
|
||||
SSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);
|
||||
if (requestHelper->GetClientCertIds().empty())
|
||||
SSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_NONE, nullptr);
|
||||
else
|
||||
SSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_PEER, nullptr);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CurlRequestHelper::CurlRequestHelper()
|
||||
{
|
||||
m_curl = curl_easy_init();
|
||||
|
|
@ -162,6 +187,11 @@ void CurlRequestHelper::initate(NetworkService service, std::string url, SERVER_
|
|||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_OLIVE);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);
|
||||
}
|
||||
else if (sslContext == SERVER_SSL_CONTEXT::CUSTOM)
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_CUSTOM);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
cemu_assert(false);
|
||||
|
|
@ -218,7 +248,8 @@ bool CurlRequestHelper::submitRequest(bool isPost)
|
|||
// post
|
||||
if (isPost)
|
||||
{
|
||||
if (!m_isUsingMultipartFormData) {
|
||||
if (!m_isUsingMultipartFormData)
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_postData.data());
|
||||
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, m_postData.size());
|
||||
|
|
@ -242,9 +273,14 @@ bool CurlRequestHelper::submitRequest(bool isPost)
|
|||
// check response code
|
||||
long httpCode = 0;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &httpCode);
|
||||
m_httpStatusCode = httpCode;
|
||||
if (httpCode != 200)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "HTTP request received response {} but expected 200", httpCode);
|
||||
char* effectiveUrl = nullptr;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &effectiveUrl);
|
||||
if (effectiveUrl)
|
||||
cemuLog_log(LogType::Force, "Request: {}", effectiveUrl);
|
||||
// error status codes (4xx or 5xx range) are always considered a failed request, except for code 400 which is usually returned as a response to failed logins etc.
|
||||
if (httpCode >= 400 && httpCode <= 599 && httpCode != 400)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ public:
|
|||
IDBE, // idbe-wup.
|
||||
TAGAYA, // tagaya.wup.shop.nintendo.net
|
||||
OLIVE, // olv.
|
||||
CUSTOM, // use cert parameters
|
||||
};
|
||||
|
||||
CurlRequestHelper();
|
||||
|
|
@ -56,6 +57,41 @@ public:
|
|||
m_isUsingMultipartFormData = isUsingMultipartFormData;
|
||||
}
|
||||
|
||||
void ClearCaCertIds()
|
||||
{
|
||||
m_caCertIds.clear();
|
||||
}
|
||||
|
||||
void ClearClientCertIds()
|
||||
{
|
||||
m_clientCertIds.clear();
|
||||
}
|
||||
|
||||
void AddCaCertId(sint32 caCertId)
|
||||
{
|
||||
m_caCertIds.emplace_back(caCertId);
|
||||
}
|
||||
|
||||
void AddClientCertId(sint32 clientCertId)
|
||||
{
|
||||
m_clientCertIds.emplace_back(clientCertId);
|
||||
}
|
||||
|
||||
std::vector<sint32> GetCaCertIds() const
|
||||
{
|
||||
return m_caCertIds;
|
||||
}
|
||||
|
||||
std::vector<sint32> GetClientCertIds() const
|
||||
{
|
||||
return m_clientCertIds;
|
||||
}
|
||||
|
||||
sint32 GetHTTPStatusCode() const
|
||||
{
|
||||
return m_httpStatusCode;
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t __curlWriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
|
||||
|
||||
|
|
@ -69,6 +105,11 @@ private:
|
|||
void* m_writeCallbackUserData{};
|
||||
|
||||
bool m_isUsingMultipartFormData = false;
|
||||
// cert data
|
||||
std::vector<sint32> m_caCertIds;
|
||||
std::vector<sint32> m_clientCertIds;
|
||||
// result
|
||||
sint32 m_httpStatusCode{ 0 };
|
||||
};
|
||||
|
||||
class CurlSOAPHelper // todo - make this use CurlRequestHelper
|
||||
|
|
|
|||
|
|
@ -59,9 +59,6 @@ target_precompile_headers(CemuCommon PUBLIC precompiled.h)
|
|||
target_include_directories(CemuCommon PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuCommon PRIVATE
|
||||
CemuCafe
|
||||
CemuConfig
|
||||
CemuComponents
|
||||
Boost::nowide
|
||||
Boost::filesystem
|
||||
glm::glm
|
||||
|
|
|
|||
|
|
@ -7,12 +7,23 @@ template <size_t N>
|
|||
class CafeString // fixed buffer size, null-terminated, PPC char
|
||||
{
|
||||
public:
|
||||
constexpr static size_t Size()
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
// checks whether the string and a null terminator can fit into the buffer
|
||||
bool CanHoldString(std::string_view sv) const
|
||||
{
|
||||
return sv.size() < N;
|
||||
}
|
||||
|
||||
bool assign(std::string_view sv)
|
||||
{
|
||||
if (sv.size()+1 >= N)
|
||||
if (sv.size() >= N)
|
||||
{
|
||||
memcpy(data, sv.data(), sv.size()-1);
|
||||
data[sv.size()-1] = '\0';
|
||||
memcpy(data, sv.data(), N-1);
|
||||
data[N-1] = '\0';
|
||||
return false;
|
||||
}
|
||||
memcpy(data, sv.data(), sv.size());
|
||||
|
|
@ -20,11 +31,50 @@ class CafeString // fixed buffer size, null-terminated, PPC char
|
|||
return true;
|
||||
}
|
||||
|
||||
const char* c_str()
|
||||
void Copy(CafeString<N>& other)
|
||||
{
|
||||
memcpy(data, other.data, N);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return data[0] == '\0';
|
||||
}
|
||||
|
||||
const char* c_str() const
|
||||
{
|
||||
return (const char*)data;
|
||||
}
|
||||
|
||||
void ClearAllBytes()
|
||||
{
|
||||
memset(data, 0, N);
|
||||
}
|
||||
|
||||
auto operator<=>(const CafeString<N>& other) const
|
||||
{
|
||||
for (size_t i = 0; i < N; i++)
|
||||
{
|
||||
if (data[i] != other.data[i])
|
||||
return data[i] <=> other.data[i];
|
||||
if (data[i] == '\0')
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
|
||||
bool operator==(const CafeString<N>& other) const
|
||||
{
|
||||
for (size_t i = 0; i < N; i++)
|
||||
{
|
||||
if (data[i] != other.data[i])
|
||||
return false;
|
||||
if (data[i] == '\0')
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8be data[N];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ GLFUNC(PFNGLPROGRAMUNIFORM1IPROC, glProgramUniform1i)
|
|||
GLFUNC(PFNGLPROGRAMUNIFORM2IPROC, glProgramUniform2i)
|
||||
GLFUNC(PFNGLPROGRAMUNIFORM1IVPROC, glProgramUniform1iv)
|
||||
GLFUNC(PFNGLPROGRAMUNIFORM4IVPROC, glProgramUniform4iv)
|
||||
GLFUNC(PFNGLPROGRAMUNIFORM1IPROC, glProgramUniform1f)
|
||||
GLFUNC(PFNGLPROGRAMUNIFORM1FVPROC, glProgramUniform1fv)
|
||||
GLFUNC(PFNGLPROGRAMUNIFORM2FVPROC, glProgramUniform2fv)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
uint32 coreinit_allocFromSysArea(uint32 size, uint32 alignment);
|
||||
class SysAllocatorBase;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#ifdef __GNUC__
|
||||
#define ATTRIBUTE_AVX2 __attribute__((target("avx2")))
|
||||
#define ATTRIBUTE_SSE41 __attribute__((target("sse4.1")))
|
||||
|
|
@ -9,6 +8,8 @@
|
|||
#define ATTRIBUTE_AESNI
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
class CPUFeaturesImpl
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -31,11 +31,8 @@ endif()
|
|||
target_include_directories(CemuAudio PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuAudio PRIVATE
|
||||
CemuCafe
|
||||
CemuGui
|
||||
CemuCommon
|
||||
CemuConfig
|
||||
CemuUtil
|
||||
CemuGui
|
||||
)
|
||||
|
||||
if(ENABLE_CUBEB)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "config/ActiveSettings.h"
|
||||
#include "config/LaunchSettings.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||
|
||||
void ActiveSettings::SetPaths(bool isPortableMode,
|
||||
const fs::path& executablePath,
|
||||
|
|
@ -112,6 +113,18 @@ GraphicAPI ActiveSettings::GetGraphicsAPI()
|
|||
return api;
|
||||
}
|
||||
|
||||
float ActiveSettings::GetTVGamma()
|
||||
{
|
||||
const auto& config = GetConfig();
|
||||
return config.overrideGammaValue.GetValue() + LatteGPUState.tvGamma * !config.overrideAppGammaPreference.GetValue();
|
||||
}
|
||||
|
||||
float ActiveSettings::GetDRCGamma()
|
||||
{
|
||||
const auto& config = GetConfig();
|
||||
return config.overrideGammaValue.GetValue() + LatteGPUState.drcGamma * !config.overrideAppGammaPreference.GetValue();
|
||||
}
|
||||
|
||||
bool ActiveSettings::AudioOutputOnlyAux()
|
||||
{
|
||||
return s_audio_aux_only;
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ public:
|
|||
[[nodiscard]] static bool WaitForGX2DrawDoneEnabled();
|
||||
[[nodiscard]] static GraphicAPI GetGraphicsAPI();
|
||||
|
||||
// gamma
|
||||
[[nodiscard]] static float GetTVGamma();
|
||||
[[nodiscard]] static float GetDRCGamma();
|
||||
|
||||
// audio
|
||||
[[nodiscard]] static bool AudioOutputOnlyAux();
|
||||
static void EnableAudioOnlyAux(bool state);
|
||||
|
|
|
|||
|
|
@ -16,11 +16,7 @@ set_property(TARGET CemuConfig PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<C
|
|||
target_include_directories(CemuConfig PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuConfig PRIVATE
|
||||
CemuCafe
|
||||
CemuCommon
|
||||
CemuGui
|
||||
CemuUtil
|
||||
Boost::headers
|
||||
Boost::program_options
|
||||
pugixml::pugixml
|
||||
)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,13 @@ XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
|
|||
graphic.get("vkDevice", vk_graphic_device_uuid);
|
||||
mtl_graphic_device_uuid = graphic.get("mtlDevice", 0);
|
||||
vsync = graphic.get("VSync", 0);
|
||||
overrideAppGammaPreference = graphic.get("OverrideAppGammaPreference", false);
|
||||
overrideGammaValue = graphic.get("OverrideGammaValue", 2.2f);
|
||||
if(overrideGammaValue < 0)
|
||||
overrideGammaValue = 2.2f;
|
||||
userDisplayGamma = graphic.get("UserDisplayGamma", 2.2f);
|
||||
if(userDisplayGamma < 0)
|
||||
userDisplayGamma = 2.2f;
|
||||
gx2drawdone_sync = graphic.get("GX2DrawdoneSync", true);
|
||||
upscale_filter = graphic.get("UpscaleFilter", kBicubicHermiteFilter);
|
||||
downscale_filter = graphic.get("DownscaleFilter", kLinearFilter);
|
||||
|
|
@ -351,6 +358,9 @@ XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
|
|||
graphic.set("vkDevice", vk_graphic_device_uuid);
|
||||
graphic.set("mtlDevice", mtl_graphic_device_uuid);
|
||||
graphic.set("VSync", vsync);
|
||||
graphic.set("OverrideAppGammaPreference", overrideAppGammaPreference);
|
||||
graphic.set("OverrideGammaValue", overrideGammaValue);
|
||||
graphic.set("UserDisplayGamma", userDisplayGamma);
|
||||
graphic.set("GX2DrawdoneSync", gx2drawdone_sync);
|
||||
graphic.set("ForceMeshShaders", force_mesh_shaders);
|
||||
//graphic.set("PrecompiledShaders", precompiled_shaders.GetValue());
|
||||
|
|
|
|||
|
|
@ -440,6 +440,11 @@ struct CemuConfig
|
|||
ConfigValue<bool> async_compile{ true };
|
||||
ConfigValue<bool> force_mesh_shaders{ false };
|
||||
|
||||
// Gamma
|
||||
ConfigValue<bool> overrideAppGammaPreference{ false };
|
||||
ConfigValue<float> overrideGammaValue{ 2.2f };
|
||||
ConfigValue<float> userDisplayGamma { 2.2f }; // 0 = sRGB, >0 gamma
|
||||
|
||||
ConfigValue<bool> vk_accurate_barriers{ true };
|
||||
|
||||
struct
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <shared_mutex>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
template<typename TType>
|
||||
class ConfigValueAtomic
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ AudioDebuggerWindow::AudioDebuggerWindow(wxFrame& parent)
|
|||
|
||||
sizer->Add(voiceListbox, 1, wxEXPAND | wxBOTTOM, 0);
|
||||
|
||||
voiceListbox->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(AudioDebuggerWindow::OnVoiceListRightClick), NULL, this);
|
||||
voiceListbox->Bind(wxEVT_RIGHT_DOWN, &AudioDebuggerWindow::OnVoiceListRightClick, this);
|
||||
|
||||
mainPane->SetSizer(sizer);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
add_library(CemuWxGui
|
||||
add_library(CemuWxGui STATIC
|
||||
canvas/IRenderCanvas.h
|
||||
canvas/OpenGLCanvas.cpp
|
||||
canvas/OpenGLCanvas.h
|
||||
|
|
@ -76,8 +76,6 @@ add_library(CemuWxGui
|
|||
input/InputAPIAddWindow.h
|
||||
input/InputSettings2.cpp
|
||||
input/InputSettings2.h
|
||||
input/PairingDialog.cpp
|
||||
input/PairingDialog.h
|
||||
input/panels/ClassicControllerInputPanel.cpp
|
||||
input/panels/ClassicControllerInputPanel.h
|
||||
input/panels/InputPanel.cpp
|
||||
|
|
@ -118,13 +116,20 @@ add_library(CemuWxGui
|
|||
wxHelper.h
|
||||
)
|
||||
|
||||
if(ENABLE_METAL)
|
||||
if (ENABLE_METAL)
|
||||
target_sources(CemuWxGui PRIVATE
|
||||
canvas/MetalCanvas.cpp
|
||||
canvas/MetalCanvas.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_BLUEZ)
|
||||
target_sources(CemuWxGui PRIVATE
|
||||
input/PairingDialog.cpp
|
||||
input/PairingDialog.h
|
||||
)
|
||||
endif()
|
||||
|
||||
set_property(TARGET CemuWxGui PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
|
||||
|
|
@ -133,20 +138,16 @@ target_include_directories(CemuWxGui PUBLIC "../")
|
|||
target_include_directories(CemuWxGui PUBLIC ${RAPIDJSON_INCLUDE_DIRS})
|
||||
|
||||
target_link_libraries(CemuWxGui PRIVATE
|
||||
CemuAudio
|
||||
CemuCafe
|
||||
CemuCommon
|
||||
CemuComponents
|
||||
CemuConfig
|
||||
CemuInput
|
||||
CemuResource
|
||||
CemuUtil
|
||||
Boost::headers
|
||||
CURL::libcurl
|
||||
libzip::zip
|
||||
OpenSSL::Crypto
|
||||
pugixml::pugixml
|
||||
ZArchive::zarchive
|
||||
CemuComponents
|
||||
SDL2::SDL2
|
||||
pugixml::pugixml
|
||||
CemuCafe
|
||||
PUBLIC
|
||||
CURL::libcurl
|
||||
)
|
||||
|
||||
if(ENABLE_WXWIDGETS AND UNIX AND NOT APPLE)
|
||||
|
|
@ -168,7 +169,7 @@ if(UNIX AND NOT APPLE)
|
|||
endif()
|
||||
if (ENABLE_WXWIDGETS)
|
||||
# PUBLIC because wx/app.h is included in CemuApp.h
|
||||
target_link_libraries(CemuWxGui PUBLIC wx::base wx::core wx::gl wx::propgrid wx::xrc)
|
||||
target_link_libraries(CemuWxGui PUBLIC wxWidgets::wxWidgets)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ void unused_translation_dummy()
|
|||
}
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <shlobj_core.h>
|
||||
#include <shlobj.h>
|
||||
fs::path GetAppDataRoamingPath()
|
||||
{
|
||||
PWSTR path = nullptr;
|
||||
|
|
@ -295,6 +295,10 @@ bool CemuApp::OnInit()
|
|||
{
|
||||
MSWEnableDarkMode(DarkMode_Always);
|
||||
}
|
||||
|
||||
// extend tooltip duration to the maximum possible value
|
||||
wxToolTip::SetDelay(-1);
|
||||
wxToolTip::SetAutoPop(MAKELPARAM(std::numeric_limits<short>::max(),0));
|
||||
#endif
|
||||
|
||||
for (auto&& path : failedWriteAccess)
|
||||
|
|
|
|||
|
|
@ -590,16 +590,16 @@ void CemuUpdateWindow::OnClose(wxCloseEvent& event)
|
|||
if (m_restartRequired && !m_restartFile.empty() && fs::exists(m_restartFile))
|
||||
{
|
||||
PROCESS_INFORMATION pi{};
|
||||
STARTUPINFO si{};
|
||||
STARTUPINFOW si{};
|
||||
si.cb = sizeof(si);
|
||||
|
||||
std::wstring cmdline = GetCommandLineW();
|
||||
const auto index = cmdline.find('"', 1);
|
||||
cemu_assert_debug(index != std::wstring::npos);
|
||||
cmdline = L"\"" + m_restartFile.wstring() + L"\"" + cmdline.substr(index + 1);
|
||||
cmdline = L"\"" + boost::nowide::widen(_pathToUtf8(m_restartFile)) + L"\"" + cmdline.substr(index + 1);
|
||||
|
||||
HANDLE lock = CreateMutex(nullptr, TRUE, L"Global\\cemu_update_lock");
|
||||
CreateProcess(nullptr, (wchar_t*)cmdline.c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
|
||||
HANDLE lock = CreateMutexW(nullptr, TRUE, L"Global\\cemu_update_lock");
|
||||
CreateProcessW(nullptr, (wchar_t*)cmdline.c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ size_t DownloadGraphicPacksWindow::curlDownloadFile_writeData(void *ptr, size_t
|
|||
return writeSize;
|
||||
}
|
||||
|
||||
int DownloadGraphicPacksWindow::progress_callback(curlDownloadFileState_t* downloadState, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
int DownloadGraphicPacksWindow::progress_callback(curlDownloadFileState_t* downloadState, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
if (dltotal > 1.0)
|
||||
downloadState->progress = dlnow / dltotal;
|
||||
|
|
@ -47,7 +47,7 @@ bool DownloadGraphicPacksWindow::curlDownloadFile(const char *url, curlDownloadF
|
|||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlDownloadFile_writeData);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, downloadState);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, downloadState);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <curl/system.h>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/gauge.h>
|
||||
|
||||
|
|
@ -55,6 +57,6 @@ private:
|
|||
std::unique_ptr<curlDownloadFileState_t> m_downloadState;
|
||||
|
||||
static size_t curlDownloadFile_writeData(void* ptr, size_t size, size_t nmemb, curlDownloadFileState_t* downloadState);
|
||||
static int progress_callback(curlDownloadFileState_t* downloadState, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
static int progress_callback(curlDownloadFileState_t* downloadState, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
|
||||
static bool curlDownloadFile(const char* url, curlDownloadFileState_t* downloadState);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -400,6 +400,55 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)
|
|||
graphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);
|
||||
}
|
||||
|
||||
{
|
||||
auto box = new wxStaticBox(graphics_panel, wxID_ANY, _("Gamma settings"));
|
||||
auto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
auto row = new wxFlexGridSizer(0, 2, 0, 0);
|
||||
row->SetFlexibleDirection(wxBOTH);
|
||||
row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
||||
|
||||
auto targetGammaLabel = new wxStaticText(box, wxID_ANY, _("Target Gamma"));
|
||||
row->Add(targetGammaLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
m_overrideGammaValue = new wxSpinCtrlDouble(box, wxID_ANY, "2.2f", wxDefaultPosition, {230, -1}, wxSP_ARROW_KEYS, 0.1f, 4.0f, 2.2f, 0.1f);
|
||||
row->Add(m_overrideGammaValue, 0, wxALL, 5);
|
||||
auto targetGammaTooltip = _("The display gamma to reproduce\nIf you are unsure, set this to 2.2");
|
||||
targetGammaLabel->SetToolTip(targetGammaTooltip);
|
||||
m_overrideGammaValue->SetToolTip(targetGammaTooltip);
|
||||
|
||||
|
||||
auto displayGammaLabel = new wxStaticText(box, wxID_ANY, _("Display Gamma"));
|
||||
row->Add(displayGammaLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxBoxSizer* srgbCheckBoxSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
row->Add(srgbCheckBoxSizer);
|
||||
m_userDisplayGamma = new wxSpinCtrlDouble(box, wxID_ANY, "2.2f", wxDefaultPosition, {230, -1}, wxSP_ARROW_KEYS, 0.1f, 4.0f, 2.2f, 0.1f);
|
||||
|
||||
auto displayGammaTooltip = _("The gamma of your monitor\nIf you are unsure, set this to 2.2");
|
||||
m_userDisplayGamma->SetToolTip(displayGammaTooltip);
|
||||
displayGammaLabel->SetToolTip(displayGammaTooltip);
|
||||
|
||||
m_userDisplayisSRGB = new wxCheckBox(box, wxID_ANY, "sRGB", wxDefaultPosition, wxDefaultSize);
|
||||
m_userDisplayisSRGB->SetToolTip(_("Select this if Cemu is being displayed using a piecewise sRGB gamma curve.\n"
|
||||
"This is typically not the case so you can probably leave this unchecked.\n"
|
||||
"Exceptions include HDR displays (with HDR enabled), calibrated SDR displays with Windows 11's Auto Color Management enabled, "
|
||||
"or when using a display profile with a VCGT tag that targets piecewise sRGB.\n"
|
||||
"When this box is selected Cemu will compensate for the piecewise curve to approximate the pure gamma curve of a TV.\n"
|
||||
"Colors will be more accurate, especially in dark scenes, but this may result in banding or crushed shadows, "
|
||||
"so it is best if you display Cemu with pure gamma and do not use this setting."));
|
||||
m_userDisplayisSRGB->Bind(wxEVT_CHECKBOX, &GeneralSettings2::OnUserDisplaySRGBSelected, this);
|
||||
|
||||
srgbCheckBoxSizer->Add(m_userDisplayGamma, 0, wxALL, 5);
|
||||
srgbCheckBoxSizer->Add(m_userDisplayisSRGB, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
row->Add(new wxStaticText(box, wxID_ANY, _("Override Gamma")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
m_overrideGamma = new wxCheckBox(box, wxID_ANY, "", wxDefaultPosition, {230, -1});
|
||||
m_overrideGamma->SetToolTip(_("Ignore title's gamma preference"));
|
||||
row->Add(m_overrideGamma, 0, wxALL, 5);
|
||||
|
||||
box_sizer->Add(row, 0, wxEXPAND, 5);
|
||||
graphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);
|
||||
}
|
||||
|
||||
{
|
||||
wxString choices[] = { _("Bilinear"), _("Bicubic"), _("Hermite"), _("Nearest Neighbor") };
|
||||
m_upscale_filter = new wxRadioBox(graphics_panel, wxID_ANY, _("Upscale filter"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 5, wxRA_SPECIFY_COLS);
|
||||
|
|
@ -1171,6 +1220,9 @@ void GeneralSettings2::StoreConfig()
|
|||
|
||||
|
||||
config.vsync = m_vsync->GetSelection();
|
||||
config.overrideAppGammaPreference = m_overrideGamma->IsChecked();
|
||||
config.overrideGammaValue = m_overrideGammaValue->GetValue();
|
||||
config.userDisplayGamma = m_userDisplayGamma->GetValue() * !m_userDisplayisSRGB->GetValue();
|
||||
config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();
|
||||
config.force_mesh_shaders = m_force_mesh_shaders->IsChecked();
|
||||
config.async_compile = m_async_compile->IsChecked();
|
||||
|
|
@ -1789,6 +1841,15 @@ void GeneralSettings2::ApplyConfig()
|
|||
// graphics
|
||||
m_graphic_api->SetSelection(config.graphic_api);
|
||||
m_vsync->SetSelection(config.vsync);
|
||||
m_overrideGamma->SetValue(config.overrideAppGammaPreference);
|
||||
m_overrideGammaValue->SetValue(config.overrideGammaValue);
|
||||
m_userDisplayisSRGB->SetValue(config.userDisplayGamma == 0.0f);
|
||||
m_userDisplayGamma->SetValue(config.userDisplayGamma);
|
||||
if(m_userDisplayisSRGB->GetValue())
|
||||
{
|
||||
m_userDisplayGamma->Disable();
|
||||
m_userDisplayGamma->SetValue(2.2f);
|
||||
}
|
||||
m_async_compile->SetValue(config.async_compile);
|
||||
m_gx2drawdone_sync->SetValue(config.gx2drawdone_sync);
|
||||
m_force_mesh_shaders->SetValue(config.force_mesh_shaders);
|
||||
|
|
@ -2148,6 +2209,15 @@ void GeneralSettings2::OnGraphicAPISelected(wxCommandEvent& event)
|
|||
HandleGraphicsApiSelection();
|
||||
}
|
||||
|
||||
void GeneralSettings2::OnUserDisplaySRGBSelected(wxCommandEvent& event)
|
||||
{
|
||||
m_userDisplayGamma->SetValue(2.2f);
|
||||
if(event.GetInt())
|
||||
m_userDisplayGamma->Disable();
|
||||
else
|
||||
m_userDisplayGamma->Enable();
|
||||
}
|
||||
|
||||
void GeneralSettings2::OnAddPathClicked(wxCommandEvent& event)
|
||||
{
|
||||
wxDirDialog path_dialog(this, _("Select a directory containing games."), wxEmptyString, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,11 @@ private:
|
|||
// Graphics
|
||||
wxChoice* m_graphic_api, * m_graphic_device;
|
||||
wxChoice* m_vsync;
|
||||
wxCheckBox* m_overrideGamma;
|
||||
wxSpinCtrlDouble* m_overrideGammaValue;
|
||||
wxSpinCtrlDouble* m_userDisplayGamma;
|
||||
wxCheckBox* m_userDisplayisSRGB;
|
||||
|
||||
wxCheckBox *m_async_compile, *m_gx2drawdone_sync, *m_force_mesh_shaders;
|
||||
wxRadioBox* m_upscale_filter, *m_downscale_filter, *m_fullscreen_scaling;
|
||||
wxChoice* m_overlay_position, *m_notification_position, *m_overlay_scale, *m_notification_scale;
|
||||
|
|
@ -97,6 +102,7 @@ private:
|
|||
void OnAudioDeviceSelected(wxCommandEvent& event);
|
||||
void OnAudioChannelsSelected(wxCommandEvent& event);
|
||||
void OnGraphicAPISelected(wxCommandEvent& event);
|
||||
void OnUserDisplaySRGBSelected(wxCommandEvent& event);
|
||||
void OnAddPathClicked(wxCommandEvent& event);
|
||||
void OnRemovePathClicked(wxCommandEvent& event);
|
||||
void OnActiveAccountChanged(wxCommandEvent& event);
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ enum
|
|||
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
|
||||
MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER,
|
||||
MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER,
|
||||
MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE,
|
||||
MAINFRAME_MENU_ID_FILE_EXIT,
|
||||
MAINFRAME_MENU_ID_FILE_END_EMULATION,
|
||||
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
||||
|
|
@ -184,6 +185,7 @@ EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
|||
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenFolder)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, MainWindow::OnOpenFolder)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, MainWindow::OnOpenFolder)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, MainWindow::OnClearSpotPassCache)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
|
||||
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
|
||||
|
|
@ -703,8 +705,15 @@ void MainWindow::OnOpenFolder(wxCommandEvent& event)
|
|||
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetMlcPath()));
|
||||
else if (id == MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER)
|
||||
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetCachePath("shaderCache")));
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::OnClearSpotPassCache(wxCommandEvent& event)
|
||||
{
|
||||
fs::path bossPath = ActiveSettings::GetMlcPath("usr/boss");
|
||||
fs::remove_all(bossPath);
|
||||
// recreate usr/boss/
|
||||
fs::create_directory(bossPath);
|
||||
wxMessageBox(_("SpotPass cache cleared"));
|
||||
}
|
||||
|
||||
void MainWindow::OnInstallUpdate(wxCommandEvent& event)
|
||||
|
|
@ -865,7 +874,7 @@ void MainWindow::OpenSettings()
|
|||
const bool mlc_modified = frame.MLCModified();
|
||||
|
||||
if (paths_modified)
|
||||
m_game_list->ReloadGameEntries(false);
|
||||
m_game_list->ReloadGameEntries();
|
||||
else
|
||||
SaveSettings();
|
||||
|
||||
|
|
@ -1010,7 +1019,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
|
|||
if (m_game_list)
|
||||
{
|
||||
m_game_list->DeleteCachedStrings();
|
||||
m_game_list->ReloadGameEntries(false);
|
||||
m_game_list->ReloadGameEntries();
|
||||
}
|
||||
GetConfigHandle().Save();
|
||||
}
|
||||
|
|
@ -1456,7 +1465,7 @@ void MainWindow::OnAccountListRefresh(wxCommandEvent& event)
|
|||
|
||||
void MainWindow::OnRequestGameListRefresh(wxCommandEvent& event)
|
||||
{
|
||||
m_game_list->ReloadGameEntries(false);
|
||||
m_game_list->ReloadGameEntries();
|
||||
}
|
||||
|
||||
void MainWindow::OnSetWindowTitle(wxCommandEvent& event)
|
||||
|
|
@ -2128,7 +2137,8 @@ void MainWindow::RecreateMenu()
|
|||
m_loadMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_LOAD, _("&Load..."));
|
||||
m_installUpdateMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, _("&Install game title, update or DLC..."));
|
||||
|
||||
sint32 recentFileIndex = 0;
|
||||
wxMenu* recentMenu = new wxMenu();
|
||||
sint32 recentFileIndex = 1;
|
||||
m_fileMenuSeparator0 = nullptr;
|
||||
m_fileMenuSeparator1 = nullptr;
|
||||
for (size_t i = 0; i < guiConfig.recent_launch_files.size(); i++)
|
||||
|
|
@ -2136,15 +2146,21 @@ void MainWindow::RecreateMenu()
|
|||
const std::string& pathStr = guiConfig.recent_launch_files[i];
|
||||
if (pathStr.empty())
|
||||
continue;
|
||||
if (recentFileIndex == 0)
|
||||
m_fileMenuSeparator0 = m_fileMenu->AppendSeparator();
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_RECENT_0 + i, to_wxString(fmt::format("{}. {}", recentFileIndex, pathStr)));
|
||||
recentMenu->Append(MAINFRAME_MENU_ID_FILE_RECENT_0 + i, to_wxString(fmt::format("{}. {}", recentFileIndex, pathStr)));
|
||||
recentFileIndex++;
|
||||
|
||||
if (recentFileIndex >= 8)
|
||||
if (recentFileIndex >= 10)
|
||||
break;
|
||||
}
|
||||
m_fileMenuSeparator1 = m_fileMenu->AppendSeparator();
|
||||
if (recentFileIndex == 0)
|
||||
{
|
||||
wxMenuItem* placeholder = recentMenu->Append(wxID_NONE, _("(No recent files)"));
|
||||
placeholder->Enable(false);
|
||||
}
|
||||
|
||||
m_fileMenu->AppendSeparator();
|
||||
m_fileMenu->AppendSubMenu(recentMenu, _("Recent files"));
|
||||
m_fileMenu->AppendSeparator();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2154,11 +2170,14 @@ void MainWindow::RecreateMenu()
|
|||
#endif
|
||||
}
|
||||
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _("&Open Cemu folder"));
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, _("&Open MLC folder"));
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _("Open Cemu folder"));
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, _("Open MLC folder"));
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, _("Open &shader cache folder"));
|
||||
m_fileMenu->AppendSeparator();
|
||||
|
||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, _("Clear Spot&Pass cache"), wxEmptyString);
|
||||
if (m_game_launched)
|
||||
m_fileMenu->Enable(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, false);
|
||||
m_fileMenu->AppendSeparator();
|
||||
m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit"));
|
||||
m_menuBar->Append(m_fileMenu, _("&File"));
|
||||
// options->account submenu
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public:
|
|||
void OnClose(wxCloseEvent& event);
|
||||
void OnFileMenu(wxCommandEvent& event);
|
||||
void OnOpenFolder(wxCommandEvent& event);
|
||||
void OnClearSpotPassCache(wxCommandEvent& event);
|
||||
void OnLaunchFromFile(wxLaunchGameEvent& event);
|
||||
void OnInstallUpdate(wxCommandEvent& event);
|
||||
void OnFileExit(wxCommandEvent& event);
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ void MemorySearcherTool::OnEntryListRightClick(wxDataViewEvent& event)
|
|||
//mnu.SetClientData(data);
|
||||
mnu.Append(LIST_ENTRY_ADD, _("&Add new entry"))->Enable(false);
|
||||
mnu.Append(LIST_ENTRY_REMOVE, _("&Remove entry"));
|
||||
mnu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MemorySearcherTool::OnPopupClick), nullptr, this);
|
||||
mnu.Bind(wxEVT_COMMAND_MENU_SELECTED, &MemorySearcherTool::OnPopupClick, this);
|
||||
PopupMenu(&mnu);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ void _stripPathFilename(fs::path& path)
|
|||
path = path.parent_path();
|
||||
}
|
||||
|
||||
std::list<fs::path> _getCachesPaths(const TitleId& titleId)
|
||||
std::vector<fs::path> _getCachesPaths(const TitleId& titleId)
|
||||
{
|
||||
std::list<fs::path> cachePaths{
|
||||
std::vector<fs::path> cachePaths{
|
||||
ActiveSettings::GetCachePath(L"shaderCache/driver/vk/{:016x}.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/precompiled/{:016x}_spirv.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/precompiled/{:016x}_gl.bin", titleId),
|
||||
|
|
@ -78,12 +78,12 @@ std::list<fs::path> _getCachesPaths(const TitleId& titleId)
|
|||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_vkpipeline.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_mtlpipeline.bin", titleId)};
|
||||
|
||||
cachePaths.remove_if(
|
||||
[](const fs::path& cachePath)
|
||||
{
|
||||
cachePaths.erase(std::remove_if(cachePaths.begin(), cachePaths.end(),
|
||||
[](const fs::path& cachePath) {
|
||||
std::error_code ec;
|
||||
return !fs::exists(cachePath, ec);
|
||||
});
|
||||
}),
|
||||
cachePaths.end());
|
||||
|
||||
return cachePaths;
|
||||
}
|
||||
|
|
@ -144,17 +144,15 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
|
|||
const auto& config = GetWxGUIConfig();
|
||||
|
||||
char transparent_bitmap[kIconWidth * kIconWidth * 4] = {};
|
||||
memset((void*)transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));
|
||||
memset(transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));
|
||||
wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);
|
||||
|
||||
m_image_list_data = {};
|
||||
m_image_list_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
m_image_list_data.Add(blank);
|
||||
wxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);
|
||||
|
||||
m_image_list_small_data = {};
|
||||
wxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth});
|
||||
m_image_list_small_data.emplace_back(wxBitmapBundle::FromBitmap(blank));
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
m_image_list_small_data.Add(blank);
|
||||
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);
|
||||
|
||||
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
|
||||
if(config.show_icon_column)
|
||||
|
|
@ -305,12 +303,6 @@ int wxGameList::GetColumnDefaultWidth(int column)
|
|||
switch (column)
|
||||
{
|
||||
case ColumnIcon:
|
||||
#if __WXMSW__
|
||||
// note: this is another workaround that could be used to fix the icon offset, but instead of this there's a vcpkg patch for wxWidgets that fixes the icon offset
|
||||
// wxWidgets offsets the icon in the REPORT view so it's cut off if the column width is set to 64px, see https://github.com/wxWidgets/wxWidgets/blob/09f433faf39aab3f25b3c564b82448bb845fae56/src/msw/listctrl.cpp#L3091
|
||||
// so add 6px to the column width to compensate, and add another 6px to the right side so that it has equal whitespace on both sides
|
||||
// return kListIconWidth + 6 + 6;
|
||||
#endif
|
||||
return kListIconWidth;
|
||||
case ColumnName:
|
||||
return DefaultColumnSize::name;
|
||||
|
|
@ -353,7 +345,7 @@ bool wxGameList::IsVisible(long item) const
|
|||
return visible;
|
||||
}
|
||||
|
||||
void wxGameList::ReloadGameEntries(bool cached)
|
||||
void wxGameList::ReloadGameEntries()
|
||||
{
|
||||
wxWindowUpdateLocker windowlock(this);
|
||||
DeleteAllItems();
|
||||
|
|
@ -413,11 +405,13 @@ void wxGameList::SetStyle(Style style, bool save)
|
|||
switch(style)
|
||||
{
|
||||
case Style::kIcons:
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
wxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);
|
||||
break;
|
||||
case Style::kSmallIcons:
|
||||
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_NORMAL);
|
||||
break;
|
||||
case Style::kList:
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
wxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +440,7 @@ long wxGameList::GetStyleFlags(Style style) const
|
|||
switch (style)
|
||||
{
|
||||
case Style::kList:
|
||||
return (wxLC_SINGLE_SEL | wxLC_REPORT);
|
||||
return (wxLC_SINGLE_SEL | wxLC_VRULES | wxLC_REPORT);
|
||||
case Style::kIcons:
|
||||
return (wxLC_SINGLE_SEL | wxLC_ICON);
|
||||
case Style::kSmallIcons:
|
||||
|
|
@ -461,25 +455,22 @@ void wxGameList::UpdateItemColors(sint32 startIndex)
|
|||
{
|
||||
wxWindowUpdateLocker lock(this);
|
||||
|
||||
wxColour bgColourPrimary = GetBackgroundColour();
|
||||
wxColour bgColourSecondary = wxHelper::CalculateAccentColour(bgColourPrimary);
|
||||
|
||||
for (int i = startIndex; i < GetItemCount(); ++i)
|
||||
{
|
||||
const auto titleId = (uint64)GetItemData(i);
|
||||
const uint64 titleId = GetItemData(i);
|
||||
if (GetConfig().IsGameListFavorite(titleId))
|
||||
{
|
||||
SetItemBackgroundColour(i, kFavoriteColor);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
else if ((i&1) != 0)
|
||||
else if ((i % 2) != 0)
|
||||
{
|
||||
SetItemBackgroundColour(i, bgColourPrimary);
|
||||
SetItemBackgroundColour(i, kPrimaryColor);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetItemBackgroundColour(i, bgColourSecondary);
|
||||
SetItemBackgroundColour(i, kAlternateColor);
|
||||
SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
}
|
||||
}
|
||||
|
|
@ -487,7 +478,7 @@ void wxGameList::UpdateItemColors(sint32 startIndex)
|
|||
|
||||
static inline int order_to_int(const std::weak_ordering &wo)
|
||||
{
|
||||
// no easy conversion seems to exists in C++20
|
||||
// no easy conversion seems to exist in C++20
|
||||
if (wo == std::weak_ordering::less)
|
||||
return -1;
|
||||
else if (wo == std::weak_ordering::greater)
|
||||
|
|
@ -517,9 +508,6 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2,
|
|||
return CafeTitleList::GetGameInfo(id).GetRegion();
|
||||
};
|
||||
|
||||
if (!sortData->asc)
|
||||
std::swap(titleId1, titleId2);
|
||||
|
||||
switch(sortData->column)
|
||||
{
|
||||
default:
|
||||
|
|
@ -548,7 +536,7 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2,
|
|||
int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
|
||||
{
|
||||
const auto sort_data = (SortData*)sortData;
|
||||
return order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data));
|
||||
return sort_data->dir * order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data));
|
||||
}
|
||||
|
||||
void wxGameList::SortEntries(int column)
|
||||
|
|
@ -572,7 +560,7 @@ void wxGameList::SortEntries(int column)
|
|||
case ColumnRegion:
|
||||
case ColumnTitleID:
|
||||
{
|
||||
SortData data{this, ItemColumns{column}, ascending};
|
||||
SortData data{this, ItemColumns{column}, ascending ? 1 : -1};
|
||||
SortItems(SortFunction, (wxIntPtr)&data);
|
||||
ShowSortIndicator(column, ascending);
|
||||
break;
|
||||
|
|
@ -843,8 +831,8 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
|
|||
int icon_small;
|
||||
if (!QueryIconForTitle(title_id, icon_large, icon_small))
|
||||
break;
|
||||
auto icon = m_image_list_data[icon_large];
|
||||
auto newClipboardData = wxBitmapDataObject(icon.GetBitmap(icon.GetDefaultSize()));
|
||||
auto icon = m_image_list_data.GetIcon(icon_large);
|
||||
auto newClipboardData = wxBitmapDataObject(icon);
|
||||
wxClipboard::Get()->SetData(&newClipboardData);
|
||||
wxClipboard::Get()->Close();
|
||||
}
|
||||
|
|
@ -857,7 +845,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
|
|||
switch (event.GetId())
|
||||
{
|
||||
case kContextMenuRefreshGames:
|
||||
ReloadGameEntries(false);
|
||||
ReloadGameEntries();
|
||||
break;
|
||||
case kContextMenuStyleList:
|
||||
SetStyle(Style::kList);
|
||||
|
|
@ -1005,7 +993,7 @@ void wxGameList::ApplyGameListColumnWidths()
|
|||
const auto& config = GetWxGUIConfig();
|
||||
wxWindowUpdateLocker lock(this);
|
||||
if(config.show_icon_column)
|
||||
SetColumnWidth(ColumnIcon, GetColumnDefaultWidth(ColumnIcon));
|
||||
SetColumnWidth(ColumnIcon, kListIconWidth);
|
||||
else
|
||||
SetColumnWidth(ColumnIcon, 0);
|
||||
SetColumnWidth(ColumnName, config.column_width.name);
|
||||
|
|
@ -1120,19 +1108,6 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)
|
|||
TitleId baseTitleId = gameInfo.GetBaseTitleId();
|
||||
bool isNewEntry = false;
|
||||
|
||||
if (m_style == Style::kIcons)
|
||||
{
|
||||
wxListCtrl::SetNormalImages(m_image_list_data);
|
||||
}
|
||||
else if (m_style == Style::kSmallIcons)
|
||||
{
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
}
|
||||
else if (m_style == Style::kList)
|
||||
{
|
||||
wxListCtrl::SetSmallImages(m_image_list_small_data);
|
||||
}
|
||||
|
||||
int icon = -1; /* 0 is the default empty icon */
|
||||
int icon_small = -1; /* 0 is the default empty icon */
|
||||
QueryIconForTitle(baseTitleId, icon, icon_small);
|
||||
|
|
@ -1283,7 +1258,7 @@ void wxGameList::HandleTitleListCallback(CafeTitleListCallbackEvent* evt)
|
|||
}
|
||||
}
|
||||
|
||||
void wxGameList::RemoveCache(const std::list<fs::path>& cachePaths, const std::string& titleName)
|
||||
void wxGameList::RemoveCache(const std::vector<fs::path>& cachePaths, const std::string& titleName)
|
||||
{
|
||||
wxMessageDialog dialog(this, formatWxString(_("Remove the shader caches for {}?"), titleName), _("Remove shader caches"), wxCENTRE | wxYES_NO | wxICON_EXCLAMATION);
|
||||
dialog.SetYesNoLabels(_("Yes"), _("No"));
|
||||
|
|
@ -1291,7 +1266,7 @@ void wxGameList::RemoveCache(const std::list<fs::path>& cachePaths, const std::s
|
|||
const auto dialogResult = dialog.ShowModal();
|
||||
if (dialogResult != wxID_YES)
|
||||
return;
|
||||
std::list<std::string> errs;
|
||||
std::vector<std::string> errs;
|
||||
for (const fs::path& cachePath : cachePaths)
|
||||
{
|
||||
if (std::error_code ec; !fs::remove(cachePath, ec))
|
||||
|
|
@ -1348,18 +1323,17 @@ void wxGameList::AsyncWorkerThread()
|
|||
wxMemoryInputStream tmp_stream(tgaData->data(), tgaData->size());
|
||||
const wxImage image(tmp_stream);
|
||||
// todo - is wxImageList thread safe?
|
||||
m_image_list_data.emplace_back(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
m_image_list_small_data.emplace_back(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
int icon = m_image_list_data.Add(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
int icon_small = m_image_list_small_data.Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));
|
||||
// store in cache
|
||||
m_icon_cache_mtx.lock();
|
||||
m_icon_cache.try_emplace(titleId, m_image_list_data.size() - 1, m_image_list_small_data.size() - 1);
|
||||
m_icon_cache.try_emplace(titleId, icon, icon_small);
|
||||
m_icon_cache_mtx.unlock();
|
||||
iconSuccessfullyLoaded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to load icon for title {:016x}", titleId);
|
||||
cemu_assert_debug(false);
|
||||
}
|
||||
titleInfo.Unmount(tempMountPath);
|
||||
// notify UI about loaded icon
|
||||
|
|
@ -1418,9 +1392,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
// Obtain and convert icon
|
||||
[&]()
|
||||
{
|
||||
int iconIndex, smallIconIndex;
|
||||
int iconIdx, smallIconIdx;
|
||||
|
||||
if (!QueryIconForTitle(titleId, iconIndex, smallIconIndex))
|
||||
if (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||
return;
|
||||
|
|
@ -1436,8 +1410,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||
|
||||
const auto icon = m_image_list_data[iconIndex];
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||
wxBitmap bitmap{icon};
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
wxPNGHandler pngHandler;
|
||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||
|
|
@ -1511,9 +1485,9 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
// Obtain and convert icon
|
||||
[&]()
|
||||
{
|
||||
int iconIndex, smallIconIndex;
|
||||
int iconIdx, smallIconIdx;
|
||||
|
||||
if (!QueryIconForTitle(titleId, iconIndex, smallIconIndex))
|
||||
if (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||
return;
|
||||
|
|
@ -1529,8 +1503,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
iconPath = outIconDir / fmt::format("{:016x}.png", gameInfo.GetBaseTitleId());
|
||||
wxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));
|
||||
|
||||
const auto icon = m_image_list_data[iconIndex];
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||
wxBitmap bitmap{icon};
|
||||
wxImage image = bitmap.ConvertToImage();
|
||||
wxPNGHandler pngHandler;
|
||||
if (!pngHandler.SaveFile(&image, pngFileStream, false))
|
||||
|
|
@ -1638,14 +1612,14 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo)
|
|||
cemuLog_log(LogType::Force, "Icon hasn't loaded");
|
||||
return;
|
||||
}
|
||||
const auto icon = m_image_list_data[iconIdx];
|
||||
const auto icon = m_image_list_data.GetIcon(iconIdx);
|
||||
const auto folder = ActiveSettings::GetUserDataPath("icons");
|
||||
if (!fs::exists(folder) && !fs::create_directories(folder))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to create icon directory");
|
||||
return;
|
||||
}
|
||||
wxBitmap bitmap{icon.GetBitmap(wxDefaultSize)};
|
||||
wxBitmap bitmap{icon};
|
||||
|
||||
icon_path = folder / fmt::format("{:016x}.ico", titleId);
|
||||
auto stream = wxFileOutputStream(icon_path->wstring());
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
#include "config/CemuConfig.h"
|
||||
#include "Cafe/TitleList/TitleId.h"
|
||||
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/settings.h>
|
||||
#include <Cafe/TitleList/GameInfo.h>
|
||||
|
||||
#include "wxHelper.h"
|
||||
#include "util/helpers/Semaphore.h"
|
||||
|
||||
class wxTitleIdEvent : public wxCommandEvent
|
||||
|
|
@ -51,7 +51,7 @@ public:
|
|||
void SaveConfig(bool flush = false);
|
||||
bool IsVisible(long item) const; // only available in wxwidgets 3.1.3
|
||||
|
||||
void ReloadGameEntries(bool cached = false);
|
||||
void ReloadGameEntries();
|
||||
void DeleteCachedStrings();
|
||||
|
||||
void CreateShortcut(GameInfo2& gameInfo);
|
||||
|
|
@ -66,7 +66,8 @@ private:
|
|||
|
||||
const wxColour kUpdateColor{ wxSystemSettings::SelectLightDark(wxColour(195, 57, 57), wxColour(84, 29, 29)) };
|
||||
const wxColour kFavoriteColor{ wxSystemSettings::SelectLightDark(wxColour(253, 246, 211), wxColour(82, 84, 48)) };
|
||||
const wxColour kSecondColor{ wxSystemSettings::SelectLightDark(wxColour(242, 249, 253), wxColour(34, 34, 34)) };
|
||||
const wxColour kPrimaryColor = GetBackgroundColour();
|
||||
const wxColour kAlternateColor = wxHelper::CalculateAccentColour(kPrimaryColor);
|
||||
void UpdateItemColors(sint32 startIndex = 0);
|
||||
|
||||
enum ItemColumns : int
|
||||
|
|
@ -89,7 +90,7 @@ private:
|
|||
{
|
||||
wxGameList* thisptr;
|
||||
ItemColumns column;
|
||||
bool asc;
|
||||
int dir;
|
||||
};
|
||||
|
||||
int FindInsertPosition(TitleId titleId);
|
||||
|
|
@ -114,7 +115,7 @@ private:
|
|||
|
||||
void HandleTitleListCallback(struct CafeTitleListCallbackEvent* evt);
|
||||
|
||||
void RemoveCache(const std::list<fs::path>& cachePath, const std::string& titleName);
|
||||
void RemoveCache(const std::vector<fs::path>& cachePath, const std::string& titleName);
|
||||
|
||||
void AsyncWorkerThread();
|
||||
void RequestLoadIconAsync(TitleId titleId);
|
||||
|
|
@ -122,7 +123,8 @@ private:
|
|||
|
||||
inline static constexpr int kListIconWidth = 64;
|
||||
inline static constexpr int kIconWidth = 128;
|
||||
wxWithImages::Images m_image_list_data, m_image_list_small_data;
|
||||
wxImageList m_image_list_data = wxImageList(kIconWidth, kIconWidth, false, 1);
|
||||
wxImageList m_image_list_small_data = wxImageList(kListIconWidth, kListIconWidth, false, 1);
|
||||
|
||||
std::mutex m_icon_cache_mtx;
|
||||
std::set<TitleId> m_icon_loaded;
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ void BreakpointWindow::OnRightDown(wxMouseEvent& event)
|
|||
menu.Append(MENU_ID_CREATE_MEM_BP_READ, _("Create memory breakpoint (read)"));
|
||||
menu.Append(MENU_ID_CREATE_MEM_BP_WRITE, _("Create memory breakpoint (write)"));
|
||||
|
||||
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(BreakpointWindow::OnContextMenuClick), nullptr, this);
|
||||
menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &BreakpointWindow::OnContextMenuClick, this);
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
else
|
||||
|
|
@ -234,7 +234,7 @@ void BreakpointWindow::OnRightDown(wxMouseEvent& event)
|
|||
wxMenu menu;
|
||||
menu.Append(MENU_ID_DELETE_BP, _("Delete breakpoint"));
|
||||
|
||||
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(BreakpointWindow::OnContextMenuClickSelected), nullptr, this);
|
||||
menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &BreakpointWindow::OnContextMenuClickSelected, this);
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,8 +239,8 @@ void HotkeySettings::CreateHotkeyRow(const wxString& label, sHotkeyCfg& cfgHotke
|
|||
controllerInput->Bind(wxEVT_BUTTON, &HotkeySettings::OnControllerHotkeyInputLeftClick, this);
|
||||
|
||||
/* for cancelling and clearing input */
|
||||
keyInput->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(HotkeySettings::OnKeyboardHotkeyInputRightClick), NULL, this);
|
||||
controllerInput->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(HotkeySettings::OnControllerHotkeyInputRightClick), NULL, this);
|
||||
keyInput->Bind(wxEVT_RIGHT_UP, &HotkeySettings::OnKeyboardHotkeyInputRightClick, this);
|
||||
controllerInput->Bind(wxEVT_RIGHT_UP, &HotkeySettings::OnControllerHotkeyInputRightClick, this);
|
||||
|
||||
keyInput->SetMinSize(m_minButtonSize);
|
||||
controllerInput->SetMinSize(m_minButtonSize);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@
|
|||
#include "wxgui/input/InputAPIAddWindow.h"
|
||||
#include "input/ControllerFactory.h"
|
||||
|
||||
#ifdef HAS_BLUEZ
|
||||
#include "wxgui/input/PairingDialog.h"
|
||||
#endif
|
||||
|
||||
#include "wxgui/input/panels/VPADInputPanel.h"
|
||||
#include "wxgui/input/panels/ProControllerInputPanel.h"
|
||||
|
|
@ -255,12 +257,14 @@ wxWindow* InputSettings2::initialize_page(size_t index)
|
|||
page_data.m_controller_api_remove = remove_api;
|
||||
}
|
||||
|
||||
#ifdef HAS_BLUEZ
|
||||
auto* pairingDialog = new wxButton(page, wxID_ANY, _("Pair Wii/Wii U Controller"));
|
||||
pairingDialog->Bind(wxEVT_BUTTON, [this](wxEvent&) {
|
||||
PairingDialog pairing_dialog(this);
|
||||
pairing_dialog.ShowModal();
|
||||
});
|
||||
sizer->Add(pairingDialog, wxGBPosition(5, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
#endif
|
||||
|
||||
// controller
|
||||
auto* controller_bttns = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ DebugPPCThreadsWindow::DebugPPCThreadsWindow(wxFrame& parent)
|
|||
|
||||
sizer->Add(row, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
m_thread_list->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(DebugPPCThreadsWindow::OnThreadListRightClick), nullptr, this);
|
||||
m_thread_list->Bind(wxEVT_RIGHT_DOWN, &DebugPPCThreadsWindow::OnThreadListRightClick, this);
|
||||
|
||||
SetSizer(sizer);
|
||||
|
||||
|
|
@ -466,7 +466,7 @@ void DebugPPCThreadsWindow::OnThreadListRightClick(wxMouseEvent& event)
|
|||
menu.AppendSeparator();
|
||||
menu.Append(THREADLIST_MENU_DUMP_STACK_TRACE, _("Write stack trace to log"));
|
||||
menu.Append(THREADLIST_MENU_PROFILE_THREAD, _("Profile thread"));
|
||||
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(DebugPPCThreadsWindow::OnThreadListPopupClick), nullptr, this);
|
||||
menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &DebugPPCThreadsWindow::OnThreadListPopupClick, this);
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ TextureRelationViewerWindow::TextureRelationViewerWindow(wxFrame& parent)
|
|||
sizerBottom->Add(checkboxShowViews, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM | wxTOP | wxLEFT, 10);
|
||||
checkboxShowViews->SetValue(true);
|
||||
|
||||
textureRelationListA->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(TextureRelationViewerWindow::OnTextureListRightClick), NULL, this);
|
||||
textureRelationListA->Bind(wxEVT_RIGHT_DOWN, &TextureRelationViewerWindow::OnTextureListRightClick, this);
|
||||
|
||||
sizer->Add(
|
||||
sizerBottom,
|
||||
|
|
|
|||
|
|
@ -25,10 +25,9 @@ namespace wxHelper
|
|||
|
||||
inline wxColour CalculateAccentColour(const wxColour& bgColour)
|
||||
{
|
||||
wxColour bgColourSecondary;
|
||||
const uint32 bgLightness = (bgColour.GetRed() + bgColour.GetGreen() + bgColour.GetBlue()) / 3;
|
||||
const bool isDarkTheme = bgLightness < 128;
|
||||
bgColourSecondary = bgColour.ChangeLightness(isDarkTheme ? 110 : 90); // color for even rows
|
||||
wxColour bgColourSecondary = bgColour.ChangeLightness(isDarkTheme ? 110 : 90); // color for even rows
|
||||
// for very light themes we'll use a blue tint to match the older Windows Cemu look
|
||||
if (bgLightness > 250)
|
||||
bgColourSecondary = wxColour(bgColour.Red() - 13, bgColour.Green() - 6, bgColour.Blue() - 2);
|
||||
|
|
|
|||
|
|
@ -121,49 +121,49 @@ void wxCheckTree::Init()
|
|||
|
||||
// Unchecked
|
||||
renderer_dc.SelectObject(unchecked_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_NONE);
|
||||
|
||||
// Unchecked Mouse Over
|
||||
renderer_dc.SelectObject(unchecked_mouse_over_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CURRENT);
|
||||
|
||||
// Unchecked and Disabled
|
||||
renderer_dc.SelectObject(unchecked_disabled_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_DISABLED);
|
||||
|
||||
// Unchecked Left Down
|
||||
renderer_dc.SelectObject(unchecked_left_down_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CURRENT | wxCONTROL_PRESSED);
|
||||
|
||||
// Checked
|
||||
renderer_dc.SelectObject(checked_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED);
|
||||
|
||||
// Checked Mouse Over
|
||||
renderer_dc.SelectObject(checked_mouse_over_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED | wxCONTROL_CURRENT);
|
||||
|
||||
// Checked Left Down
|
||||
renderer_dc.SelectObject(checked_left_down_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED | wxCONTROL_CURRENT | wxCONTROL_PRESSED);
|
||||
|
||||
// Checked and Disabled
|
||||
renderer_dc.SelectObject(checked_disabled_bmp);
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID));
|
||||
renderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));
|
||||
renderer_dc.Clear();
|
||||
wxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED | wxCONTROL_DISABLED);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,10 +31,6 @@ target_sources(imguiImpl PRIVATE
|
|||
target_include_directories(imguiImpl PUBLIC "../../dependencies/imgui/")
|
||||
|
||||
target_link_libraries(imguiImpl PRIVATE
|
||||
CemuCafe
|
||||
CemuCommon
|
||||
CemuGui
|
||||
CemuInput
|
||||
CemuResource
|
||||
CemuUtil
|
||||
)
|
||||
|
|
|
|||
|
|
@ -88,16 +88,8 @@ endif ()
|
|||
target_include_directories(CemuInput PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuInput PRIVATE
|
||||
CemuCafe
|
||||
CemuCommon
|
||||
CemuConfig
|
||||
CemuGui
|
||||
CemuUtil
|
||||
Boost::headers
|
||||
Boost::program_options
|
||||
glm::glm
|
||||
pugixml::pugixml
|
||||
SDL2::SDL2
|
||||
)
|
||||
|
||||
if (ENABLE_HIDAPI)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ DirectInputController::~DirectInputController()
|
|||
// TODO: test if really needed
|
||||
// workaround for gamecube controllers crash on release?
|
||||
bool should_release_device = true;
|
||||
if (m_product_guid == GUID{}) {
|
||||
DIDEVICEINSTANCE info{};
|
||||
info.dwSize = sizeof(DIDEVICEINSTANCE);
|
||||
if (m_product_guid == GUID{})
|
||||
{
|
||||
DIDEVICEINSTANCEW info{};
|
||||
info.dwSize = sizeof(DIDEVICEINSTANCEW);
|
||||
if (SUCCEEDED(m_device->GetDeviceInfo(&info)))
|
||||
{
|
||||
m_product_guid = info.guidProduct;
|
||||
|
|
@ -90,8 +91,8 @@ bool DirectInputController::connect()
|
|||
if (FAILED(hr) || m_device == nullptr)
|
||||
return false;
|
||||
|
||||
DIDEVICEINSTANCE idi{};
|
||||
idi.dwSize = sizeof(DIDEVICEINSTANCE);
|
||||
DIDEVICEINSTANCEW idi{};
|
||||
idi.dwSize = sizeof(DIDEVICEINSTANCEW);
|
||||
if (SUCCEEDED(m_device->GetDeviceInfo(&idi)))
|
||||
{
|
||||
// overwrite guid name with "real" display name
|
||||
|
|
@ -147,8 +148,8 @@ bool DirectInputController::connect()
|
|||
}
|
||||
}
|
||||
|
||||
DIDEVICEINSTANCE info{};
|
||||
info.dwSize = sizeof(DIDEVICEINSTANCE);
|
||||
DIDEVICEINSTANCEW info{};
|
||||
info.dwSize = sizeof(DIDEVICEINSTANCEW);
|
||||
if (SUCCEEDED(m_device->GetDeviceInfo(&info)))
|
||||
{
|
||||
m_product_guid = info.guidProduct;
|
||||
|
|
@ -157,7 +158,7 @@ bool DirectInputController::connect()
|
|||
std::fill(m_min_axis.begin(), m_min_axis.end(), 0);
|
||||
std::fill(m_max_axis.begin(), m_max_axis.end(), std::numeric_limits<uint16>::max());
|
||||
m_device->EnumObjects(
|
||||
[](LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) -> BOOL
|
||||
[](LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef) -> BOOL
|
||||
{
|
||||
auto* thisptr = (DirectInputController*)pvRef;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ private:
|
|||
GUID m_product_guid{};
|
||||
|
||||
std::shared_mutex m_mutex;
|
||||
Microsoft::WRL::ComPtr<IDirectInputDevice8> m_device;
|
||||
Microsoft::WRL::ComPtr<IDirectInputDevice8W> m_device;
|
||||
Microsoft::WRL::ComPtr<IDirectInputEffect> m_effect;
|
||||
|
||||
std::array<LONG, 6> m_min_axis{};
|
||||
|
|
|
|||
|
|
@ -4,34 +4,16 @@
|
|||
|
||||
DirectInputControllerProvider::DirectInputControllerProvider()
|
||||
{
|
||||
/*m_module = LoadLibraryA("dinput8.dll");
|
||||
if (!m_module)
|
||||
throw std::runtime_error("can't load any xinput dll");
|
||||
|
||||
m_DirectInput8Create = (decltype(&DirectInput8Create))GetProcAddress(m_module, "DirectInput8Create");
|
||||
m_GetdfDIJoystick = (decltype(&GetdfDIJoystick))GetProcAddress(m_module, "GetdfDIJoystick");
|
||||
|
||||
if (!m_DirectInput8Create)
|
||||
{
|
||||
FreeLibrary(m_module);
|
||||
throw std::runtime_error("can't find the DirectInput8Create export");
|
||||
}*/
|
||||
|
||||
|
||||
const auto r = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_dinput8, nullptr);
|
||||
const auto r = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, (void**)&m_dinput8, nullptr);
|
||||
if (FAILED(r))
|
||||
{
|
||||
const auto error = GetLastError();
|
||||
//FreeLibrary(m_module);
|
||||
throw std::runtime_error(fmt::format("can't create direct input object (error: {:#x})", error));
|
||||
}
|
||||
}
|
||||
|
||||
DirectInputControllerProvider::~DirectInputControllerProvider()
|
||||
{
|
||||
/*if (m_module)
|
||||
FreeLibrary(m_module);
|
||||
*/
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_controllers()
|
||||
|
|
@ -39,7 +21,7 @@ std::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_
|
|||
std::vector<std::shared_ptr<ControllerBase>> result;
|
||||
|
||||
m_dinput8->EnumDevices(DI8DEVCLASS_GAMECTRL,
|
||||
[](LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) -> BOOL
|
||||
[](LPCDIDEVICEINSTANCEW lpddi, LPVOID pvRef) -> BOOL
|
||||
{
|
||||
auto* controllers = (decltype(&result))pvRef;
|
||||
|
||||
|
|
@ -55,8 +37,5 @@ std::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_
|
|||
|
||||
LPCDIDATAFORMAT DirectInputControllerProvider::get_data_format() const
|
||||
{
|
||||
/*if (m_GetdfDIJoystick)
|
||||
return m_GetdfDIJoystick();*/
|
||||
|
||||
return GetdfDIJoystick();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public:
|
|||
|
||||
std::vector<std::shared_ptr<ControllerBase>> get_controllers() override;
|
||||
|
||||
IDirectInput8* get_dinput() const { return m_dinput8.Get(); }
|
||||
IDirectInput8W* get_dinput() const { return m_dinput8.Get(); }
|
||||
LPCDIDATAFORMAT get_data_format() const;
|
||||
|
||||
private:
|
||||
|
|
@ -32,7 +32,7 @@ private:
|
|||
decltype(&DirectInput8Create) m_DirectInput8Create;
|
||||
decltype(&GetdfDIJoystick) m_GetdfDIJoystick = nullptr;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDirectInput8> m_dinput8;
|
||||
Microsoft::WRL::ComPtr<IDirectInput8W> m_dinput8;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -96,12 +96,12 @@ void WindowsInitCwd()
|
|||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
executablePath.resize(4096);
|
||||
int i = GetModuleFileName(NULL, executablePath.data(), executablePath.size());
|
||||
int i = GetModuleFileNameW(NULL, executablePath.data(), executablePath.size());
|
||||
if(i >= 0)
|
||||
executablePath.resize(i);
|
||||
else
|
||||
executablePath.clear();
|
||||
SetCurrentDirectory(executablePath.c_str());
|
||||
SetCurrentDirectoryW(executablePath.c_str());
|
||||
// set high priority
|
||||
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
|
||||
#endif
|
||||
|
|
@ -192,7 +192,7 @@ void HandlePostUpdate()
|
|||
HANDLE lock;
|
||||
do
|
||||
{
|
||||
lock = CreateMutex(nullptr, TRUE, L"Global\\cemu_update_lock");
|
||||
lock = CreateMutexW(nullptr, TRUE, L"Global\\cemu_update_lock");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
} while (lock == nullptr);
|
||||
const DWORD wait_result = WaitForSingleObject(lock, 2000);
|
||||
|
|
@ -220,7 +220,7 @@ void ToolShaderCacheMerger();
|
|||
#if BOOST_OS_WINDOWS
|
||||
|
||||
// entrypoint for release builds
|
||||
int wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd)
|
||||
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))
|
||||
cemuLog_log(LogType::Force, "CoInitializeEx() failed");
|
||||
|
|
|
|||
|
|
@ -22,4 +22,4 @@ target_sources(CemuResource PRIVATE CafeDefaultFont.cpp)
|
|||
|
||||
target_include_directories(CemuResource PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuResource PRIVATE CemuCommon CemuComponents)
|
||||
target_link_libraries(CemuResource PRIVATE CemuCommon)
|
||||
|
|
|
|||
|
|
@ -93,8 +93,4 @@ target_include_directories(CemuUtil PUBLIC "../")
|
|||
|
||||
target_link_libraries(CemuUtil PRIVATE
|
||||
CemuCommon
|
||||
CemuConfig
|
||||
Boost::headers
|
||||
Boost::nowide
|
||||
OpenSSL::Crypto
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <charconv>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
#include <set>
|
||||
|
||||
#include "util/math/vector2.h"
|
||||
#include "util/math/vector3.h"
|
||||
|
|
|
|||
|
|
@ -34,13 +34,7 @@
|
|||
"default-features": false
|
||||
},
|
||||
"zstd",
|
||||
{
|
||||
"name": "wxwidgets",
|
||||
"features": [
|
||||
"debug-support"
|
||||
],
|
||||
"default-features": false
|
||||
},
|
||||
"wxwidgets",
|
||||
"openssl",
|
||||
{
|
||||
"name": "curl",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue