diff options
116 files changed, 1748 insertions, 1175 deletions
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh index 155d8a5c8..584b9b39f 100755 --- a/.ci/scripts/windows/docker.sh +++ b/.ci/scripts/windows/docker.sh | |||
| @@ -41,12 +41,11 @@ for i in package/*.exe; do | |||
| 41 | done | 41 | done |
| 42 | 42 | ||
| 43 | pip3 install pefile | 43 | pip3 install pefile |
| 44 | python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/" | 44 | python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/" |
| 45 | python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/" | ||
| 46 | 45 | ||
| 47 | # copy FFmpeg libraries | 46 | # copy FFmpeg libraries |
| 48 | EXTERNALS_PATH="$(pwd)/build/externals" | 47 | EXTERNALS_PATH="$(pwd)/build/externals" |
| 49 | FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin" | 48 | FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin" |
| 50 | find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' | 49 | find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';' |
| 51 | 50 | ||
| 52 | # copy libraries from yuzu.exe path | 51 | # copy libraries from yuzu.exe path |
diff --git a/.gitmodules b/.gitmodules index dc6ed500f..a9cf9a24a 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -34,12 +34,12 @@ | |||
| 34 | [submodule "opus"] | 34 | [submodule "opus"] |
| 35 | path = externals/opus/opus | 35 | path = externals/opus/opus |
| 36 | url = https://github.com/xiph/opus.git | 36 | url = https://github.com/xiph/opus.git |
| 37 | [submodule "ffmpeg"] | ||
| 38 | path = externals/ffmpeg | ||
| 39 | url = https://git.ffmpeg.org/ffmpeg.git | ||
| 40 | [submodule "SDL"] | 37 | [submodule "SDL"] |
| 41 | path = externals/SDL | 38 | path = externals/SDL |
| 42 | url = https://github.com/libsdl-org/SDL.git | 39 | url = https://github.com/libsdl-org/SDL.git |
| 43 | [submodule "externals/cpp-httplib"] | 40 | [submodule "externals/cpp-httplib"] |
| 44 | path = externals/cpp-httplib | 41 | path = externals/cpp-httplib |
| 45 | url = https://github.com/yhirose/cpp-httplib.git | 42 | url = https://github.com/yhirose/cpp-httplib.git |
| 43 | [submodule "externals/ffmpeg/ffmpeg"] | ||
| 44 | path = externals/ffmpeg/ffmpeg | ||
| 45 | url = https://git.ffmpeg.org/ffmpeg.git | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a7b1d85a..707d514c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -231,7 +231,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST) | |||
| 231 | include_directories(SYSTEM "${Boost_INCLUDE_DIRS}") | 231 | include_directories(SYSTEM "${Boost_INCLUDE_DIRS}") |
| 232 | else() | 232 | else() |
| 233 | message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan") | 233 | message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan") |
| 234 | list(APPEND CONAN_REQUIRED_LIBS "boost/1.73.0") | 234 | list(APPEND CONAN_REQUIRED_LIBS "boost/1.78.0") |
| 235 | endif() | 235 | endif() |
| 236 | 236 | ||
| 237 | # Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS | 237 | # Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS |
| @@ -251,7 +251,7 @@ if(ENABLE_QT) | |||
| 251 | # Check for system Qt on Linux, fallback to bundled Qt | 251 | # Check for system Qt on Linux, fallback to bundled Qt |
| 252 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 252 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |
| 253 | if (NOT YUZU_USE_BUNDLED_QT) | 253 | if (NOT YUZU_USE_BUNDLED_QT) |
| 254 | find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets) | 254 | find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus) |
| 255 | endif() | 255 | endif() |
| 256 | if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) | 256 | if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT) |
| 257 | # Check for dependencies, then enable bundled Qt download | 257 | # Check for dependencies, then enable bundled Qt download |
| @@ -510,13 +510,13 @@ set(FFmpeg_COMPONENTS | |||
| 510 | avutil | 510 | avutil |
| 511 | swscale) | 511 | swscale) |
| 512 | 512 | ||
| 513 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 513 | if (UNIX AND NOT APPLE) |
| 514 | Include(FindPkgConfig REQUIRED) | 514 | Include(FindPkgConfig REQUIRED) |
| 515 | pkg_check_modules(LIBVA libva) | 515 | pkg_check_modules(LIBVA libva) |
| 516 | endif() | 516 | endif() |
| 517 | if (NOT YUZU_USE_BUNDLED_FFMPEG) | 517 | if (NOT YUZU_USE_BUNDLED_FFMPEG) |
| 518 | # Use system installed FFmpeg | 518 | # Use system installed FFmpeg |
| 519 | find_package(FFmpeg QUIET COMPONENTS ${FFmpeg_COMPONENTS}) | 519 | find_package(FFmpeg 4.3 QUIET COMPONENTS ${FFmpeg_COMPONENTS}) |
| 520 | 520 | ||
| 521 | if (FFmpeg_FOUND) | 521 | if (FFmpeg_FOUND) |
| 522 | # Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries. | 522 | # Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries. |
| @@ -529,225 +529,11 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG) | |||
| 529 | set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE) | 529 | set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE) |
| 530 | endforeach() | 530 | endforeach() |
| 531 | else() | 531 | else() |
| 532 | message(WARNING "FFmpeg not found, falling back to externals") | 532 | message(WARNING "FFmpeg not found or too old, falling back to externals") |
| 533 | set(YUZU_USE_BUNDLED_FFMPEG ON) | 533 | set(YUZU_USE_BUNDLED_FFMPEG ON) |
| 534 | endif() | 534 | endif() |
| 535 | endif() | 535 | endif() |
| 536 | 536 | ||
| 537 | if (YUZU_USE_BUNDLED_FFMPEG) | ||
| 538 | if (NOT WIN32) | ||
| 539 | # TODO(lat9nq): Move this to externals/ffmpeg/CMakeLists.txt (and move externals/ffmpeg to | ||
| 540 | # externals/ffmpeg/ffmpeg) | ||
| 541 | |||
| 542 | # Build FFmpeg from externals | ||
| 543 | message(STATUS "Using FFmpeg from externals") | ||
| 544 | |||
| 545 | # FFmpeg has source that requires one of nasm or yasm to assemble it. | ||
| 546 | # REQUIRED throws an error if not found here during configuration rather than during compilation. | ||
| 547 | find_program(ASSEMBLER NAMES nasm yasm) | ||
| 548 | if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") | ||
| 549 | message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") | ||
| 550 | endif() | ||
| 551 | |||
| 552 | find_program(AUTOCONF autoconf) | ||
| 553 | if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") | ||
| 554 | message(FATAL_ERROR "Required program `autoconf` not found.") | ||
| 555 | endif() | ||
| 556 | |||
| 557 | set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg) | ||
| 558 | set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg) | ||
| 559 | set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) | ||
| 560 | make_directory(${FFmpeg_BUILD_DIR}) | ||
| 561 | |||
| 562 | # Read version string from external | ||
| 563 | file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) | ||
| 564 | set(FFmpeg_FOUND NO) | ||
| 565 | if (NOT FFmpeg_VERSION STREQUAL "") | ||
| 566 | set(FFmpeg_FOUND YES) | ||
| 567 | endif() | ||
| 568 | |||
| 569 | unset(FFmpeg_LIBRARIES CACHE) | ||
| 570 | foreach(COMPONENT ${FFmpeg_COMPONENTS}) | ||
| 571 | set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") | ||
| 572 | set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") | ||
| 573 | set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") | ||
| 574 | |||
| 575 | set(FFmpeg_LIBRARIES | ||
| 576 | ${FFmpeg_LIBRARIES} | ||
| 577 | ${FFmpeg_${COMPONENT}_LIBRARY} | ||
| 578 | CACHE PATH "Paths to FFmpeg libraries" FORCE) | ||
| 579 | endforeach() | ||
| 580 | |||
| 581 | Include(FindPkgConfig REQUIRED) | ||
| 582 | pkg_check_modules(LIBVA libva) | ||
| 583 | pkg_check_modules(CUDA cuda) | ||
| 584 | pkg_check_modules(FFNVCODEC ffnvcodec) | ||
| 585 | pkg_check_modules(VDPAU vdpau) | ||
| 586 | |||
| 587 | set(FFmpeg_HWACCEL_LIBRARIES) | ||
| 588 | set(FFmpeg_HWACCEL_FLAGS) | ||
| 589 | set(FFmpeg_HWACCEL_INCLUDE_DIRS) | ||
| 590 | set(FFmpeg_HWACCEL_LDFLAGS) | ||
| 591 | |||
| 592 | if(LIBVA_FOUND) | ||
| 593 | pkg_check_modules(LIBDRM libdrm REQUIRED) | ||
| 594 | find_package(X11 REQUIRED) | ||
| 595 | pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) | ||
| 596 | pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) | ||
| 597 | list(APPEND FFmpeg_HWACCEL_LIBRARIES | ||
| 598 | ${LIBDRM_LIBRARIES} | ||
| 599 | ${X11_LIBRARIES} | ||
| 600 | ${LIBVA-DRM_LIBRARIES} | ||
| 601 | ${LIBVA-X11_LIBRARIES} | ||
| 602 | ${LIBVA_LIBRARIES}) | ||
| 603 | set(FFmpeg_HWACCEL_FLAGS | ||
| 604 | --enable-hwaccel=h264_vaapi | ||
| 605 | --enable-hwaccel=vp8_vaapi | ||
| 606 | --enable-hwaccel=vp9_vaapi | ||
| 607 | --enable-libdrm) | ||
| 608 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS | ||
| 609 | ${LIBDRM_INCLUDE_DIRS} | ||
| 610 | ${X11_INCLUDE_DIRS} | ||
| 611 | ${LIBVA-DRM_INCLUDE_DIRS} | ||
| 612 | ${LIBVA-X11_INCLUDE_DIRS} | ||
| 613 | ${LIBVA_INCLUDE_DIRS} | ||
| 614 | ) | ||
| 615 | message(STATUS "VA-API found") | ||
| 616 | else() | ||
| 617 | set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) | ||
| 618 | endif() | ||
| 619 | |||
| 620 | if (FFNVCODEC_FOUND AND CUDA_FOUND) | ||
| 621 | list(APPEND FFmpeg_HWACCEL_FLAGS | ||
| 622 | --enable-cuvid | ||
| 623 | --enable-ffnvcodec | ||
| 624 | --enable-nvdec | ||
| 625 | --enable-hwaccel=h264_nvdec | ||
| 626 | --enable-hwaccel=vp8_nvdec | ||
| 627 | --enable-hwaccel=vp9_nvdec | ||
| 628 | --extra-cflags=-I${CUDA_INCLUDE_DIRS} | ||
| 629 | ) | ||
| 630 | list(APPEND FFmpeg_HWACCEL_LIBRARIES | ||
| 631 | ${FFNVCODEC_LIBRARIES} | ||
| 632 | ${CUDA_LIBRARIES} | ||
| 633 | ) | ||
| 634 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS | ||
| 635 | ${FFNVCODEC_INCLUDE_DIRS} | ||
| 636 | ${CUDA_INCLUDE_DIRS} | ||
| 637 | ) | ||
| 638 | list(APPEND FFmpeg_HWACCEL_LDFLAGS | ||
| 639 | ${FFNVCODEC_LDFLAGS} | ||
| 640 | ${CUDA_LDFLAGS} | ||
| 641 | ) | ||
| 642 | message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") | ||
| 643 | endif() | ||
| 644 | |||
| 645 | if (VDPAU_FOUND) | ||
| 646 | list(APPEND FFmpeg_HWACCEL_FLAGS | ||
| 647 | --enable-vdpau | ||
| 648 | --enable-hwaccel=h264_vdpau | ||
| 649 | --enable-hwaccel=vp9_vdpau | ||
| 650 | ) | ||
| 651 | list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) | ||
| 652 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) | ||
| 653 | list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) | ||
| 654 | message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") | ||
| 655 | else() | ||
| 656 | list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) | ||
| 657 | endif() | ||
| 658 | |||
| 659 | # `configure` parameters builds only exactly what yuzu needs from FFmpeg | ||
| 660 | # `--disable-vdpau` is needed to avoid linking issues | ||
| 661 | add_custom_command( | ||
| 662 | OUTPUT | ||
| 663 | ${FFmpeg_MAKEFILE} | ||
| 664 | COMMAND | ||
| 665 | /bin/bash ${FFmpeg_PREFIX}/configure | ||
| 666 | --disable-avdevice | ||
| 667 | --disable-avfilter | ||
| 668 | --disable-avformat | ||
| 669 | --disable-doc | ||
| 670 | --disable-everything | ||
| 671 | --disable-ffmpeg | ||
| 672 | --disable-ffprobe | ||
| 673 | --disable-network | ||
| 674 | --disable-postproc | ||
| 675 | --disable-swresample | ||
| 676 | --enable-decoder=h264 | ||
| 677 | --enable-decoder=vp8 | ||
| 678 | --enable-decoder=vp9 | ||
| 679 | --cc="${CMAKE_C_COMPILER}" | ||
| 680 | --cxx="${CMAKE_CXX_COMPILER}" | ||
| 681 | ${FFmpeg_HWACCEL_FLAGS} | ||
| 682 | WORKING_DIRECTORY | ||
| 683 | ${FFmpeg_BUILD_DIR} | ||
| 684 | ) | ||
| 685 | unset(FFmpeg_HWACCEL_FLAGS) | ||
| 686 | |||
| 687 | # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child | ||
| 688 | # with context of the jobserver. Also helps ninja users. | ||
| 689 | execute_process( | ||
| 690 | COMMAND | ||
| 691 | nproc | ||
| 692 | OUTPUT_VARIABLE | ||
| 693 | SYSTEM_THREADS) | ||
| 694 | |||
| 695 | set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) | ||
| 696 | add_custom_command( | ||
| 697 | OUTPUT | ||
| 698 | ${FFmpeg_BUILD_LIBRARIES} | ||
| 699 | COMMAND | ||
| 700 | make -j${SYSTEM_THREADS} | ||
| 701 | WORKING_DIRECTORY | ||
| 702 | ${FFmpeg_BUILD_DIR} | ||
| 703 | ) | ||
| 704 | |||
| 705 | set(FFmpeg_INCLUDE_DIR | ||
| 706 | "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" | ||
| 707 | CACHE PATH "Path to FFmpeg headers" FORCE) | ||
| 708 | |||
| 709 | set(FFmpeg_LDFLAGS | ||
| 710 | "${FFmpeg_HWACCEL_LDFLAGS}" | ||
| 711 | CACHE STRING "FFmpeg linker flags" FORCE) | ||
| 712 | |||
| 713 | # ALL makes this custom target build every time | ||
| 714 | # but it won't actually build if the DEPENDS parameter is up to date | ||
| 715 | add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) | ||
| 716 | add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) | ||
| 717 | link_libraries(${FFmpeg_LIBVA_LIBRARIES}) | ||
| 718 | set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} | ||
| 719 | CACHE PATH "Paths to FFmpeg libraries" FORCE) | ||
| 720 | unset(FFmpeg_BUILD_LIBRARIES) | ||
| 721 | unset(FFmpeg_HWACCEL_FLAGS) | ||
| 722 | unset(FFmpeg_HWACCEL_INCLUDE_DIRS) | ||
| 723 | unset(FFmpeg_HWACCEL_LDFLAGS) | ||
| 724 | unset(FFmpeg_HWACCEL_LIBRARIES) | ||
| 725 | |||
| 726 | if (FFmpeg_FOUND) | ||
| 727 | message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") | ||
| 728 | else() | ||
| 729 | message(FATAL_ERROR "FFmpeg not found") | ||
| 730 | endif() | ||
| 731 | else() # WIN32 | ||
| 732 | # Use yuzu FFmpeg binaries | ||
| 733 | set(FFmpeg_EXT_NAME "ffmpeg-4.4") | ||
| 734 | set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") | ||
| 735 | download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") | ||
| 736 | set(FFmpeg_FOUND YES) | ||
| 737 | set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) | ||
| 738 | set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) | ||
| 739 | set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) | ||
| 740 | set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) | ||
| 741 | set(FFmpeg_LIBRARIES | ||
| 742 | ${FFmpeg_LIBRARY_DIR}/swscale.lib | ||
| 743 | ${FFmpeg_LIBRARY_DIR}/avcodec.lib | ||
| 744 | ${FFmpeg_LIBRARY_DIR}/avutil.lib | ||
| 745 | CACHE PATH "Paths to FFmpeg libraries" FORCE) | ||
| 746 | endif() | ||
| 747 | endif() | ||
| 748 | |||
| 749 | unset(FFmpeg_COMPONENTS) | ||
| 750 | |||
| 751 | # Prefer the -pthread flag on Linux. | 537 | # Prefer the -pthread flag on Linux. |
| 752 | set(THREADS_PREFER_PTHREAD_FLAG ON) | 538 | set(THREADS_PREFER_PTHREAD_FLAG ON) |
| 753 | find_package(Threads REQUIRED) | 539 | find_package(Threads REQUIRED) |
diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake index 43ca730ec..c7da2b91d 100644 --- a/CMakeModules/GenerateSCMRev.cmake +++ b/CMakeModules/GenerateSCMRev.cmake | |||
| @@ -11,9 +11,15 @@ find_package(Git QUIET PATHS "${GIT_EXECUTABLE}") | |||
| 11 | 11 | ||
| 12 | # generate git/build information | 12 | # generate git/build information |
| 13 | include(GetGitRevisionDescription) | 13 | include(GetGitRevisionDescription) |
| 14 | get_git_head_revision(GIT_REF_SPEC GIT_REV) | 14 | if(NOT GIT_REF_SPEC) |
| 15 | git_describe(GIT_DESC --always --long --dirty) | 15 | get_git_head_revision(GIT_REF_SPEC GIT_REV) |
| 16 | git_branch_name(GIT_BRANCH) | 16 | endif() |
| 17 | if(NOT GIT_DESC) | ||
| 18 | git_describe(GIT_DESC --always --long --dirty) | ||
| 19 | endif() | ||
| 20 | if (NOT GIT_BRANCH) | ||
| 21 | git_branch_name(GIT_BRANCH) | ||
| 22 | endif() | ||
| 17 | get_timestamp(BUILD_DATE) | 23 | get_timestamp(BUILD_DATE) |
| 18 | 24 | ||
| 19 | # Generate cpp with Git revision from template | 25 | # Generate cpp with Git revision from template |
diff --git a/dist/yuzu.desktop b/dist/yuzu.desktop index 105080c73..6cc0704d2 100644 --- a/dist/yuzu.desktop +++ b/dist/yuzu.desktop | |||
| @@ -8,5 +8,5 @@ Icon=yuzu | |||
| 8 | TryExec=yuzu | 8 | TryExec=yuzu |
| 9 | Exec=yuzu %f | 9 | Exec=yuzu %f |
| 10 | Categories=Game;Emulator;Qt; | 10 | Categories=Game;Emulator;Qt; |
| 11 | MimeType=application/x-nx-nro;application/x-nx-nso; | 11 | MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci; |
| 12 | Keywords=Switch;Nintendo; \ No newline at end of file | 12 | Keywords=Switch;Nintendo; \ No newline at end of file |
diff --git a/dist/yuzu.xml b/dist/yuzu.xml index f6e408321..dd1e30a6b 100644 --- a/dist/yuzu.xml +++ b/dist/yuzu.xml | |||
| @@ -15,4 +15,19 @@ | |||
| 15 | <glob pattern="*.nso"/> | 15 | <glob pattern="*.nso"/> |
| 16 | <magic><match value="NSO" type="string" offset="0"/></magic> | 16 | <magic><match value="NSO" type="string" offset="0"/></magic> |
| 17 | </mime-type> | 17 | </mime-type> |
| 18 | |||
| 19 | <mime-type type="application/x-nx-nsp"> | ||
| 20 | <comment>Nintendo Switch Package</comment> | ||
| 21 | <acronym>NSP</acronym> | ||
| 22 | <icon name="yuzu"/> | ||
| 23 | <glob pattern="*.nsp"/> | ||
| 24 | <magic><match value="PFS" type="string" offset="0"/></magic> | ||
| 25 | </mime-type> | ||
| 26 | |||
| 27 | <mime-type type="application/x-nx-xci"> | ||
| 28 | <comment>Nintendo Switch Card Image</comment> | ||
| 29 | <acronym>XCI</acronym> | ||
| 30 | <icon name="yuzu"/> | ||
| 31 | <glob pattern="*.xci"/> | ||
| 32 | </mime-type> | ||
| 18 | </mime-info> \ No newline at end of file | 33 | </mime-info> \ No newline at end of file |
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 26ead64f2..158113516 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -52,11 +52,12 @@ endif() | |||
| 52 | # SDL2 | 52 | # SDL2 |
| 53 | if (YUZU_USE_EXTERNAL_SDL2) | 53 | if (YUZU_USE_EXTERNAL_SDL2) |
| 54 | if (NOT WIN32) | 54 | if (NOT WIN32) |
| 55 | # Yuzu itself needs: Events Joystick Haptic Sensor Timers Audio | 55 | # Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers |
| 56 | # Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095) | ||
| 56 | # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen) | 57 | # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen) |
| 57 | set(SDL_UNUSED_SUBSYSTEMS | 58 | set(SDL_UNUSED_SUBSYSTEMS |
| 58 | Atomic Render Power Threads | 59 | CPUinfo File Filesystem |
| 59 | File CPUinfo Filesystem Locale) | 60 | Locale Power Render) |
| 60 | foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS}) | 61 | foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS}) |
| 61 | string(TOUPPER ${_SUB} _OPT) | 62 | string(TOUPPER ${_SUB} _OPT) |
| 62 | option(SDL_${_OPT} "" OFF) | 63 | option(SDL_${_OPT} "" OFF) |
| @@ -121,3 +122,12 @@ if (YUZU_USE_BUNDLED_OPUS) | |||
| 121 | else() | 122 | else() |
| 122 | find_package(opus 1.3 REQUIRED) | 123 | find_package(opus 1.3 REQUIRED) |
| 123 | endif() | 124 | endif() |
| 125 | |||
| 126 | # FFMpeg | ||
| 127 | if (YUZU_USE_BUNDLED_FFMPEG) | ||
| 128 | add_subdirectory(ffmpeg) | ||
| 129 | set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE) | ||
| 130 | set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE) | ||
| 131 | set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE) | ||
| 132 | set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) | ||
| 133 | endif() | ||
diff --git a/externals/SDL b/externals/SDL | |||
| Subproject 2e9821423a237a1206e3c09020778faacfe430b | Subproject e2ade2bfc46d915cd306c63c830b81d800b2575 | ||
diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers | |||
| Subproject 07c4a37bcf41ea50aef6e98236abdfe8089fb4c | Subproject e005e1f8175d006adc3676b40ac3dd2212961a6 | ||
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject cce7e4ee5d7b07a4609c73c053fbf57dc8c7845 | Subproject 28714ee75aa079cbb706e38bdabc8ee1f6c6951 | ||
diff --git a/externals/ffmpeg b/externals/ffmpeg deleted file mode 160000 | |||
| Subproject 79e8d17024e6c6328a40fcee191ffd70798a9c6 | |||
diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt new file mode 100644 index 000000000..c57b54f77 --- /dev/null +++ b/externals/ffmpeg/CMakeLists.txt | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | if (NOT WIN32) | ||
| 2 | # Build FFmpeg from externals | ||
| 3 | message(STATUS "Using FFmpeg from externals") | ||
| 4 | |||
| 5 | if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)") | ||
| 6 | # FFmpeg has source that requires one of nasm or yasm to assemble it. | ||
| 7 | # REQUIRED throws an error if not found here during configuration rather than during compilation. | ||
| 8 | find_program(ASSEMBLER NAMES nasm yasm) | ||
| 9 | if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND") | ||
| 10 | message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.") | ||
| 11 | endif() | ||
| 12 | endif() | ||
| 13 | |||
| 14 | find_program(AUTOCONF autoconf) | ||
| 15 | if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND") | ||
| 16 | message(FATAL_ERROR "Required program `autoconf` not found.") | ||
| 17 | endif() | ||
| 18 | |||
| 19 | set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg) | ||
| 20 | set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg-build) | ||
| 21 | set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile) | ||
| 22 | make_directory(${FFmpeg_BUILD_DIR}) | ||
| 23 | |||
| 24 | # Read version string from external | ||
| 25 | file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION) | ||
| 26 | set(FFmpeg_FOUND NO) | ||
| 27 | if (NOT FFmpeg_VERSION STREQUAL "") | ||
| 28 | set(FFmpeg_FOUND YES) | ||
| 29 | endif() | ||
| 30 | |||
| 31 | unset(FFmpeg_LIBRARIES CACHE) | ||
| 32 | foreach(COMPONENT ${FFmpeg_COMPONENTS}) | ||
| 33 | set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}") | ||
| 34 | set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a") | ||
| 35 | set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}") | ||
| 36 | |||
| 37 | set(FFmpeg_LIBRARIES | ||
| 38 | ${FFmpeg_LIBRARIES} | ||
| 39 | ${FFmpeg_${COMPONENT}_LIBRARY} | ||
| 40 | CACHE PATH "Paths to FFmpeg libraries" FORCE) | ||
| 41 | endforeach() | ||
| 42 | |||
| 43 | Include(FindPkgConfig REQUIRED) | ||
| 44 | pkg_check_modules(LIBVA libva) | ||
| 45 | pkg_check_modules(CUDA cuda) | ||
| 46 | pkg_check_modules(FFNVCODEC ffnvcodec) | ||
| 47 | pkg_check_modules(VDPAU vdpau) | ||
| 48 | |||
| 49 | set(FFmpeg_HWACCEL_LIBRARIES) | ||
| 50 | set(FFmpeg_HWACCEL_FLAGS) | ||
| 51 | set(FFmpeg_HWACCEL_INCLUDE_DIRS) | ||
| 52 | set(FFmpeg_HWACCEL_LDFLAGS) | ||
| 53 | |||
| 54 | if(LIBVA_FOUND) | ||
| 55 | pkg_check_modules(LIBDRM libdrm REQUIRED) | ||
| 56 | find_package(X11 REQUIRED) | ||
| 57 | pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) | ||
| 58 | pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) | ||
| 59 | list(APPEND FFmpeg_HWACCEL_LIBRARIES | ||
| 60 | ${LIBDRM_LIBRARIES} | ||
| 61 | ${X11_LIBRARIES} | ||
| 62 | ${LIBVA-DRM_LIBRARIES} | ||
| 63 | ${LIBVA-X11_LIBRARIES} | ||
| 64 | ${LIBVA_LIBRARIES}) | ||
| 65 | set(FFmpeg_HWACCEL_FLAGS | ||
| 66 | --enable-hwaccel=h264_vaapi | ||
| 67 | --enable-hwaccel=vp8_vaapi | ||
| 68 | --enable-hwaccel=vp9_vaapi | ||
| 69 | --enable-libdrm) | ||
| 70 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS | ||
| 71 | ${LIBDRM_INCLUDE_DIRS} | ||
| 72 | ${X11_INCLUDE_DIRS} | ||
| 73 | ${LIBVA-DRM_INCLUDE_DIRS} | ||
| 74 | ${LIBVA-X11_INCLUDE_DIRS} | ||
| 75 | ${LIBVA_INCLUDE_DIRS} | ||
| 76 | ) | ||
| 77 | message(STATUS "VA-API found") | ||
| 78 | else() | ||
| 79 | set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) | ||
| 80 | endif() | ||
| 81 | |||
| 82 | if (FFNVCODEC_FOUND) | ||
| 83 | list(APPEND FFmpeg_HWACCEL_FLAGS | ||
| 84 | --enable-cuvid | ||
| 85 | --enable-ffnvcodec | ||
| 86 | --enable-nvdec | ||
| 87 | --enable-hwaccel=h264_nvdec | ||
| 88 | --enable-hwaccel=vp8_nvdec | ||
| 89 | --enable-hwaccel=vp9_nvdec | ||
| 90 | ) | ||
| 91 | list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) | ||
| 92 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) | ||
| 93 | list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) | ||
| 94 | message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") | ||
| 95 | # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress | ||
| 96 | # here we handle the hard-linking senario where CUDA is linked during compilation | ||
| 97 | if (CUDA_FOUND) | ||
| 98 | list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) | ||
| 99 | list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) | ||
| 100 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) | ||
| 101 | list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) | ||
| 102 | message(STATUS "CUDA libraries found, hard-linking will be performed") | ||
| 103 | endif(CUDA_FOUND) | ||
| 104 | endif() | ||
| 105 | |||
| 106 | if (VDPAU_FOUND) | ||
| 107 | list(APPEND FFmpeg_HWACCEL_FLAGS | ||
| 108 | --enable-vdpau | ||
| 109 | --enable-hwaccel=h264_vdpau | ||
| 110 | --enable-hwaccel=vp9_vdpau | ||
| 111 | ) | ||
| 112 | list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) | ||
| 113 | list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) | ||
| 114 | list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) | ||
| 115 | message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") | ||
| 116 | else() | ||
| 117 | list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) | ||
| 118 | endif() | ||
| 119 | |||
| 120 | # `configure` parameters builds only exactly what yuzu needs from FFmpeg | ||
| 121 | # `--disable-vdpau` is needed to avoid linking issues | ||
| 122 | add_custom_command( | ||
| 123 | OUTPUT | ||
| 124 | ${FFmpeg_MAKEFILE} | ||
| 125 | COMMAND | ||
| 126 | /bin/bash ${FFmpeg_PREFIX}/configure | ||
| 127 | --disable-avdevice | ||
| 128 | --disable-avfilter | ||
| 129 | --disable-avformat | ||
| 130 | --disable-doc | ||
| 131 | --disable-everything | ||
| 132 | --disable-ffmpeg | ||
| 133 | --disable-ffprobe | ||
| 134 | --disable-network | ||
| 135 | --disable-postproc | ||
| 136 | --disable-swresample | ||
| 137 | --enable-decoder=h264 | ||
| 138 | --enable-decoder=vp8 | ||
| 139 | --enable-decoder=vp9 | ||
| 140 | --cc="${CMAKE_C_COMPILER}" | ||
| 141 | --cxx="${CMAKE_CXX_COMPILER}" | ||
| 142 | ${FFmpeg_HWACCEL_FLAGS} | ||
| 143 | WORKING_DIRECTORY | ||
| 144 | ${FFmpeg_BUILD_DIR} | ||
| 145 | ) | ||
| 146 | unset(FFmpeg_HWACCEL_FLAGS) | ||
| 147 | |||
| 148 | # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child | ||
| 149 | # with context of the jobserver. Also helps ninja users. | ||
| 150 | execute_process( | ||
| 151 | COMMAND | ||
| 152 | nproc | ||
| 153 | OUTPUT_VARIABLE | ||
| 154 | SYSTEM_THREADS) | ||
| 155 | |||
| 156 | set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES}) | ||
| 157 | add_custom_command( | ||
| 158 | OUTPUT | ||
| 159 | ${FFmpeg_BUILD_LIBRARIES} | ||
| 160 | COMMAND | ||
| 161 | make -j${SYSTEM_THREADS} | ||
| 162 | WORKING_DIRECTORY | ||
| 163 | ${FFmpeg_BUILD_DIR} | ||
| 164 | ) | ||
| 165 | |||
| 166 | set(FFmpeg_INCLUDE_DIR | ||
| 167 | "${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}" | ||
| 168 | CACHE PATH "Path to FFmpeg headers" FORCE) | ||
| 169 | |||
| 170 | set(FFmpeg_LDFLAGS | ||
| 171 | "${FFmpeg_HWACCEL_LDFLAGS}" | ||
| 172 | CACHE STRING "FFmpeg linker flags" FORCE) | ||
| 173 | |||
| 174 | # ALL makes this custom target build every time | ||
| 175 | # but it won't actually build if the DEPENDS parameter is up to date | ||
| 176 | add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE}) | ||
| 177 | add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure) | ||
| 178 | link_libraries(${FFmpeg_LIBVA_LIBRARIES}) | ||
| 179 | set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES} | ||
| 180 | CACHE PATH "Paths to FFmpeg libraries" FORCE) | ||
| 181 | unset(FFmpeg_BUILD_LIBRARIES) | ||
| 182 | unset(FFmpeg_HWACCEL_FLAGS) | ||
| 183 | unset(FFmpeg_HWACCEL_INCLUDE_DIRS) | ||
| 184 | unset(FFmpeg_HWACCEL_LDFLAGS) | ||
| 185 | unset(FFmpeg_HWACCEL_LIBRARIES) | ||
| 186 | |||
| 187 | if (FFmpeg_FOUND) | ||
| 188 | message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}") | ||
| 189 | else() | ||
| 190 | message(FATAL_ERROR "FFmpeg not found") | ||
| 191 | endif() | ||
| 192 | else(WIN32) | ||
| 193 | # Use yuzu FFmpeg binaries | ||
| 194 | set(FFmpeg_EXT_NAME "ffmpeg-4.4") | ||
| 195 | set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}") | ||
| 196 | download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "") | ||
| 197 | set(FFmpeg_FOUND YES) | ||
| 198 | set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) | ||
| 199 | set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE) | ||
| 200 | set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE) | ||
| 201 | set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) | ||
| 202 | set(FFmpeg_LIBRARIES | ||
| 203 | ${FFmpeg_LIBRARY_DIR}/swscale.lib | ||
| 204 | ${FFmpeg_LIBRARY_DIR}/avcodec.lib | ||
| 205 | ${FFmpeg_LIBRARY_DIR}/avutil.lib | ||
| 206 | CACHE PATH "Paths to FFmpeg libraries" FORCE) | ||
| 207 | # exported variables | ||
| 208 | set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE) | ||
| 209 | set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE) | ||
| 210 | set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE) | ||
| 211 | set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE) | ||
| 212 | endif(WIN32) | ||
| 213 | |||
| 214 | unset(FFmpeg_COMPONENTS) | ||
diff --git a/externals/ffmpeg/ffmpeg b/externals/ffmpeg/ffmpeg new file mode 160000 | |||
| Subproject dc91b913b6260e85e1304c74ff7bb3c22a8c9fb | |||
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 919da4a53..790193b00 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -22,6 +22,11 @@ add_custom_command(OUTPUT scm_rev.cpp | |||
| 22 | -DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING} | 22 | -DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING} |
| 23 | -DBUILD_TAG=${BUILD_TAG} | 23 | -DBUILD_TAG=${BUILD_TAG} |
| 24 | -DBUILD_ID=${DISPLAY_VERSION} | 24 | -DBUILD_ID=${DISPLAY_VERSION} |
| 25 | -DGIT_REF_SPEC=${GIT_REF_SPEC} | ||
| 26 | -DGIT_REV=${GIT_REV} | ||
| 27 | -DGIT_DESC=${GIT_DESC} | ||
| 28 | -DGIT_BRANCH=${GIT_BRANCH} | ||
| 29 | -DBUILD_FULLNAME=${BUILD_FULLNAME} | ||
| 25 | -DGIT_EXECUTABLE=${GIT_EXECUTABLE} | 30 | -DGIT_EXECUTABLE=${GIT_EXECUTABLE} |
| 26 | -P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake | 31 | -P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake |
| 27 | DEPENDS | 32 | DEPENDS |
diff --git a/src/common/settings.h b/src/common/settings.h index 313f1fa7f..d01c0448c 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -597,6 +597,7 @@ struct Values { | |||
| 597 | BasicSetting<std::string> program_args{std::string(), "program_args"}; | 597 | BasicSetting<std::string> program_args{std::string(), "program_args"}; |
| 598 | BasicSetting<bool> dump_exefs{false, "dump_exefs"}; | 598 | BasicSetting<bool> dump_exefs{false, "dump_exefs"}; |
| 599 | BasicSetting<bool> dump_nso{false, "dump_nso"}; | 599 | BasicSetting<bool> dump_nso{false, "dump_nso"}; |
| 600 | BasicSetting<bool> dump_shaders{false, "dump_shaders"}; | ||
| 600 | BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"}; | 601 | BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"}; |
| 601 | BasicSetting<bool> reporting_services{false, "reporting_services"}; | 602 | BasicSetting<bool> reporting_services{false, "reporting_services"}; |
| 602 | BasicSetting<bool> quest_flag{false, "quest_flag"}; | 603 | BasicSetting<bool> quest_flag{false, "quest_flag"}; |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 49bed614a..b1a746727 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -187,6 +187,8 @@ add_library(core STATIC | |||
| 187 | hle/kernel/k_event.h | 187 | hle/kernel/k_event.h |
| 188 | hle/kernel/k_handle_table.cpp | 188 | hle/kernel/k_handle_table.cpp |
| 189 | hle/kernel/k_handle_table.h | 189 | hle/kernel/k_handle_table.h |
| 190 | hle/kernel/k_interrupt_manager.cpp | ||
| 191 | hle/kernel/k_interrupt_manager.h | ||
| 190 | hle/kernel/k_light_condition_variable.cpp | 192 | hle/kernel/k_light_condition_variable.cpp |
| 191 | hle/kernel/k_light_condition_variable.h | 193 | hle/kernel/k_light_condition_variable.h |
| 192 | hle/kernel/k_light_lock.cpp | 194 | hle/kernel/k_light_lock.cpp |
| @@ -265,8 +267,6 @@ add_library(core STATIC | |||
| 265 | hle/kernel/svc_wrap.h | 267 | hle/kernel/svc_wrap.h |
| 266 | hle/kernel/time_manager.cpp | 268 | hle/kernel/time_manager.cpp |
| 267 | hle/kernel/time_manager.h | 269 | hle/kernel/time_manager.h |
| 268 | hle/lock.cpp | ||
| 269 | hle/lock.h | ||
| 270 | hle/result.h | 270 | hle/result.h |
| 271 | hle/service/acc/acc.cpp | 271 | hle/service/acc/acc.cpp |
| 272 | hle/service/acc/acc.h | 272 | hle/service/acc/acc.h |
diff --git a/src/core/core.cpp b/src/core/core.cpp index aa96f709b..3f9a7f44b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -317,6 +317,8 @@ struct System::Impl { | |||
| 317 | is_powered_on = false; | 317 | is_powered_on = false; |
| 318 | exit_lock = false; | 318 | exit_lock = false; |
| 319 | 319 | ||
| 320 | gpu_core->NotifyShutdown(); | ||
| 321 | |||
| 320 | services.reset(); | 322 | services.reset(); |
| 321 | service_manager.reset(); | 323 | service_manager.reset(); |
| 322 | cheat_engine.reset(); | 324 | cheat_engine.reset(); |
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 6dbd38ffa..e1033b634 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp | |||
| @@ -45,26 +45,26 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb | |||
| 45 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld | 45 | // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld |
| 46 | if (parameters.allow_pro_controller) { | 46 | if (parameters.allow_pro_controller) { |
| 47 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | 47 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); |
| 48 | controller->Connect(); | 48 | controller->Connect(true); |
| 49 | } else if (parameters.allow_dual_joycons) { | 49 | } else if (parameters.allow_dual_joycons) { |
| 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); | 50 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); |
| 51 | controller->Connect(); | 51 | controller->Connect(true); |
| 52 | } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { | 52 | } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { |
| 53 | // Assign left joycons to even player indices and right joycons to odd player indices. | 53 | // Assign left joycons to even player indices and right joycons to odd player indices. |
| 54 | // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and | 54 | // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and |
| 55 | // a right Joycon for Player 2 in 2 Player Assist mode. | 55 | // a right Joycon for Player 2 in 2 Player Assist mode. |
| 56 | if (index % 2 == 0) { | 56 | if (index % 2 == 0) { |
| 57 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); | 57 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); |
| 58 | controller->Connect(); | 58 | controller->Connect(true); |
| 59 | } else { | 59 | } else { |
| 60 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); | 60 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); |
| 61 | controller->Connect(); | 61 | controller->Connect(true); |
| 62 | } | 62 | } |
| 63 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && | 63 | } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && |
| 64 | !Settings::values.use_docked_mode.GetValue()) { | 64 | !Settings::values.use_docked_mode.GetValue()) { |
| 65 | // We should *never* reach here under any normal circumstances. | 65 | // We should *never* reach here under any normal circumstances. |
| 66 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | 66 | controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); |
| 67 | controller->Connect(); | 67 | controller->Connect(true); |
| 68 | } else { | 68 | } else { |
| 69 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); | 69 | UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); |
| 70 | } | 70 | } |
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 685ec080c..08f8af551 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp | |||
| @@ -161,7 +161,10 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { | |||
| 161 | motion.rotation = emulated.GetGyroscope(); | 161 | motion.rotation = emulated.GetGyroscope(); |
| 162 | motion.orientation = emulated.GetOrientation(); | 162 | motion.orientation = emulated.GetOrientation(); |
| 163 | motion.quaternion = emulated.GetQuaternion(); | 163 | motion.quaternion = emulated.GetQuaternion(); |
| 164 | motion.gyro_bias = emulated.GetGyroBias(); | ||
| 164 | motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); | 165 | motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); |
| 166 | // Find what is this value | ||
| 167 | motion.verticalization_error = 0.0f; | ||
| 165 | 168 | ||
| 166 | TriggerOnChange(ConsoleTriggerType::Motion); | 169 | TriggerOnChange(ConsoleTriggerType::Motion); |
| 167 | } | 170 | } |
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 3afd284d5..707419102 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h | |||
| @@ -50,6 +50,8 @@ struct ConsoleMotion { | |||
| 50 | Common::Vec3f rotation{}; | 50 | Common::Vec3f rotation{}; |
| 51 | std::array<Common::Vec3f, 3> orientation{}; | 51 | std::array<Common::Vec3f, 3> orientation{}; |
| 52 | Common::Quaternion<f32> quaternion{}; | 52 | Common::Quaternion<f32> quaternion{}; |
| 53 | Common::Vec3f gyro_bias{}; | ||
| 54 | f32 verticalization_error{}; | ||
| 53 | bool is_at_rest{}; | 55 | bool is_at_rest{}; |
| 54 | }; | 56 | }; |
| 55 | 57 | ||
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 93372445b..71fc05807 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -843,23 +843,18 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v | |||
| 843 | } | 843 | } |
| 844 | 844 | ||
| 845 | bool EmulatedController::TestVibration(std::size_t device_index) { | 845 | bool EmulatedController::TestVibration(std::size_t device_index) { |
| 846 | if (device_index >= output_devices.size()) { | 846 | static constexpr VibrationValue test_vibration = { |
| 847 | return false; | ||
| 848 | } | ||
| 849 | if (!output_devices[device_index]) { | ||
| 850 | return false; | ||
| 851 | } | ||
| 852 | |||
| 853 | // Send a slight vibration to test for rumble support | ||
| 854 | constexpr Common::Input::VibrationStatus status = { | ||
| 855 | .low_amplitude = 0.001f, | 847 | .low_amplitude = 0.001f, |
| 856 | .low_frequency = 160.0f, | 848 | .low_frequency = 160.0f, |
| 857 | .high_amplitude = 0.001f, | 849 | .high_amplitude = 0.001f, |
| 858 | .high_frequency = 320.0f, | 850 | .high_frequency = 320.0f, |
| 859 | .type = Common::Input::VibrationAmplificationType::Linear, | ||
| 860 | }; | 851 | }; |
| 861 | return output_devices[device_index]->SetVibration(status) == | 852 | |
| 862 | Common::Input::VibrationError::None; | 853 | // Send a slight vibration to test for rumble support |
| 854 | SetVibration(device_index, test_vibration); | ||
| 855 | |||
| 856 | // Stop any vibration and return the result | ||
| 857 | return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); | ||
| 863 | } | 858 | } |
| 864 | 859 | ||
| 865 | void EmulatedController::SetLedPattern() { | 860 | void EmulatedController::SetLedPattern() { |
| @@ -884,15 +879,42 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) | |||
| 884 | if (!is_connected) { | 879 | if (!is_connected) { |
| 885 | return; | 880 | return; |
| 886 | } | 881 | } |
| 887 | if (!IsControllerSupported()) { | 882 | if (IsControllerSupported()) { |
| 888 | LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller", | 883 | return; |
| 889 | npad_type); | ||
| 890 | Disconnect(); | ||
| 891 | } | 884 | } |
| 885 | |||
| 886 | Disconnect(); | ||
| 887 | |||
| 888 | // Fallback fullkey controllers to Pro controllers | ||
| 889 | if (IsControllerFullkey() && supported_style_tag.fullkey) { | ||
| 890 | LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); | ||
| 891 | SetNpadStyleIndex(NpadStyleIndex::ProController); | ||
| 892 | Connect(); | ||
| 893 | return; | ||
| 894 | } | ||
| 895 | |||
| 896 | LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller", | ||
| 897 | npad_type); | ||
| 892 | } | 898 | } |
| 893 | 899 | ||
| 894 | bool EmulatedController::IsControllerSupported() const { | 900 | bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { |
| 895 | switch (npad_type) { | 901 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 902 | switch (type) { | ||
| 903 | case NpadStyleIndex::ProController: | ||
| 904 | case NpadStyleIndex::GameCube: | ||
| 905 | case NpadStyleIndex::NES: | ||
| 906 | case NpadStyleIndex::SNES: | ||
| 907 | case NpadStyleIndex::N64: | ||
| 908 | case NpadStyleIndex::SegaGenesis: | ||
| 909 | return true; | ||
| 910 | default: | ||
| 911 | return false; | ||
| 912 | } | ||
| 913 | } | ||
| 914 | |||
| 915 | bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { | ||
| 916 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||
| 917 | switch (type) { | ||
| 896 | case NpadStyleIndex::ProController: | 918 | case NpadStyleIndex::ProController: |
| 897 | return supported_style_tag.fullkey; | 919 | return supported_style_tag.fullkey; |
| 898 | case NpadStyleIndex::Handheld: | 920 | case NpadStyleIndex::Handheld: |
| @@ -920,9 +942,10 @@ bool EmulatedController::IsControllerSupported() const { | |||
| 920 | } | 942 | } |
| 921 | } | 943 | } |
| 922 | 944 | ||
| 923 | void EmulatedController::Connect() { | 945 | void EmulatedController::Connect(bool use_temporary_value) { |
| 924 | if (!IsControllerSupported()) { | 946 | if (!IsControllerSupported(use_temporary_value)) { |
| 925 | LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type); | 947 | const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; |
| 948 | LOG_ERROR(Service_HID, "Controller type {} is not supported", type); | ||
| 926 | return; | 949 | return; |
| 927 | } | 950 | } |
| 928 | { | 951 | { |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index e42aafebc..c0994ab4d 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -167,8 +167,11 @@ public: | |||
| 167 | */ | 167 | */ |
| 168 | void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); | 168 | void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); |
| 169 | 169 | ||
| 170 | /// Sets the connected status to true | 170 | /** |
| 171 | void Connect(); | 171 | * Sets the connected status to true |
| 172 | * @param use_temporary_value If true tmp_npad_type will be used | ||
| 173 | */ | ||
| 174 | void Connect(bool use_temporary_value = false); | ||
| 172 | 175 | ||
| 173 | /// Sets the connected status to false | 176 | /// Sets the connected status to false |
| 174 | void Disconnect(); | 177 | void Disconnect(); |
| @@ -318,10 +321,17 @@ private: | |||
| 318 | void LoadTASParams(); | 321 | void LoadTASParams(); |
| 319 | 322 | ||
| 320 | /** | 323 | /** |
| 324 | * @param use_temporary_value If true tmp_npad_type will be used | ||
| 325 | * @return true if the controller style is fullkey | ||
| 326 | */ | ||
| 327 | bool IsControllerFullkey(bool use_temporary_value = false) const; | ||
| 328 | |||
| 329 | /** | ||
| 321 | * Checks the current controller type against the supported_style_tag | 330 | * Checks the current controller type against the supported_style_tag |
| 331 | * @param use_temporary_value If true tmp_npad_type will be used | ||
| 322 | * @return true if the controller is supported | 332 | * @return true if the controller is supported |
| 323 | */ | 333 | */ |
| 324 | bool IsControllerSupported() const; | 334 | bool IsControllerSupported(bool use_temporary_value = false) const; |
| 325 | 335 | ||
| 326 | /** | 336 | /** |
| 327 | * Updates the button status of the controller | 337 | * Updates the button status of the controller |
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 7c12f01fc..4eca68533 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h | |||
| @@ -496,6 +496,13 @@ struct VibrationValue { | |||
| 496 | }; | 496 | }; |
| 497 | static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); | 497 | static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); |
| 498 | 498 | ||
| 499 | constexpr VibrationValue DEFAULT_VIBRATION_VALUE{ | ||
| 500 | .low_amplitude = 0.0f, | ||
| 501 | .low_frequency = 160.0f, | ||
| 502 | .high_amplitude = 0.0f, | ||
| 503 | .high_frequency = 320.0f, | ||
| 504 | }; | ||
| 505 | |||
| 499 | // This is nn::hid::VibrationDeviceInfo | 506 | // This is nn::hid::VibrationDeviceInfo |
| 500 | struct VibrationDeviceInfo { | 507 | struct VibrationDeviceInfo { |
| 501 | VibrationDeviceType type{}; | 508 | VibrationDeviceType type{}; |
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp index c25fea966..a23f192d7 100644 --- a/src/core/hid/motion_input.cpp +++ b/src/core/hid/motion_input.cpp | |||
| @@ -23,11 +23,11 @@ void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { | |||
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { | 25 | void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { |
| 26 | gyro = gyroscope - gyro_drift; | 26 | gyro = gyroscope - gyro_bias; |
| 27 | 27 | ||
| 28 | // Auto adjust drift to minimize drift | 28 | // Auto adjust drift to minimize drift |
| 29 | if (!IsMoving(0.1f)) { | 29 | if (!IsMoving(0.1f)) { |
| 30 | gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f); | 30 | gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | if (gyro.Length2() < gyro_threshold) { | 33 | if (gyro.Length2() < gyro_threshold) { |
| @@ -41,8 +41,8 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) { | |||
| 41 | quat = quaternion; | 41 | quat = quaternion; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | void MotionInput::SetGyroDrift(const Common::Vec3f& drift) { | 44 | void MotionInput::SetGyroBias(const Common::Vec3f& bias) { |
| 45 | gyro_drift = drift; | 45 | gyro_bias = bias; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | void MotionInput::SetGyroThreshold(f32 threshold) { | 48 | void MotionInput::SetGyroThreshold(f32 threshold) { |
| @@ -192,6 +192,10 @@ Common::Vec3f MotionInput::GetGyroscope() const { | |||
| 192 | return gyro; | 192 | return gyro; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | Common::Vec3f MotionInput::GetGyroBias() const { | ||
| 196 | return gyro_bias; | ||
| 197 | } | ||
| 198 | |||
| 195 | Common::Quaternion<f32> MotionInput::GetQuaternion() const { | 199 | Common::Quaternion<f32> MotionInput::GetQuaternion() const { |
| 196 | return quat; | 200 | return quat; |
| 197 | } | 201 | } |
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h index 5b5b420bb..bca4520fa 100644 --- a/src/core/hid/motion_input.h +++ b/src/core/hid/motion_input.h | |||
| @@ -24,7 +24,7 @@ public: | |||
| 24 | void SetAcceleration(const Common::Vec3f& acceleration); | 24 | void SetAcceleration(const Common::Vec3f& acceleration); |
| 25 | void SetGyroscope(const Common::Vec3f& gyroscope); | 25 | void SetGyroscope(const Common::Vec3f& gyroscope); |
| 26 | void SetQuaternion(const Common::Quaternion<f32>& quaternion); | 26 | void SetQuaternion(const Common::Quaternion<f32>& quaternion); |
| 27 | void SetGyroDrift(const Common::Vec3f& drift); | 27 | void SetGyroBias(const Common::Vec3f& bias); |
| 28 | void SetGyroThreshold(f32 threshold); | 28 | void SetGyroThreshold(f32 threshold); |
| 29 | 29 | ||
| 30 | void EnableReset(bool reset); | 30 | void EnableReset(bool reset); |
| @@ -36,6 +36,7 @@ public: | |||
| 36 | [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const; | 36 | [[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const; |
| 37 | [[nodiscard]] Common::Vec3f GetAcceleration() const; | 37 | [[nodiscard]] Common::Vec3f GetAcceleration() const; |
| 38 | [[nodiscard]] Common::Vec3f GetGyroscope() const; | 38 | [[nodiscard]] Common::Vec3f GetGyroscope() const; |
| 39 | [[nodiscard]] Common::Vec3f GetGyroBias() const; | ||
| 39 | [[nodiscard]] Common::Vec3f GetRotations() const; | 40 | [[nodiscard]] Common::Vec3f GetRotations() const; |
| 40 | [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const; | 41 | [[nodiscard]] Common::Quaternion<f32> GetQuaternion() const; |
| 41 | 42 | ||
| @@ -69,7 +70,7 @@ private: | |||
| 69 | Common::Vec3f gyro; | 70 | Common::Vec3f gyro; |
| 70 | 71 | ||
| 71 | // Vector to be substracted from gyro measurements | 72 | // Vector to be substracted from gyro measurements |
| 72 | Common::Vec3f gyro_drift; | 73 | Common::Vec3f gyro_bias; |
| 73 | 74 | ||
| 74 | // Minimum gyro amplitude to detect if the device is moving | 75 | // Minimum gyro amplitude to detect if the device is moving |
| 75 | f32 gyro_threshold = 0.0f; | 76 | f32 gyro_threshold = 0.0f; |
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index 4f4e338e3..baad2c5d6 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/hle/kernel/global_scheduler_context.h" | 9 | #include "core/hle/kernel/global_scheduler_context.h" |
| 10 | #include "core/hle/kernel/k_scheduler.h" | 10 | #include "core/hle/kernel/k_scheduler.h" |
| 11 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/physical_core.h" | ||
| 12 | 13 | ||
| 13 | namespace Kernel { | 14 | namespace Kernel { |
| 14 | 15 | ||
| @@ -42,6 +43,11 @@ void GlobalSchedulerContext::PreemptThreads() { | |||
| 42 | for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | 43 | for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { |
| 43 | const u32 priority = preemption_priorities[core_id]; | 44 | const u32 priority = preemption_priorities[core_id]; |
| 44 | kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority); | 45 | kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority); |
| 46 | |||
| 47 | // Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result | ||
| 48 | // in the rotator thread being scheduled. For cores 0-2, this is to simulate or system | ||
| 49 | // interrupts that may have occurred. | ||
| 50 | kernel.PhysicalCore(core_id).Interrupt(); | ||
| 45 | } | 51 | } |
| 46 | } | 52 | } |
| 47 | 53 | ||
diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp new file mode 100644 index 000000000..e5dd39751 --- /dev/null +++ b/src/core/hle/kernel/k_interrupt_manager.cpp | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/k_interrupt_manager.h" | ||
| 6 | #include "core/hle/kernel/k_process.h" | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | ||
| 10 | |||
| 11 | namespace Kernel::KInterruptManager { | ||
| 12 | |||
| 13 | void HandleInterrupt(KernelCore& kernel, s32 core_id) { | ||
| 14 | auto* process = kernel.CurrentProcess(); | ||
| 15 | if (!process) { | ||
| 16 | return; | ||
| 17 | } | ||
| 18 | |||
| 19 | auto& scheduler = kernel.Scheduler(core_id); | ||
| 20 | auto& current_thread = *scheduler.GetCurrentThread(); | ||
| 21 | |||
| 22 | // If the user disable count is set, we may need to pin the current thread. | ||
| 23 | if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) { | ||
| 24 | KScopedSchedulerLock sl{kernel}; | ||
| 25 | |||
| 26 | // Pin the current thread. | ||
| 27 | process->PinCurrentThread(core_id); | ||
| 28 | |||
| 29 | // Set the interrupt flag for the thread. | ||
| 30 | scheduler.GetCurrentThread()->SetInterruptFlag(); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | } // namespace Kernel::KInterruptManager | ||
diff --git a/src/core/hle/kernel/k_interrupt_manager.h b/src/core/hle/kernel/k_interrupt_manager.h new file mode 100644 index 000000000..05924801e --- /dev/null +++ b/src/core/hle/kernel/k_interrupt_manager.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class KernelCore; | ||
| 12 | |||
| 13 | namespace KInterruptManager { | ||
| 14 | void HandleInterrupt(KernelCore& kernel, s32 core_id); | ||
| 15 | } | ||
| 16 | |||
| 17 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index fd491146f..9e51c33ce 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -120,7 +120,7 @@ static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015); | |||
| 120 | 120 | ||
| 121 | enum class KMemoryPermission : u8 { | 121 | enum class KMemoryPermission : u8 { |
| 122 | None = 0, | 122 | None = 0, |
| 123 | Mask = static_cast<u8>(~None), | 123 | All = static_cast<u8>(~None), |
| 124 | 124 | ||
| 125 | Read = 1 << 0, | 125 | Read = 1 << 0, |
| 126 | Write = 1 << 1, | 126 | Write = 1 << 1, |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 99982e5a3..4da509224 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -264,9 +264,9 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_ | |||
| 264 | ASSERT(heap_last < stack_start || stack_last < heap_start); | 264 | ASSERT(heap_last < stack_start || stack_last < heap_start); |
| 265 | ASSERT(heap_last < kmap_start || kmap_last < heap_start); | 265 | ASSERT(heap_last < kmap_start || kmap_last < heap_start); |
| 266 | 266 | ||
| 267 | current_heap_addr = heap_region_start; | 267 | current_heap_end = heap_region_start; |
| 268 | heap_capacity = 0; | 268 | max_heap_size = 0; |
| 269 | physical_memory_usage = 0; | 269 | mapped_physical_memory_size = 0; |
| 270 | memory_pool = pool; | 270 | memory_pool = pool; |
| 271 | 271 | ||
| 272 | page_table_impl.Resize(address_space_width, PageBits); | 272 | page_table_impl.Resize(address_space_width, PageBits); |
| @@ -306,7 +306,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std: | |||
| 306 | KMemoryState state{}; | 306 | KMemoryState state{}; |
| 307 | KMemoryPermission perm{}; | 307 | KMemoryPermission perm{}; |
| 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, | 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, |
| 309 | KMemoryState::Normal, KMemoryPermission::Mask, | 309 | KMemoryState::Normal, KMemoryPermission::All, |
| 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, | 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, |
| 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 312 | 312 | ||
| @@ -465,7 +465,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 465 | 465 | ||
| 466 | MapPhysicalMemory(page_linked_list, addr, end_addr); | 466 | MapPhysicalMemory(page_linked_list, addr, end_addr); |
| 467 | 467 | ||
| 468 | physical_memory_usage += remaining_size; | 468 | mapped_physical_memory_size += remaining_size; |
| 469 | 469 | ||
| 470 | const std::size_t num_pages{size / PageSize}; | 470 | const std::size_t num_pages{size / PageSize}; |
| 471 | block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, | 471 | block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, |
| @@ -507,7 +507,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 507 | 507 | ||
| 508 | auto process{system.Kernel().CurrentProcess()}; | 508 | auto process{system.Kernel().CurrentProcess()}; |
| 509 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); | 509 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); |
| 510 | physical_memory_usage -= mapped_size; | 510 | mapped_physical_memory_size -= mapped_size; |
| 511 | 511 | ||
| 512 | return ResultSuccess; | 512 | return ResultSuccess; |
| 513 | } | 513 | } |
| @@ -554,7 +554,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 554 | KMemoryState src_state{}; | 554 | KMemoryState src_state{}; |
| 555 | CASCADE_CODE(CheckMemoryState( | 555 | CASCADE_CODE(CheckMemoryState( |
| 556 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 556 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 557 | KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite, | 557 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite, |
| 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 559 | 559 | ||
| 560 | if (IsRegionMapped(dst_addr, size)) { | 560 | if (IsRegionMapped(dst_addr, size)) { |
| @@ -593,7 +593,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 593 | KMemoryState src_state{}; | 593 | KMemoryState src_state{}; |
| 594 | CASCADE_CODE(CheckMemoryState( | 594 | CASCADE_CODE(CheckMemoryState( |
| 595 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 595 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 596 | KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None, | 596 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None, |
| 597 | KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 597 | KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 598 | 598 | ||
| 599 | KMemoryPermission dst_perm{}; | 599 | KMemoryPermission dst_perm{}; |
| @@ -784,7 +784,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo | |||
| 784 | CASCADE_CODE(CheckMemoryState( | 784 | CASCADE_CODE(CheckMemoryState( |
| 785 | &state, nullptr, &attribute, addr, size, | 785 | &state, nullptr, &attribute, addr, size, |
| 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, | 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, |
| 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask, | 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, |
| 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, | 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, |
| 789 | KMemoryAttribute::IpcAndDeviceMapped)); | 789 | KMemoryAttribute::IpcAndDeviceMapped)); |
| 790 | 790 | ||
| @@ -806,6 +806,33 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) { | |||
| 806 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 806 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 807 | 807 | ||
| 808 | block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); | 808 | block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); |
| 809 | return ResultSuccess; | ||
| 810 | } | ||
| 811 | |||
| 812 | ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size, | ||
| 813 | Svc::MemoryPermission svc_perm) { | ||
| 814 | const size_t num_pages = size / PageSize; | ||
| 815 | |||
| 816 | // Lock the table. | ||
| 817 | std::lock_guard lock{page_table_lock}; | ||
| 818 | |||
| 819 | // Verify we can change the memory permission. | ||
| 820 | KMemoryState old_state; | ||
| 821 | KMemoryPermission old_perm; | ||
| 822 | R_TRY(this->CheckMemoryState( | ||
| 823 | std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size, | ||
| 824 | KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None, | ||
| 825 | KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None)); | ||
| 826 | |||
| 827 | // Determine new perm. | ||
| 828 | const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); | ||
| 829 | R_SUCCEED_IF(old_perm == new_perm); | ||
| 830 | |||
| 831 | // Perform mapping operation. | ||
| 832 | R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions)); | ||
| 833 | |||
| 834 | // Update the blocks. | ||
| 835 | block_manager->Update(addr, num_pages, old_state, new_perm, KMemoryAttribute::None); | ||
| 809 | 836 | ||
| 810 | return ResultSuccess; | 837 | return ResultSuccess; |
| 811 | } | 838 | } |
| @@ -832,61 +859,125 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryA | |||
| 832 | return ResultSuccess; | 859 | return ResultSuccess; |
| 833 | } | 860 | } |
| 834 | 861 | ||
| 835 | ResultCode KPageTable::SetHeapCapacity(std::size_t new_heap_capacity) { | 862 | ResultCode KPageTable::SetMaxHeapSize(std::size_t size) { |
| 863 | // Lock the table. | ||
| 836 | std::lock_guard lock{page_table_lock}; | 864 | std::lock_guard lock{page_table_lock}; |
| 837 | heap_capacity = new_heap_capacity; | ||
| 838 | return ResultSuccess; | ||
| 839 | } | ||
| 840 | 865 | ||
| 841 | ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) { | 866 | // Only process page tables are allowed to set heap size. |
| 867 | ASSERT(!this->IsKernel()); | ||
| 842 | 868 | ||
| 843 | if (size > heap_region_end - heap_region_start) { | 869 | max_heap_size = size; |
| 844 | return ResultOutOfMemory; | ||
| 845 | } | ||
| 846 | 870 | ||
| 847 | const u64 previous_heap_size{GetHeapSize()}; | 871 | return ResultSuccess; |
| 848 | 872 | } | |
| 849 | UNIMPLEMENTED_IF_MSG(previous_heap_size > size, "Heap shrink is unimplemented"); | ||
| 850 | 873 | ||
| 851 | // Increase the heap size | 874 | ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) { |
| 875 | // Try to perform a reduction in heap, instead of an extension. | ||
| 876 | VAddr cur_address{}; | ||
| 877 | std::size_t allocation_size{}; | ||
| 852 | { | 878 | { |
| 853 | std::lock_guard lock{page_table_lock}; | 879 | // Lock the table. |
| 854 | 880 | std::lock_guard lk(page_table_lock); | |
| 855 | const u64 delta{size - previous_heap_size}; | 881 | |
| 856 | 882 | // Validate that setting heap size is possible at all. | |
| 857 | // Reserve memory for the heap extension. | 883 | R_UNLESS(!is_kernel, ResultOutOfMemory); |
| 858 | KScopedResourceReservation memory_reservation( | 884 | R_UNLESS(size <= static_cast<std::size_t>(heap_region_end - heap_region_start), |
| 859 | system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, | 885 | ResultOutOfMemory); |
| 860 | delta); | 886 | R_UNLESS(size <= max_heap_size, ResultOutOfMemory); |
| 861 | 887 | ||
| 862 | if (!memory_reservation.Succeeded()) { | 888 | if (size < GetHeapSize()) { |
| 863 | LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); | 889 | // The size being requested is less than the current size, so we need to free the end of |
| 864 | return ResultLimitReached; | 890 | // the heap. |
| 891 | |||
| 892 | // Validate memory state. | ||
| 893 | std::size_t num_allocator_blocks; | ||
| 894 | R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), | ||
| 895 | heap_region_start + size, GetHeapSize() - size, | ||
| 896 | KMemoryState::All, KMemoryState::Normal, | ||
| 897 | KMemoryPermission::All, KMemoryPermission::ReadAndWrite, | ||
| 898 | KMemoryAttribute::All, KMemoryAttribute::None)); | ||
| 899 | |||
| 900 | // Unmap the end of the heap. | ||
| 901 | const auto num_pages = (GetHeapSize() - size) / PageSize; | ||
| 902 | R_TRY(Operate(heap_region_start + size, num_pages, KMemoryPermission::None, | ||
| 903 | OperationType::Unmap)); | ||
| 904 | |||
| 905 | // Release the memory from the resource limit. | ||
| 906 | system.Kernel().CurrentProcess()->GetResourceLimit()->Release( | ||
| 907 | LimitableResource::PhysicalMemory, num_pages * PageSize); | ||
| 908 | |||
| 909 | // Apply the memory block update. | ||
| 910 | block_manager->Update(heap_region_start + size, num_pages, KMemoryState::Free, | ||
| 911 | KMemoryPermission::None, KMemoryAttribute::None); | ||
| 912 | |||
| 913 | // Update the current heap end. | ||
| 914 | current_heap_end = heap_region_start + size; | ||
| 915 | |||
| 916 | // Set the output. | ||
| 917 | *out = heap_region_start; | ||
| 918 | return ResultSuccess; | ||
| 919 | } else if (size == GetHeapSize()) { | ||
| 920 | // The size requested is exactly the current size. | ||
| 921 | *out = heap_region_start; | ||
| 922 | return ResultSuccess; | ||
| 923 | } else { | ||
| 924 | // We have to allocate memory. Determine how much to allocate and where while the table | ||
| 925 | // is locked. | ||
| 926 | cur_address = current_heap_end; | ||
| 927 | allocation_size = size - GetHeapSize(); | ||
| 865 | } | 928 | } |
| 929 | } | ||
| 866 | 930 | ||
| 867 | KPageLinkedList page_linked_list; | 931 | // Reserve memory for the heap extension. |
| 868 | const std::size_t num_pages{delta / PageSize}; | 932 | KScopedResourceReservation memory_reservation( |
| 933 | system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, | ||
| 934 | allocation_size); | ||
| 935 | R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); | ||
| 869 | 936 | ||
| 870 | CASCADE_CODE( | 937 | // Allocate pages for the heap extension. |
| 871 | system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); | 938 | KPageLinkedList page_linked_list; |
| 939 | R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize, | ||
| 940 | memory_pool)); | ||
| 872 | 941 | ||
| 873 | if (IsRegionMapped(current_heap_addr, delta)) { | 942 | // Map the pages. |
| 874 | return ResultInvalidCurrentMemory; | 943 | { |
| 944 | // Lock the table. | ||
| 945 | std::lock_guard lk(page_table_lock); | ||
| 946 | |||
| 947 | // Ensure that the heap hasn't changed since we began executing. | ||
| 948 | ASSERT(cur_address == current_heap_end); | ||
| 949 | |||
| 950 | // Check the memory state. | ||
| 951 | std::size_t num_allocator_blocks{}; | ||
| 952 | R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), current_heap_end, | ||
| 953 | allocation_size, KMemoryState::All, KMemoryState::Free, | ||
| 954 | KMemoryPermission::None, KMemoryPermission::None, | ||
| 955 | KMemoryAttribute::None, KMemoryAttribute::None)); | ||
| 956 | |||
| 957 | // Map the pages. | ||
| 958 | const auto num_pages = allocation_size / PageSize; | ||
| 959 | R_TRY(Operate(current_heap_end, num_pages, page_linked_list, OperationType::MapGroup)); | ||
| 960 | |||
| 961 | // Clear all the newly allocated pages. | ||
| 962 | for (std::size_t cur_page = 0; cur_page < num_pages; ++cur_page) { | ||
| 963 | std::memset(system.Memory().GetPointer(current_heap_end + (cur_page * PageSize)), 0, | ||
| 964 | PageSize); | ||
| 875 | } | 965 | } |
| 876 | 966 | ||
| 877 | CASCADE_CODE( | 967 | // We succeeded, so commit our memory reservation. |
| 878 | Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); | ||
| 879 | |||
| 880 | // Succeeded in allocation, commit the resource reservation | ||
| 881 | memory_reservation.Commit(); | 968 | memory_reservation.Commit(); |
| 882 | 969 | ||
| 883 | block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal, | 970 | // Apply the memory block update. |
| 884 | KMemoryPermission::ReadAndWrite); | 971 | block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal, |
| 972 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); | ||
| 885 | 973 | ||
| 886 | current_heap_addr = heap_region_start + size; | 974 | // Update the current heap end. |
| 887 | } | 975 | current_heap_end = heap_region_start + size; |
| 888 | 976 | ||
| 889 | return heap_region_start; | 977 | // Set the output. |
| 978 | *out = heap_region_start; | ||
| 979 | return ResultSuccess; | ||
| 980 | } | ||
| 890 | } | 981 | } |
| 891 | 982 | ||
| 892 | ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, | 983 | ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, |
| @@ -978,7 +1069,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { | |||
| 978 | 1069 | ||
| 979 | if (const ResultCode result{CheckMemoryState( | 1070 | if (const ResultCode result{CheckMemoryState( |
| 980 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | 1071 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, |
| 981 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask, | 1072 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, |
| 982 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; | 1073 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; |
| 983 | result.IsError()) { | 1074 | result.IsError()) { |
| 984 | return result; | 1075 | return result; |
| @@ -1031,9 +1122,8 @@ ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | |||
| 1031 | 1122 | ||
| 1032 | bool KPageTable::IsRegionMapped(VAddr address, u64 size) { | 1123 | bool KPageTable::IsRegionMapped(VAddr address, u64 size) { |
| 1033 | return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, | 1124 | return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, |
| 1034 | KMemoryPermission::Mask, KMemoryPermission::None, | 1125 | KMemoryPermission::All, KMemoryPermission::None, KMemoryAttribute::Mask, |
| 1035 | KMemoryAttribute::Mask, KMemoryAttribute::None, | 1126 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped) |
| 1036 | KMemoryAttribute::IpcAndDeviceMapped) | ||
| 1037 | .IsError(); | 1127 | .IsError(); |
| 1038 | } | 1128 | } |
| 1039 | 1129 | ||
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index d784aa67e..564410dca 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -47,10 +47,11 @@ public: | |||
| 47 | KMemoryInfo QueryInfo(VAddr addr); | 47 | KMemoryInfo QueryInfo(VAddr addr); |
| 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); | 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); |
| 50 | ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm); | ||
| 50 | ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, | 51 | ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, |
| 51 | KMemoryAttribute value); | 52 | KMemoryAttribute value); |
| 52 | ResultCode SetHeapCapacity(std::size_t new_heap_capacity); | 53 | ResultCode SetMaxHeapSize(std::size_t size); |
| 53 | ResultVal<VAddr> SetHeapSize(std::size_t size); | 54 | ResultCode SetHeapSize(VAddr* out, std::size_t size); |
| 54 | ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, | 55 | ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, |
| 55 | bool is_map_only, VAddr region_start, | 56 | bool is_map_only, VAddr region_start, |
| 56 | std::size_t region_num_pages, KMemoryState state, | 57 | std::size_t region_num_pages, KMemoryState state, |
| @@ -182,14 +183,15 @@ public: | |||
| 182 | constexpr VAddr GetAliasCodeRegionSize() const { | 183 | constexpr VAddr GetAliasCodeRegionSize() const { |
| 183 | return alias_code_region_end - alias_code_region_start; | 184 | return alias_code_region_end - alias_code_region_start; |
| 184 | } | 185 | } |
| 186 | size_t GetNormalMemorySize() { | ||
| 187 | std::lock_guard lk(page_table_lock); | ||
| 188 | return GetHeapSize() + mapped_physical_memory_size; | ||
| 189 | } | ||
| 185 | constexpr std::size_t GetAddressSpaceWidth() const { | 190 | constexpr std::size_t GetAddressSpaceWidth() const { |
| 186 | return address_space_width; | 191 | return address_space_width; |
| 187 | } | 192 | } |
| 188 | constexpr std::size_t GetHeapSize() { | 193 | constexpr std::size_t GetHeapSize() const { |
| 189 | return current_heap_addr - heap_region_start; | 194 | return current_heap_end - heap_region_start; |
| 190 | } | ||
| 191 | constexpr std::size_t GetTotalHeapSize() { | ||
| 192 | return GetHeapSize() + physical_memory_usage; | ||
| 193 | } | 195 | } |
| 194 | constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { | 196 | constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { |
| 195 | return address_space_start <= address && address + size - 1 <= address_space_end - 1; | 197 | return address_space_start <= address && address + size - 1 <= address_space_end - 1; |
| @@ -269,10 +271,8 @@ private: | |||
| 269 | VAddr code_region_end{}; | 271 | VAddr code_region_end{}; |
| 270 | VAddr alias_code_region_start{}; | 272 | VAddr alias_code_region_start{}; |
| 271 | VAddr alias_code_region_end{}; | 273 | VAddr alias_code_region_end{}; |
| 272 | VAddr current_heap_addr{}; | ||
| 273 | 274 | ||
| 274 | std::size_t heap_capacity{}; | 275 | std::size_t mapped_physical_memory_size{}; |
| 275 | std::size_t physical_memory_usage{}; | ||
| 276 | std::size_t max_heap_size{}; | 276 | std::size_t max_heap_size{}; |
| 277 | std::size_t max_physical_memory_size{}; | 277 | std::size_t max_physical_memory_size{}; |
| 278 | std::size_t address_space_width{}; | 278 | std::size_t address_space_width{}; |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 90dda40dc..bf98a51e2 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include "core/hle/kernel/k_thread.h" | 28 | #include "core/hle/kernel/k_thread.h" |
| 29 | #include "core/hle/kernel/kernel.h" | 29 | #include "core/hle/kernel/kernel.h" |
| 30 | #include "core/hle/kernel/svc_results.h" | 30 | #include "core/hle/kernel/svc_results.h" |
| 31 | #include "core/hle/lock.h" | ||
| 32 | #include "core/memory.h" | 31 | #include "core/memory.h" |
| 33 | 32 | ||
| 34 | namespace Kernel { | 33 | namespace Kernel { |
| @@ -173,7 +172,7 @@ void KProcess::DecrementThreadCount() { | |||
| 173 | 172 | ||
| 174 | u64 KProcess::GetTotalPhysicalMemoryAvailable() const { | 173 | u64 KProcess::GetTotalPhysicalMemoryAvailable() const { |
| 175 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + | 174 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + |
| 176 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + | 175 | page_table->GetNormalMemorySize() + GetSystemResourceSize() + image_size + |
| 177 | main_thread_stack_size}; | 176 | main_thread_stack_size}; |
| 178 | if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); | 177 | if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application); |
| 179 | capacity != pool_size) { | 178 | capacity != pool_size) { |
| @@ -190,7 +189,7 @@ u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { | |||
| 190 | } | 189 | } |
| 191 | 190 | ||
| 192 | u64 KProcess::GetTotalPhysicalMemoryUsed() const { | 191 | u64 KProcess::GetTotalPhysicalMemoryUsed() const { |
| 193 | return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() + | 192 | return image_size + main_thread_stack_size + page_table->GetNormalMemorySize() + |
| 194 | GetSystemResourceSize(); | 193 | GetSystemResourceSize(); |
| 195 | } | 194 | } |
| 196 | 195 | ||
| @@ -221,30 +220,28 @@ bool KProcess::ReleaseUserException(KThread* thread) { | |||
| 221 | } | 220 | } |
| 222 | } | 221 | } |
| 223 | 222 | ||
| 224 | void KProcess::PinCurrentThread() { | 223 | void KProcess::PinCurrentThread(s32 core_id) { |
| 225 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 224 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 226 | 225 | ||
| 227 | // Get the current thread. | 226 | // Get the current thread. |
| 228 | const s32 core_id = GetCurrentCoreId(kernel); | 227 | KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread(); |
| 229 | KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||
| 230 | 228 | ||
| 231 | // If the thread isn't terminated, pin it. | 229 | // If the thread isn't terminated, pin it. |
| 232 | if (!cur_thread->IsTerminationRequested()) { | 230 | if (!cur_thread->IsTerminationRequested()) { |
| 233 | // Pin it. | 231 | // Pin it. |
| 234 | PinThread(core_id, cur_thread); | 232 | PinThread(core_id, cur_thread); |
| 235 | cur_thread->Pin(); | 233 | cur_thread->Pin(core_id); |
| 236 | 234 | ||
| 237 | // An update is needed. | 235 | // An update is needed. |
| 238 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 236 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 239 | } | 237 | } |
| 240 | } | 238 | } |
| 241 | 239 | ||
| 242 | void KProcess::UnpinCurrentThread() { | 240 | void KProcess::UnpinCurrentThread(s32 core_id) { |
| 243 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 241 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 244 | 242 | ||
| 245 | // Get the current thread. | 243 | // Get the current thread. |
| 246 | const s32 core_id = GetCurrentCoreId(kernel); | 244 | KThread* cur_thread = kernel.Scheduler(static_cast<std::size_t>(core_id)).GetCurrentThread(); |
| 247 | KThread* cur_thread = GetCurrentThreadPointer(kernel); | ||
| 248 | 245 | ||
| 249 | // Unpin it. | 246 | // Unpin it. |
| 250 | cur_thread->Unpin(); | 247 | cur_thread->Unpin(); |
| @@ -411,8 +408,8 @@ void KProcess::Run(s32 main_thread_priority, u64 stack_size) { | |||
| 411 | resource_limit->Reserve(LimitableResource::Threads, 1); | 408 | resource_limit->Reserve(LimitableResource::Threads, 1); |
| 412 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); | 409 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); |
| 413 | 410 | ||
| 414 | const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; | 411 | const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)}; |
| 415 | ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); | 412 | ASSERT(!page_table->SetMaxHeapSize(heap_capacity).IsError()); |
| 416 | 413 | ||
| 417 | ChangeStatus(ProcessStatus::Running); | 414 | ChangeStatus(ProcessStatus::Running); |
| 418 | 415 | ||
| @@ -543,7 +540,6 @@ void KProcess::FreeTLSRegion(VAddr tls_address) { | |||
| 543 | } | 540 | } |
| 544 | 541 | ||
| 545 | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { | 542 | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { |
| 546 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 547 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, | 543 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, |
| 548 | KMemoryPermission permission) { | 544 | KMemoryPermission permission) { |
| 549 | page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); | 545 | page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index cb93c7e24..e7c8b5838 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -345,8 +345,8 @@ public: | |||
| 345 | 345 | ||
| 346 | bool IsSignaled() const override; | 346 | bool IsSignaled() const override; |
| 347 | 347 | ||
| 348 | void PinCurrentThread(); | 348 | void PinCurrentThread(s32 core_id); |
| 349 | void UnpinCurrentThread(); | 349 | void UnpinCurrentThread(s32 core_id); |
| 350 | void UnpinThread(KThread* thread); | 350 | void UnpinThread(KThread* thread); |
| 351 | 351 | ||
| 352 | KLightLock& GetStateLock() { | 352 | KLightLock& GetStateLock() { |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 277201de4..31cec990e 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/core.h" | 15 | #include "core/core.h" |
| 16 | #include "core/core_timing.h" | 16 | #include "core/core_timing.h" |
| 17 | #include "core/cpu_manager.h" | 17 | #include "core/cpu_manager.h" |
| 18 | #include "core/hle/kernel/k_interrupt_manager.h" | ||
| 18 | #include "core/hle/kernel/k_process.h" | 19 | #include "core/hle/kernel/k_process.h" |
| 19 | #include "core/hle/kernel/k_scheduler.h" | 20 | #include "core/hle/kernel/k_scheduler.h" |
| 20 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 21 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| @@ -53,6 +54,13 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul | |||
| 53 | } | 54 | } |
| 54 | cores_pending_reschedule &= ~(1ULL << core); | 55 | cores_pending_reschedule &= ~(1ULL << core); |
| 55 | } | 56 | } |
| 57 | |||
| 58 | for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; ++core_id) { | ||
| 59 | if (kernel.PhysicalCore(core_id).IsInterrupted()) { | ||
| 60 | KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_id)); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 56 | if (must_context_switch) { | 64 | if (must_context_switch) { |
| 57 | auto core_scheduler = kernel.CurrentScheduler(); | 65 | auto core_scheduler = kernel.CurrentScheduler(); |
| 58 | kernel.ExitSVCProfile(); | 66 | kernel.ExitSVCProfile(); |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 752592e2e..71e029a3f 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <atomic> | ||
| 6 | #include <cinttypes> | 7 | #include <cinttypes> |
| 7 | #include <optional> | 8 | #include <optional> |
| 8 | #include <vector> | 9 | #include <vector> |
| @@ -26,12 +27,14 @@ | |||
| 26 | #include "core/hle/kernel/k_resource_limit.h" | 27 | #include "core/hle/kernel/k_resource_limit.h" |
| 27 | #include "core/hle/kernel/k_scheduler.h" | 28 | #include "core/hle/kernel/k_scheduler.h" |
| 28 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 29 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 30 | #include "core/hle/kernel/k_system_control.h" | ||
| 29 | #include "core/hle/kernel/k_thread.h" | 31 | #include "core/hle/kernel/k_thread.h" |
| 30 | #include "core/hle/kernel/k_thread_queue.h" | 32 | #include "core/hle/kernel/k_thread_queue.h" |
| 31 | #include "core/hle/kernel/kernel.h" | 33 | #include "core/hle/kernel/kernel.h" |
| 32 | #include "core/hle/kernel/svc_results.h" | 34 | #include "core/hle/kernel/svc_results.h" |
| 33 | #include "core/hle/kernel/time_manager.h" | 35 | #include "core/hle/kernel/time_manager.h" |
| 34 | #include "core/hle/result.h" | 36 | #include "core/hle/result.h" |
| 37 | #include "core/memory.h" | ||
| 35 | 38 | ||
| 36 | #ifdef ARCHITECTURE_x86_64 | 39 | #ifdef ARCHITECTURE_x86_64 |
| 37 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | 40 | #include "core/arm/dynarmic/arm_dynarmic_32.h" |
| @@ -50,6 +53,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, | |||
| 50 | VAddr entry_point, u64 arg) { | 53 | VAddr entry_point, u64 arg) { |
| 51 | context = {}; | 54 | context = {}; |
| 52 | context.cpu_registers[0] = arg; | 55 | context.cpu_registers[0] = arg; |
| 56 | context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1; | ||
| 53 | context.pc = entry_point; | 57 | context.pc = entry_point; |
| 54 | context.sp = stack_top; | 58 | context.sp = stack_top; |
| 55 | // TODO(merry): Perform a hardware test to determine the below value. | 59 | // TODO(merry): Perform a hardware test to determine the below value. |
| @@ -61,6 +65,13 @@ namespace Kernel { | |||
| 61 | 65 | ||
| 62 | namespace { | 66 | namespace { |
| 63 | 67 | ||
| 68 | struct ThreadLocalRegion { | ||
| 69 | static constexpr std::size_t MessageBufferSize = 0x100; | ||
| 70 | std::array<u32, MessageBufferSize / sizeof(u32)> message_buffer; | ||
| 71 | std::atomic_uint16_t disable_count; | ||
| 72 | std::atomic_uint16_t interrupt_flag; | ||
| 73 | }; | ||
| 74 | |||
| 64 | class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { | 75 | class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { |
| 65 | public: | 76 | public: |
| 66 | explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) | 77 | explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) |
| @@ -344,7 +355,7 @@ void KThread::StartTermination() { | |||
| 344 | if (parent != nullptr) { | 355 | if (parent != nullptr) { |
| 345 | parent->ReleaseUserException(this); | 356 | parent->ReleaseUserException(this); |
| 346 | if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) { | 357 | if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) { |
| 347 | parent->UnpinCurrentThread(); | 358 | parent->UnpinCurrentThread(core_id); |
| 348 | } | 359 | } |
| 349 | } | 360 | } |
| 350 | 361 | ||
| @@ -370,7 +381,7 @@ void KThread::StartTermination() { | |||
| 370 | this->Close(); | 381 | this->Close(); |
| 371 | } | 382 | } |
| 372 | 383 | ||
| 373 | void KThread::Pin() { | 384 | void KThread::Pin(s32 current_core) { |
| 374 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 385 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 375 | 386 | ||
| 376 | // Set ourselves as pinned. | 387 | // Set ourselves as pinned. |
| @@ -387,7 +398,6 @@ void KThread::Pin() { | |||
| 387 | 398 | ||
| 388 | // Bind ourselves to this core. | 399 | // Bind ourselves to this core. |
| 389 | const s32 active_core = GetActiveCore(); | 400 | const s32 active_core = GetActiveCore(); |
| 390 | const s32 current_core = GetCurrentCoreId(kernel); | ||
| 391 | 401 | ||
| 392 | SetActiveCore(current_core); | 402 | SetActiveCore(current_core); |
| 393 | physical_ideal_core_id = current_core; | 403 | physical_ideal_core_id = current_core; |
| @@ -480,6 +490,36 @@ void KThread::Unpin() { | |||
| 480 | } | 490 | } |
| 481 | } | 491 | } |
| 482 | 492 | ||
| 493 | u16 KThread::GetUserDisableCount() const { | ||
| 494 | if (!IsUserThread()) { | ||
| 495 | // We only emulate TLS for user threads | ||
| 496 | return {}; | ||
| 497 | } | ||
| 498 | |||
| 499 | auto& memory = kernel.System().Memory(); | ||
| 500 | return memory.Read16(tls_address + offsetof(ThreadLocalRegion, disable_count)); | ||
| 501 | } | ||
| 502 | |||
| 503 | void KThread::SetInterruptFlag() { | ||
| 504 | if (!IsUserThread()) { | ||
| 505 | // We only emulate TLS for user threads | ||
| 506 | return; | ||
| 507 | } | ||
| 508 | |||
| 509 | auto& memory = kernel.System().Memory(); | ||
| 510 | memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1); | ||
| 511 | } | ||
| 512 | |||
| 513 | void KThread::ClearInterruptFlag() { | ||
| 514 | if (!IsUserThread()) { | ||
| 515 | // We only emulate TLS for user threads | ||
| 516 | return; | ||
| 517 | } | ||
| 518 | |||
| 519 | auto& memory = kernel.System().Memory(); | ||
| 520 | memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0); | ||
| 521 | } | ||
| 522 | |||
| 483 | ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) { | 523 | ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) { |
| 484 | KScopedSchedulerLock sl{kernel}; | 524 | KScopedSchedulerLock sl{kernel}; |
| 485 | 525 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index c8a08bd71..83dfde69b 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -307,6 +307,10 @@ public: | |||
| 307 | return parent != nullptr; | 307 | return parent != nullptr; |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | u16 GetUserDisableCount() const; | ||
| 311 | void SetInterruptFlag(); | ||
| 312 | void ClearInterruptFlag(); | ||
| 313 | |||
| 310 | [[nodiscard]] KThread* GetLockOwner() const { | 314 | [[nodiscard]] KThread* GetLockOwner() const { |
| 311 | return lock_owner; | 315 | return lock_owner; |
| 312 | } | 316 | } |
| @@ -490,7 +494,7 @@ public: | |||
| 490 | this->GetStackParameters().disable_count--; | 494 | this->GetStackParameters().disable_count--; |
| 491 | } | 495 | } |
| 492 | 496 | ||
| 493 | void Pin(); | 497 | void Pin(s32 current_core); |
| 494 | 498 | ||
| 495 | void Unpin(); | 499 | void Unpin(); |
| 496 | 500 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 2e4e4cb1c..1225e1fba 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -182,7 +182,10 @@ struct KernelCore::Impl { | |||
| 182 | // Shutdown all processes. | 182 | // Shutdown all processes. |
| 183 | if (current_process) { | 183 | if (current_process) { |
| 184 | current_process->Finalize(); | 184 | current_process->Finalize(); |
| 185 | current_process->Close(); | 185 | // current_process->Close(); |
| 186 | // TODO: The current process should be destroyed based on accurate ref counting after | ||
| 187 | // calling Close(). Adding a manual Destroy() call instead to avoid a memory leak. | ||
| 188 | current_process->Destroy(); | ||
| 186 | current_process = nullptr; | 189 | current_process = nullptr; |
| 187 | } | 190 | } |
| 188 | 191 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a9f7438ea..250ef9042 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -41,7 +41,6 @@ | |||
| 41 | #include "core/hle/kernel/svc_results.h" | 41 | #include "core/hle/kernel/svc_results.h" |
| 42 | #include "core/hle/kernel/svc_types.h" | 42 | #include "core/hle/kernel/svc_types.h" |
| 43 | #include "core/hle/kernel/svc_wrap.h" | 43 | #include "core/hle/kernel/svc_wrap.h" |
| 44 | #include "core/hle/lock.h" | ||
| 45 | #include "core/hle/result.h" | 44 | #include "core/hle/result.h" |
| 46 | #include "core/memory.h" | 45 | #include "core/memory.h" |
| 47 | #include "core/reporter.h" | 46 | #include "core/reporter.h" |
| @@ -136,25 +135,15 @@ enum class ResourceLimitValueType { | |||
| 136 | } // Anonymous namespace | 135 | } // Anonymous namespace |
| 137 | 136 | ||
| 138 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 137 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 139 | static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) { | 138 | static ResultCode SetHeapSize(Core::System& system, VAddr* out_address, u64 size) { |
| 140 | std::lock_guard lock{HLE::g_hle_lock}; | 139 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); |
| 141 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | ||
| 142 | |||
| 143 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. | ||
| 144 | if ((heap_size % 0x200000) != 0) { | ||
| 145 | LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}", | ||
| 146 | heap_size); | ||
| 147 | return ResultInvalidSize; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (heap_size >= 0x200000000) { | ||
| 151 | LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size); | ||
| 152 | return ResultInvalidSize; | ||
| 153 | } | ||
| 154 | 140 | ||
| 155 | auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; | 141 | // Validate size. |
| 142 | R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); | ||
| 143 | R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); | ||
| 156 | 144 | ||
| 157 | CASCADE_RESULT(*heap_addr, page_table.SetHeapSize(heap_size)); | 145 | // Set the heap size. |
| 146 | R_TRY(system.Kernel().CurrentProcess()->PageTable().SetHeapSize(out_address, size)); | ||
| 158 | 147 | ||
| 159 | return ResultSuccess; | 148 | return ResultSuccess; |
| 160 | } | 149 | } |
| @@ -166,9 +155,38 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s | |||
| 166 | return result; | 155 | return result; |
| 167 | } | 156 | } |
| 168 | 157 | ||
| 158 | constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) { | ||
| 159 | switch (perm) { | ||
| 160 | case MemoryPermission::None: | ||
| 161 | case MemoryPermission::Read: | ||
| 162 | case MemoryPermission::ReadWrite: | ||
| 163 | return true; | ||
| 164 | default: | ||
| 165 | return false; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, | ||
| 170 | MemoryPermission perm) { | ||
| 171 | // Validate address / size. | ||
| 172 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 173 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 174 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 175 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 176 | |||
| 177 | // Validate the permission. | ||
| 178 | R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 179 | |||
| 180 | // Validate that the region is in range for the current process. | ||
| 181 | auto& page_table = system.Kernel().CurrentProcess()->PageTable(); | ||
| 182 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | ||
| 183 | |||
| 184 | // Set the memory attribute. | ||
| 185 | return page_table.SetMemoryPermission(address, size, perm); | ||
| 186 | } | ||
| 187 | |||
| 169 | static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, | 188 | static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, |
| 170 | u32 attribute) { | 189 | u32 attribute) { |
| 171 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 172 | LOG_DEBUG(Kernel_SVC, | 190 | LOG_DEBUG(Kernel_SVC, |
| 173 | "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, | 191 | "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, |
| 174 | size, mask, attribute); | 192 | size, mask, attribute); |
| @@ -212,7 +230,6 @@ static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 si | |||
| 212 | 230 | ||
| 213 | /// Maps a memory range into a different range. | 231 | /// Maps a memory range into a different range. |
| 214 | static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { | 232 | static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { |
| 215 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 216 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 233 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 217 | src_addr, size); | 234 | src_addr, size); |
| 218 | 235 | ||
| @@ -232,7 +249,6 @@ static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, | |||
| 232 | 249 | ||
| 233 | /// Unmaps a region that was previously mapped with svcMapMemory | 250 | /// Unmaps a region that was previously mapped with svcMapMemory |
| 234 | static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { | 251 | static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { |
| 235 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 236 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, | 252 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, |
| 237 | src_addr, size); | 253 | src_addr, size); |
| 238 | 254 | ||
| @@ -642,7 +658,6 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) { | |||
| 642 | /// Gets system/memory information for the current process | 658 | /// Gets system/memory information for the current process |
| 643 | static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, | 659 | static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, |
| 644 | u64 info_sub_id) { | 660 | u64 info_sub_id) { |
| 645 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 646 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, | 661 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, |
| 647 | info_sub_id, handle); | 662 | info_sub_id, handle); |
| 648 | 663 | ||
| @@ -886,22 +901,17 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle | |||
| 886 | return ResultSuccess; | 901 | return ResultSuccess; |
| 887 | } | 902 | } |
| 888 | case GetInfoType::IdleTickCount: { | 903 | case GetInfoType::IdleTickCount: { |
| 889 | if (handle == 0) { | 904 | // Verify the input handle is invalid. |
| 890 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", | 905 | R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); |
| 891 | static_cast<Handle>(handle)); | ||
| 892 | return ResultInvalidHandle; | ||
| 893 | } | ||
| 894 | |||
| 895 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && | ||
| 896 | info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) { | ||
| 897 | LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id); | ||
| 898 | return ResultInvalidCombination; | ||
| 899 | } | ||
| 900 | 906 | ||
| 901 | const auto& scheduler = *system.Kernel().CurrentScheduler(); | 907 | // Verify the requested core is valid. |
| 902 | const auto* const idle_thread = scheduler.GetIdleThread(); | 908 | const bool core_valid = |
| 909 | (info_sub_id == static_cast<u64>(-1ULL)) || | ||
| 910 | (info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex())); | ||
| 911 | R_UNLESS(core_valid, ResultInvalidCombination); | ||
| 903 | 912 | ||
| 904 | *result = idle_thread->GetCpuTime(); | 913 | // Get the idle tick count. |
| 914 | *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime(); | ||
| 905 | return ResultSuccess; | 915 | return ResultSuccess; |
| 906 | } | 916 | } |
| 907 | default: | 917 | default: |
| @@ -924,7 +934,6 @@ static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_h | |||
| 924 | 934 | ||
| 925 | /// Maps memory at a desired address | 935 | /// Maps memory at a desired address |
| 926 | static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { | 936 | static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { |
| 927 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 928 | LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); | 937 | LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); |
| 929 | 938 | ||
| 930 | if (!Common::Is4KBAligned(addr)) { | 939 | if (!Common::Is4KBAligned(addr)) { |
| @@ -978,7 +987,6 @@ static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) | |||
| 978 | 987 | ||
| 979 | /// Unmaps memory previously mapped via MapPhysicalMemory | 988 | /// Unmaps memory previously mapped via MapPhysicalMemory |
| 980 | static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { | 989 | static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { |
| 981 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 982 | LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); | 990 | LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); |
| 983 | 991 | ||
| 984 | if (!Common::Is4KBAligned(addr)) { | 992 | if (!Common::Is4KBAligned(addr)) { |
| @@ -1520,7 +1528,6 @@ static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_han | |||
| 1520 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, | 1528 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, |
| 1521 | VAddr page_info_address, Handle process_handle, | 1529 | VAddr page_info_address, Handle process_handle, |
| 1522 | VAddr address) { | 1530 | VAddr address) { |
| 1523 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 1524 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); | 1531 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); |
| 1525 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 1532 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); |
| 1526 | KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); | 1533 | KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle); |
| @@ -2020,6 +2027,25 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign | |||
| 2020 | count); | 2027 | count); |
| 2021 | } | 2028 | } |
| 2022 | 2029 | ||
| 2030 | static void SynchronizePreemptionState(Core::System& system) { | ||
| 2031 | auto& kernel = system.Kernel(); | ||
| 2032 | |||
| 2033 | // Lock the scheduler. | ||
| 2034 | KScopedSchedulerLock sl{kernel}; | ||
| 2035 | |||
| 2036 | // If the current thread is pinned, unpin it. | ||
| 2037 | KProcess* cur_process = system.Kernel().CurrentProcess(); | ||
| 2038 | const auto core_id = GetCurrentCoreId(kernel); | ||
| 2039 | |||
| 2040 | if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) { | ||
| 2041 | // Clear the current thread's interrupt flag. | ||
| 2042 | GetCurrentThread(kernel).ClearInterruptFlag(); | ||
| 2043 | |||
| 2044 | // Unpin the current thread. | ||
| 2045 | cur_process->UnpinCurrentThread(core_id); | ||
| 2046 | } | ||
| 2047 | } | ||
| 2048 | |||
| 2023 | static ResultCode SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type, | 2049 | static ResultCode SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type, |
| 2024 | s32 value, s32 count) { | 2050 | s32 value, s32 count) { |
| 2025 | return SignalToAddress(system, address, signal_type, value, count); | 2051 | return SignalToAddress(system, address, signal_type, value, count); |
| @@ -2738,7 +2764,7 @@ static const FunctionDef SVC_Table_32[] = { | |||
| 2738 | static const FunctionDef SVC_Table_64[] = { | 2764 | static const FunctionDef SVC_Table_64[] = { |
| 2739 | {0x00, nullptr, "Unknown"}, | 2765 | {0x00, nullptr, "Unknown"}, |
| 2740 | {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, | 2766 | {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, |
| 2741 | {0x02, nullptr, "SetMemoryPermission"}, | 2767 | {0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"}, |
| 2742 | {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, | 2768 | {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, |
| 2743 | {0x04, SvcWrap64<MapMemory>, "MapMemory"}, | 2769 | {0x04, SvcWrap64<MapMemory>, "MapMemory"}, |
| 2744 | {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"}, | 2770 | {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"}, |
| @@ -2790,7 +2816,7 @@ static const FunctionDef SVC_Table_64[] = { | |||
| 2790 | {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"}, | 2816 | {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"}, |
| 2791 | {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"}, | 2817 | {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"}, |
| 2792 | {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"}, | 2818 | {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"}, |
| 2793 | {0x36, nullptr, "SynchronizePreemptionState"}, | 2819 | {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"}, |
| 2794 | {0x37, nullptr, "Unknown"}, | 2820 | {0x37, nullptr, "Unknown"}, |
| 2795 | {0x38, nullptr, "Unknown"}, | 2821 | {0x38, nullptr, "Unknown"}, |
| 2796 | {0x39, nullptr, "Unknown"}, | 2822 | {0x39, nullptr, "Unknown"}, |
diff --git a/src/core/hle/kernel/svc_common.h b/src/core/hle/kernel/svc_common.h index 60ea2c405..25de6e437 100644 --- a/src/core/hle/kernel/svc_common.h +++ b/src/core/hle/kernel/svc_common.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/literals.h" | ||
| 8 | 9 | ||
| 9 | namespace Kernel { | 10 | namespace Kernel { |
| 10 | using Handle = u32; | 11 | using Handle = u32; |
| @@ -12,9 +13,13 @@ using Handle = u32; | |||
| 12 | 13 | ||
| 13 | namespace Kernel::Svc { | 14 | namespace Kernel::Svc { |
| 14 | 15 | ||
| 16 | using namespace Common::Literals; | ||
| 17 | |||
| 15 | constexpr s32 ArgumentHandleCountMax = 0x40; | 18 | constexpr s32 ArgumentHandleCountMax = 0x40; |
| 16 | constexpr u32 HandleWaitMask{1u << 30}; | 19 | constexpr u32 HandleWaitMask{1u << 30}; |
| 17 | 20 | ||
| 21 | constexpr inline std::size_t HeapSizeAlignment = 2_MiB; | ||
| 22 | |||
| 18 | constexpr inline Handle InvalidHandle = Handle(0); | 23 | constexpr inline Handle InvalidHandle = Handle(0); |
| 19 | 24 | ||
| 20 | enum PseudoHandle : Handle { | 25 | enum PseudoHandle : Handle { |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 86255fe6d..a60adfcab 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -249,6 +249,14 @@ void SvcWrap64(Core::System& system) { | |||
| 249 | func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); | 249 | func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | // Used by SetMemoryPermission | ||
| 253 | template <ResultCode func(Core::System&, u64, u64, Svc::MemoryPermission)> | ||
| 254 | void SvcWrap64(Core::System& system) { | ||
| 255 | FuncReturn(system, func(system, Param(system, 0), Param(system, 1), | ||
| 256 | static_cast<Svc::MemoryPermission>(Param(system, 2))) | ||
| 257 | .raw); | ||
| 258 | } | ||
| 259 | |||
| 252 | // Used by MapSharedMemory | 260 | // Used by MapSharedMemory |
| 253 | template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> | 261 | template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)> |
| 254 | void SvcWrap64(Core::System& system) { | 262 | void SvcWrap64(Core::System& system) { |
diff --git a/src/core/hle/lock.cpp b/src/core/hle/lock.cpp deleted file mode 100644 index be4bfce3b..000000000 --- a/src/core/hle/lock.cpp +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <core/hle/lock.h> | ||
| 6 | |||
| 7 | namespace HLE { | ||
| 8 | std::recursive_mutex g_hle_lock; | ||
| 9 | } | ||
diff --git a/src/core/hle/lock.h b/src/core/hle/lock.h deleted file mode 100644 index 5c99fe996..000000000 --- a/src/core/hle/lock.h +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <mutex> | ||
| 8 | |||
| 9 | namespace HLE { | ||
| 10 | /* | ||
| 11 | * Synchronizes access to the internal HLE kernel structures, it is acquired when a guest | ||
| 12 | * application thread performs a syscall. It should be acquired by any host threads that read or | ||
| 13 | * modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or writes | ||
| 14 | * to the emulated memory is not protected by this mutex, and should be avoided in any threads other | ||
| 15 | * than the CPU thread. | ||
| 16 | */ | ||
| 17 | extern std::recursive_mutex g_hle_lock; | ||
| 18 | } // namespace HLE | ||
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp index 4c7d3bb6e..ee49edbb9 100644 --- a/src/core/hle/service/bcat/backend/backend.cpp +++ b/src/core/hle/service/bcat/backend/backend.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/hle/kernel/k_event.h" | 8 | #include "core/hle/kernel/k_event.h" |
| 9 | #include "core/hle/lock.h" | ||
| 10 | #include "core/hle/service/bcat/backend/backend.h" | 9 | #include "core/hle/service/bcat/backend/backend.h" |
| 11 | 10 | ||
| 12 | namespace Service::BCAT { | 11 | namespace Service::BCAT { |
| @@ -29,10 +28,6 @@ DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { | |||
| 29 | return impl; | 28 | return impl; |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | void ProgressServiceBackend::SetNeedHLELock(bool need) { | ||
| 33 | need_hle_lock = need; | ||
| 34 | } | ||
| 35 | |||
| 36 | void ProgressServiceBackend::SetTotalSize(u64 size) { | 31 | void ProgressServiceBackend::SetTotalSize(u64 size) { |
| 37 | impl.total_bytes = size; | 32 | impl.total_bytes = size; |
| 38 | SignalUpdate(); | 33 | SignalUpdate(); |
| @@ -88,12 +83,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) { | |||
| 88 | } | 83 | } |
| 89 | 84 | ||
| 90 | void ProgressServiceBackend::SignalUpdate() { | 85 | void ProgressServiceBackend::SignalUpdate() { |
| 91 | if (need_hle_lock) { | 86 | update_event->GetWritableEvent().Signal(); |
| 92 | std::lock_guard lock(HLE::g_hle_lock); | ||
| 93 | update_event->GetWritableEvent().Signal(); | ||
| 94 | } else { | ||
| 95 | update_event->GetWritableEvent().Signal(); | ||
| 96 | } | ||
| 97 | } | 87 | } |
| 98 | 88 | ||
| 99 | Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {} | 89 | Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {} |
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h index 59c6d4740..63833c927 100644 --- a/src/core/hle/service/bcat/backend/backend.h +++ b/src/core/hle/service/bcat/backend/backend.h | |||
| @@ -71,10 +71,6 @@ class ProgressServiceBackend { | |||
| 71 | public: | 71 | public: |
| 72 | ~ProgressServiceBackend(); | 72 | ~ProgressServiceBackend(); |
| 73 | 73 | ||
| 74 | // Clients should call this with true if any of the functions are going to be called from a | ||
| 75 | // non-HLE thread and this class need to lock the hle mutex. (default is false) | ||
| 76 | void SetNeedHLELock(bool need); | ||
| 77 | |||
| 78 | // Sets the number of bytes total in the entire download. | 74 | // Sets the number of bytes total in the entire download. |
| 79 | void SetTotalSize(u64 size); | 75 | void SetTotalSize(u64 size); |
| 80 | 76 | ||
| @@ -109,7 +105,6 @@ private: | |||
| 109 | 105 | ||
| 110 | DeliveryCacheProgressImpl impl{}; | 106 | DeliveryCacheProgressImpl impl{}; |
| 111 | Kernel::KEvent* update_event; | 107 | Kernel::KEvent* update_event; |
| 112 | bool need_hle_lock = false; | ||
| 113 | }; | 108 | }; |
| 114 | 109 | ||
| 115 | // A class representing an abstract backend for BCAT functionality. | 110 | // A class representing an abstract backend for BCAT functionality. |
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index f0f3105dc..a727b3582 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp | |||
| @@ -33,15 +33,14 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti | |||
| 33 | const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; | 33 | const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; |
| 34 | next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; | 34 | next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; |
| 35 | 35 | ||
| 36 | // Try to read sixaxis sensor states | ||
| 37 | const auto motion_status = console->GetMotion(); | 36 | const auto motion_status = console->GetMotion(); |
| 37 | last_global_timestamp = core_timing.GetGlobalTimeNs().count(); | ||
| 38 | 38 | ||
| 39 | console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; | 39 | // This value increments every time the switch goes to sleep |
| 40 | 40 | next_seven_sixaxis_state.unknown = 1; | |
| 41 | next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp; | ||
| 41 | next_seven_sixaxis_state.accel = motion_status.accel; | 42 | next_seven_sixaxis_state.accel = motion_status.accel; |
| 42 | // Zero gyro values as they just mess up with the camera | 43 | next_seven_sixaxis_state.gyro = motion_status.gyro; |
| 43 | // Note: Probably a correct sensivity setting must be set | ||
| 44 | next_seven_sixaxis_state.gyro = {}; | ||
| 45 | next_seven_sixaxis_state.quaternion = { | 44 | next_seven_sixaxis_state.quaternion = { |
| 46 | { | 45 | { |
| 47 | motion_status.quaternion.xyz.y, | 46 | motion_status.quaternion.xyz.y, |
| @@ -52,9 +51,9 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti | |||
| 52 | }; | 51 | }; |
| 53 | 52 | ||
| 54 | console_six_axis.sampling_number++; | 53 | console_six_axis.sampling_number++; |
| 55 | // TODO(German77): Find the purpose of those values | 54 | console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; |
| 56 | console_six_axis.verticalization_error = 0.0f; | 55 | console_six_axis.verticalization_error = motion_status.verticalization_error; |
| 57 | console_six_axis.gyro_bias = {0.0f, 0.0f, 0.0f}; | 56 | console_six_axis.gyro_bias = motion_status.gyro_bias; |
| 58 | 57 | ||
| 59 | // Update console six axis shared memory | 58 | // Update console six axis shared memory |
| 60 | std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); | 59 | std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); |
| @@ -69,7 +68,6 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { | |||
| 69 | } | 68 | } |
| 70 | 69 | ||
| 71 | void Controller_ConsoleSixAxis::ResetTimestamp() { | 70 | void Controller_ConsoleSixAxis::ResetTimestamp() { |
| 72 | seven_sixaxis_lifo.buffer_count = 0; | 71 | last_saved_timestamp = last_global_timestamp; |
| 73 | seven_sixaxis_lifo.buffer_tail = 0; | ||
| 74 | } | 72 | } |
| 75 | } // namespace Service::HID | 73 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 279241858..26d153f0c 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h | |||
| @@ -39,8 +39,9 @@ public: | |||
| 39 | 39 | ||
| 40 | private: | 40 | private: |
| 41 | struct SevenSixAxisState { | 41 | struct SevenSixAxisState { |
| 42 | INSERT_PADDING_WORDS(4); // unused | 42 | INSERT_PADDING_WORDS(2); // unused |
| 43 | s64 sampling_number{}; | 43 | u64 timestamp{}; |
| 44 | u64 sampling_number{}; | ||
| 44 | u64 unknown{}; | 45 | u64 unknown{}; |
| 45 | Common::Vec3f accel{}; | 46 | Common::Vec3f accel{}; |
| 46 | Common::Vec3f gyro{}; | 47 | Common::Vec3f gyro{}; |
| @@ -52,9 +53,10 @@ private: | |||
| 52 | struct ConsoleSharedMemory { | 53 | struct ConsoleSharedMemory { |
| 53 | u64 sampling_number{}; | 54 | u64 sampling_number{}; |
| 54 | bool is_seven_six_axis_sensor_at_rest{}; | 55 | bool is_seven_six_axis_sensor_at_rest{}; |
| 55 | INSERT_PADDING_BYTES(4); // padding | 56 | INSERT_PADDING_BYTES(3); // padding |
| 56 | f32 verticalization_error{}; | 57 | f32 verticalization_error{}; |
| 57 | Common::Vec3f gyro_bias{}; | 58 | Common::Vec3f gyro_bias{}; |
| 59 | INSERT_PADDING_BYTES(4); // padding | ||
| 58 | }; | 60 | }; |
| 59 | static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); | 61 | static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); |
| 60 | 62 | ||
| @@ -64,6 +66,8 @@ private: | |||
| 64 | Core::HID::EmulatedConsole* console; | 66 | Core::HID::EmulatedConsole* console; |
| 65 | u8* transfer_memory = nullptr; | 67 | u8* transfer_memory = nullptr; |
| 66 | bool is_transfer_memory_set = false; | 68 | bool is_transfer_memory_set = false; |
| 69 | u64 last_saved_timestamp{}; | ||
| 70 | u64 last_global_timestamp{}; | ||
| 67 | ConsoleSharedMemory console_six_axis{}; | 71 | ConsoleSharedMemory console_six_axis{}; |
| 68 | SevenSixAxisState next_seven_sixaxis_state{}; | 72 | SevenSixAxisState next_seven_sixaxis_state{}; |
| 69 | }; | 73 | }; |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 2705e9dcb..e5c951e06 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -66,9 +66,9 @@ Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, | |||
| 66 | auto& controller = controller_data[i]; | 66 | auto& controller = controller_data[i]; |
| 67 | controller.device = hid_core.GetEmulatedControllerByIndex(i); | 67 | controller.device = hid_core.GetEmulatedControllerByIndex(i); |
| 68 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = | 68 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = |
| 69 | DEFAULT_VIBRATION_VALUE; | 69 | Core::HID::DEFAULT_VIBRATION_VALUE; |
| 70 | controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = | 70 | controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = |
| 71 | DEFAULT_VIBRATION_VALUE; | 71 | Core::HID::DEFAULT_VIBRATION_VALUE; |
| 72 | Core::HID::ControllerUpdateCallback engine_callback{ | 72 | Core::HID::ControllerUpdateCallback engine_callback{ |
| 73 | .on_change = [this, | 73 | .on_change = [this, |
| 74 | i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, | 74 | i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, |
| @@ -781,7 +781,8 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, | |||
| 781 | Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; | 781 | Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; |
| 782 | controller.device->SetVibration(device_index, vibration); | 782 | controller.device->SetVibration(device_index, vibration); |
| 783 | // Then reset the vibration value to its default value. | 783 | // Then reset the vibration value to its default value. |
| 784 | controller.vibration[device_index].latest_vibration_value = DEFAULT_VIBRATION_VALUE; | 784 | controller.vibration[device_index].latest_vibration_value = |
| 785 | Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 785 | } | 786 | } |
| 786 | 787 | ||
| 787 | return false; | 788 | return false; |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 63281cb35..6b2872bad 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -90,13 +90,6 @@ public: | |||
| 90 | Default = 3, | 90 | Default = 3, |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{ | ||
| 94 | .low_amplitude = 0.0f, | ||
| 95 | .low_frequency = 160.0f, | ||
| 96 | .high_amplitude = 0.0f, | ||
| 97 | .high_frequency = 320.0f, | ||
| 98 | }; | ||
| 99 | |||
| 100 | void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); | 93 | void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); |
| 101 | Core::HID::NpadStyleTag GetSupportedStyleSet() const; | 94 | Core::HID::NpadStyleTag GetSupportedStyleSet() const; |
| 102 | 95 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 7163e1a4e..6e12381fb 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -1404,7 +1404,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | |||
| 1404 | .high_frequency = 0.0f, | 1404 | .high_frequency = 0.0f, |
| 1405 | }; | 1405 | }; |
| 1406 | default: | 1406 | default: |
| 1407 | return Controller_NPad::DEFAULT_VIBRATION_VALUE; | 1407 | return Core::HID::DEFAULT_VIBRATION_VALUE; |
| 1408 | } | 1408 | } |
| 1409 | }(); | 1409 | }(); |
| 1410 | 1410 | ||
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 693ffc71a..761d0d3c6 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/kernel/k_event.h" | 11 | #include "core/hle/kernel/k_event.h" |
| 12 | #include "core/hle/lock.h" | ||
| 13 | #include "core/hle/service/nfp/nfp.h" | 12 | #include "core/hle/service/nfp/nfp.h" |
| 14 | #include "core/hle/service/nfp/nfp_user.h" | 13 | #include "core/hle/service/nfp/nfp_user.h" |
| 15 | 14 | ||
| @@ -337,7 +336,6 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | |||
| 337 | } | 336 | } |
| 338 | 337 | ||
| 339 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | 338 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { |
| 340 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 341 | if (buffer.size() < sizeof(AmiiboFile)) { | 339 | if (buffer.size() < sizeof(AmiiboFile)) { |
| 342 | return false; | 340 | return false; |
| 343 | } | 341 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index b4c3a6099..5fead6d1b 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -186,6 +186,10 @@ u32 BufferQueue::Query(QueryType type) { | |||
| 186 | case QueryType::NativeWindowWidth: | 186 | case QueryType::NativeWindowWidth: |
| 187 | case QueryType::NativeWindowHeight: | 187 | case QueryType::NativeWindowHeight: |
| 188 | break; | 188 | break; |
| 189 | case QueryType::NativeWindowMinUndequeuedBuffers: | ||
| 190 | return 0; | ||
| 191 | case QueryType::NativeWindowConsumerUsageBits: | ||
| 192 | return 0; | ||
| 189 | } | 193 | } |
| 190 | UNIMPLEMENTED_MSG("Unimplemented query type={}", type); | 194 | UNIMPLEMENTED_MSG("Unimplemented query type={}", type); |
| 191 | return 0; | 195 | return 0; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 7b7baeaea..f2a579133 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -57,6 +57,11 @@ public: | |||
| 57 | NativeWindowWidth = 0, | 57 | NativeWindowWidth = 0, |
| 58 | NativeWindowHeight = 1, | 58 | NativeWindowHeight = 1, |
| 59 | NativeWindowFormat = 2, | 59 | NativeWindowFormat = 2, |
| 60 | /// The minimum number of buffers that must remain un-dequeued after a buffer has been | ||
| 61 | /// queued | ||
| 62 | NativeWindowMinUndequeuedBuffers = 3, | ||
| 63 | /// The consumer gralloc usage bits currently set by the consumer | ||
| 64 | NativeWindowConsumerUsageBits = 10, | ||
| 60 | }; | 65 | }; |
| 61 | 66 | ||
| 62 | explicit BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_, | 67 | explicit BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_, |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index a22811ec1..01e69de30 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -100,9 +100,6 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { | |||
| 100 | 100 | ||
| 101 | LOG_DEBUG(Service, "Opening \"{}\" display", name); | 101 | LOG_DEBUG(Service, "Opening \"{}\" display", name); |
| 102 | 102 | ||
| 103 | // TODO(Subv): Currently we only support the Default display. | ||
| 104 | ASSERT(name == "Default"); | ||
| 105 | |||
| 106 | const auto itr = | 103 | const auto itr = |
| 107 | std::find_if(displays.begin(), displays.end(), | 104 | std::find_if(displays.begin(), displays.end(), |
| 108 | [&](const VI::Display& display) { return display.GetName() == name; }); | 105 | [&](const VI::Display& display) { return display.GetName() == name; }); |
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 3ae9e6e0e..99ed34b00 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp | |||
| @@ -71,7 +71,6 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, | |||
| 71 | kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, 0x1FE00000, | 71 | kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, 0x1FE00000, |
| 72 | kip->GetKernelCapabilities()); | 72 | kip->GetKernelCapabilities()); |
| 73 | 73 | ||
| 74 | const VAddr base_address = process.PageTable().GetCodeRegionStart(); | ||
| 75 | Kernel::CodeSet codeset; | 74 | Kernel::CodeSet codeset; |
| 76 | Kernel::PhysicalMemory program_image; | 75 | Kernel::PhysicalMemory program_image; |
| 77 | 76 | ||
| @@ -91,7 +90,14 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, | |||
| 91 | program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); | 90 | program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); |
| 92 | codeset.DataSegment().size += kip->GetBSSSize(); | 91 | codeset.DataSegment().size += kip->GetBSSSize(); |
| 93 | 92 | ||
| 93 | // Setup the process code layout | ||
| 94 | if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size()) | ||
| 95 | .IsError()) { | ||
| 96 | return {ResultStatus::ErrorNotInitialized, {}}; | ||
| 97 | } | ||
| 98 | |||
| 94 | codeset.memory = std::move(program_image); | 99 | codeset.memory = std::move(program_image); |
| 100 | const VAddr base_address = process.PageTable().GetCodeRegionStart(); | ||
| 95 | process.LoadModule(std::move(codeset), base_address); | 101 | process.LoadModule(std::move(codeset), base_address); |
| 96 | 102 | ||
| 97 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); | 103 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); |
diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 4ab991a7d..a1ce4525d 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp | |||
| @@ -536,42 +536,46 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 536 | std::function<void(u16, u16, u16, u16)> data_callback) { | 536 | std::function<void(u16, u16, u16, u16)> data_callback) { |
| 537 | 537 | ||
| 538 | std::thread([=, this] { | 538 | std::thread([=, this] { |
| 539 | u16 min_x{UINT16_MAX}; | ||
| 540 | u16 min_y{UINT16_MAX}; | ||
| 541 | u16 max_x{}; | ||
| 542 | u16 max_y{}; | ||
| 543 | |||
| 539 | Status current_status{Status::Initialized}; | 544 | Status current_status{Status::Initialized}; |
| 540 | SocketCallback callback{ | 545 | SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, |
| 541 | [](Response::Version) {}, [](Response::PortInfo) {}, | 546 | [&](Response::PadData data) { |
| 542 | [&](Response::PadData data) { | 547 | constexpr u16 CALIBRATION_THRESHOLD = 100; |
| 543 | static constexpr u16 CALIBRATION_THRESHOLD = 100; | 548 | |
| 544 | static constexpr u16 MAX_VALUE = UINT16_MAX; | 549 | if (current_status == Status::Initialized) { |
| 545 | 550 | // Receiving data means the communication is ready now | |
| 546 | if (current_status == Status::Initialized) { | 551 | current_status = Status::Ready; |
| 547 | // Receiving data means the communication is ready now | 552 | status_callback(current_status); |
| 548 | current_status = Status::Ready; | 553 | } |
| 549 | status_callback(current_status); | 554 | if (data.touch[0].is_active == 0) { |
| 550 | } | 555 | return; |
| 551 | const auto& touchpad_0 = data.touch[0]; | 556 | } |
| 552 | if (touchpad_0.is_active == 0) { | 557 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, |
| 553 | return; | 558 | data.touch[0].y); |
| 554 | } | 559 | min_x = std::min(min_x, static_cast<u16>(data.touch[0].x)); |
| 555 | LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y); | 560 | min_y = std::min(min_y, static_cast<u16>(data.touch[0].y)); |
| 556 | const u16 min_x = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.x)); | 561 | if (current_status == Status::Ready) { |
| 557 | const u16 min_y = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.y)); | 562 | // First touch - min data (min_x/min_y) |
| 558 | if (current_status == Status::Ready) { | 563 | current_status = Status::Stage1Completed; |
| 559 | // First touch - min data (min_x/min_y) | 564 | status_callback(current_status); |
| 560 | current_status = Status::Stage1Completed; | 565 | } |
| 561 | status_callback(current_status); | 566 | if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && |
| 562 | } | 567 | data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { |
| 563 | if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD && | 568 | // Set the current position as max value and finishes |
| 564 | touchpad_0.y - min_y > CALIBRATION_THRESHOLD) { | 569 | // configuration |
| 565 | // Set the current position as max value and finishes configuration | 570 | max_x = data.touch[0].x; |
| 566 | const u16 max_x = touchpad_0.x; | 571 | max_y = data.touch[0].y; |
| 567 | const u16 max_y = touchpad_0.y; | 572 | current_status = Status::Completed; |
| 568 | current_status = Status::Completed; | 573 | data_callback(min_x, min_y, max_x, max_y); |
| 569 | data_callback(min_x, min_y, max_x, max_y); | 574 | status_callback(current_status); |
| 570 | status_callback(current_status); | 575 | |
| 571 | 576 | complete_event.Set(); | |
| 572 | complete_event.Set(); | 577 | } |
| 573 | } | 578 | }}; |
| 574 | }}; | ||
| 575 | Socket socket{host, port, std::move(callback)}; | 579 | Socket socket{host, port, std::move(callback)}; |
| 576 | std::thread worker_thread{SocketLoop, &socket}; | 580 | std::thread worker_thread{SocketLoop, &socket}; |
| 577 | complete_event.Wait(); | 581 | complete_event.Wait(); |
diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index bcba12c58..2d5d54ddb 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h | |||
| @@ -54,6 +54,18 @@ struct Message { | |||
| 54 | template <typename T> | 54 | template <typename T> |
| 55 | constexpr Type GetMessageType(); | 55 | constexpr Type GetMessageType(); |
| 56 | 56 | ||
| 57 | template <typename T> | ||
| 58 | Message<T> CreateMessage(const u32 magic, const T data, const u32 sender_id) { | ||
| 59 | boost::crc_32_type crc; | ||
| 60 | Header header{ | ||
| 61 | magic, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, sender_id, GetMessageType<T>(), | ||
| 62 | }; | ||
| 63 | Message<T> message{header, data}; | ||
| 64 | crc.process_bytes(&message, sizeof(Message<T>)); | ||
| 65 | message.header.crc = crc.checksum(); | ||
| 66 | return message; | ||
| 67 | } | ||
| 68 | |||
| 57 | namespace Request { | 69 | namespace Request { |
| 58 | 70 | ||
| 59 | enum RegisterFlags : u8 { | 71 | enum RegisterFlags : u8 { |
| @@ -101,14 +113,7 @@ static_assert(std::is_trivially_copyable_v<PadData>, | |||
| 101 | */ | 113 | */ |
| 102 | template <typename T> | 114 | template <typename T> |
| 103 | Message<T> Create(const T data, const u32 client_id = 0) { | 115 | Message<T> Create(const T data, const u32 client_id = 0) { |
| 104 | boost::crc_32_type crc; | 116 | return CreateMessage(CLIENT_MAGIC, data, client_id); |
| 105 | Header header{ | ||
| 106 | CLIENT_MAGIC, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, client_id, GetMessageType<T>(), | ||
| 107 | }; | ||
| 108 | Message<T> message{header, data}; | ||
| 109 | crc.process_bytes(&message, sizeof(Message<T>)); | ||
| 110 | message.header.crc = crc.checksum(); | ||
| 111 | return message; | ||
| 112 | } | 117 | } |
| 113 | } // namespace Request | 118 | } // namespace Request |
| 114 | 119 | ||
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 081b2c8e0..7434a1f92 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | |||
| @@ -86,7 +86,7 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal | |||
| 86 | } | 86 | } |
| 87 | switch (attr) { | 87 | switch (attr) { |
| 88 | case IR::Attribute::PrimitiveId: | 88 | case IR::Attribute::PrimitiveId: |
| 89 | ctx.Add("MOV.S {}.x,primitive.id;", inst); | 89 | ctx.Add("MOV.F {}.x,primitive.id;", inst); |
| 90 | break; | 90 | break; |
| 91 | case IR::Attribute::PositionX: | 91 | case IR::Attribute::PositionX: |
| 92 | case IR::Attribute::PositionY: | 92 | case IR::Attribute::PositionY: |
| @@ -113,19 +113,35 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal | |||
| 113 | ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle); | 113 | ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle); |
| 114 | break; | 114 | break; |
| 115 | case IR::Attribute::InstanceId: | 115 | case IR::Attribute::InstanceId: |
| 116 | ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name); | 116 | ctx.Add("MOV.F {}.x,{}.instance;", inst, ctx.attrib_name); |
| 117 | break; | 117 | break; |
| 118 | case IR::Attribute::VertexId: | 118 | case IR::Attribute::VertexId: |
| 119 | ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name); | 119 | ctx.Add("MOV.F {}.x,{}.id;", inst, ctx.attrib_name); |
| 120 | break; | 120 | break; |
| 121 | case IR::Attribute::FrontFace: | 121 | case IR::Attribute::FrontFace: |
| 122 | ctx.Add("CMP.S {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name); | 122 | ctx.Add("CMP.F {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name); |
| 123 | break; | 123 | break; |
| 124 | default: | 124 | default: |
| 125 | throw NotImplementedException("Get attribute {}", attr); | 125 | throw NotImplementedException("Get attribute {}", attr); |
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32) { | ||
| 130 | switch (attr) { | ||
| 131 | case IR::Attribute::PrimitiveId: | ||
| 132 | ctx.Add("MOV.S {}.x,primitive.id;", inst); | ||
| 133 | break; | ||
| 134 | case IR::Attribute::InstanceId: | ||
| 135 | ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name); | ||
| 136 | break; | ||
| 137 | case IR::Attribute::VertexId: | ||
| 138 | ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name); | ||
| 139 | break; | ||
| 140 | default: | ||
| 141 | throw NotImplementedException("Get U32 attribute {}", attr); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 129 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, | 145 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, |
| 130 | [[maybe_unused]] ScalarU32 vertex) { | 146 | [[maybe_unused]] ScalarU32 vertex) { |
| 131 | const u32 element{static_cast<u32>(attr) % 4}; | 147 | const u32 element{static_cast<u32>(attr) % 4}; |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index 1f343bff5..b48007856 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h | |||
| @@ -50,6 +50,7 @@ void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | |||
| 50 | void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); | 50 | void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); |
| 51 | void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); | 51 | void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, ScalarU32 offset); |
| 52 | void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex); | 52 | void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex); |
| 53 | void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, ScalarU32 vertex); | ||
| 53 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, ScalarU32 vertex); | 54 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, ScalarF32 value, ScalarU32 vertex); |
| 54 | void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, ScalarS32 offset, ScalarU32 vertex); | 55 | void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, ScalarS32 offset, ScalarU32 vertex); |
| 55 | void EmitSetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarF32 value, ScalarU32 vertex); | 56 | void EmitSetAttributeIndexed(EmitContext& ctx, ScalarU32 offset, ScalarF32 value, ScalarU32 vertex); |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp index 78b2eeaa2..b6b17a330 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp | |||
| @@ -176,7 +176,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) { | |||
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | std::string GlslVersionSpecifier(const EmitContext& ctx) { | 178 | std::string GlslVersionSpecifier(const EmitContext& ctx) { |
| 179 | if (ctx.uses_y_direction || ctx.info.stores.Legacy() || ctx.info.loads.Legacy()) { | 179 | if (ctx.uses_y_direction) { |
| 180 | return " compatibility"; | 180 | return " compatibility"; |
| 181 | } | 181 | } |
| 182 | return ""; | 182 | return ""; |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp index 0f2668d9e..e0ead7a53 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" | 7 | #include "shader_recompiler/backend/glsl/emit_glsl_instructions.h" |
| 8 | #include "shader_recompiler/backend/glsl/glsl_emit_context.h" | 8 | #include "shader_recompiler/backend/glsl/glsl_emit_context.h" |
| 9 | #include "shader_recompiler/frontend/ir/value.h" | 9 | #include "shader_recompiler/frontend/ir/value.h" |
| 10 | #include "shader_recompiler/profile.h" | ||
| 10 | 11 | ||
| 11 | namespace Shader::Backend::GLSL { | 12 | namespace Shader::Backend::GLSL { |
| 12 | namespace { | 13 | namespace { |
| @@ -30,8 +31,9 @@ void EmitConditionRef(EmitContext& ctx, IR::Inst& inst, const IR::Value& value) | |||
| 30 | inst.DestructiveAddUsage(1); | 31 | inst.DestructiveAddUsage(1); |
| 31 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U1)}; | 32 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U1)}; |
| 32 | const auto input{ctx.var_alloc.Consume(value)}; | 33 | const auto input{ctx.var_alloc.Consume(value)}; |
| 34 | const auto suffix{ctx.profile.has_gl_bool_ref_bug ? "?true:false" : ""}; | ||
| 33 | if (ret != input) { | 35 | if (ret != input) { |
| 34 | ctx.Add("{}={};", ret, input); | 36 | ctx.Add("{}={}{};", ret, input, suffix); |
| 35 | } | 37 | } |
| 36 | } | 38 | } |
| 37 | 39 | ||
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index 1920047f4..0c1fbc7b1 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp | |||
| @@ -98,47 +98,50 @@ void GetCbuf16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const | |||
| 98 | GetCbuf(ctx, ret, binding, offset, 16, cast, bit_offset); | 98 | GetCbuf(ctx, ret, binding, offset, 16, cast, bit_offset); |
| 99 | } | 99 | } |
| 100 | } | 100 | } |
| 101 | |||
| 102 | u32 TexCoordIndex(IR::Attribute attr) { | ||
| 103 | return (static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4; | ||
| 104 | } | ||
| 105 | } // Anonymous namespace | 101 | } // Anonymous namespace |
| 106 | 102 | ||
| 107 | void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 103 | void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 108 | const IR::Value& offset) { | 104 | const IR::Value& offset) { |
| 109 | GetCbuf8(ctx, inst, binding, offset, "ftou"); | 105 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"}; |
| 106 | GetCbuf8(ctx, inst, binding, offset, cast); | ||
| 110 | } | 107 | } |
| 111 | 108 | ||
| 112 | void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 109 | void EmitGetCbufS8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 113 | const IR::Value& offset) { | 110 | const IR::Value& offset) { |
| 114 | GetCbuf8(ctx, inst, binding, offset, "ftoi"); | 111 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"}; |
| 112 | GetCbuf8(ctx, inst, binding, offset, cast); | ||
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 115 | void EmitGetCbufU16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 118 | const IR::Value& offset) { | 116 | const IR::Value& offset) { |
| 119 | GetCbuf16(ctx, inst, binding, offset, "ftou"); | 117 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"}; |
| 118 | GetCbuf16(ctx, inst, binding, offset, cast); | ||
| 120 | } | 119 | } |
| 121 | 120 | ||
| 122 | void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 121 | void EmitGetCbufS16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 123 | const IR::Value& offset) { | 122 | const IR::Value& offset) { |
| 124 | GetCbuf16(ctx, inst, binding, offset, "ftoi"); | 123 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "int" : "ftoi"}; |
| 124 | GetCbuf16(ctx, inst, binding, offset, cast); | ||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 127 | void EmitGetCbufU32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 128 | const IR::Value& offset) { | 128 | const IR::Value& offset) { |
| 129 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; | 129 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32)}; |
| 130 | GetCbuf(ctx, ret, binding, offset, 32, "ftou"); | 130 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"}; |
| 131 | GetCbuf(ctx, ret, binding, offset, 32, cast); | ||
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 134 | void EmitGetCbufF32(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 134 | const IR::Value& offset) { | 135 | const IR::Value& offset) { |
| 135 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32)}; | 136 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::F32)}; |
| 136 | GetCbuf(ctx, ret, binding, offset, 32); | 137 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "utof" : ""}; |
| 138 | GetCbuf(ctx, ret, binding, offset, 32, cast); | ||
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, | 141 | void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, |
| 140 | const IR::Value& offset) { | 142 | const IR::Value& offset) { |
| 141 | const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; | 143 | const auto cbuf{fmt::format("{}_cbuf{}", ctx.stage_name, binding.U32())}; |
| 144 | const auto cast{ctx.profile.has_gl_cbuf_ftou_bug ? "" : "ftou"}; | ||
| 142 | if (offset.IsImmediate()) { | 145 | if (offset.IsImmediate()) { |
| 143 | static constexpr u32 cbuf_size{0x10000}; | 146 | static constexpr u32 cbuf_size{0x10000}; |
| 144 | const u32 u32_offset{offset.U32()}; | 147 | const u32 u32_offset{offset.U32()}; |
| @@ -149,26 +152,26 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding | |||
| 149 | return; | 152 | return; |
| 150 | } | 153 | } |
| 151 | if (u32_offset % 2 == 0) { | 154 | if (u32_offset % 2 == 0) { |
| 152 | ctx.AddU32x2("{}=ftou({}[{}].{}{});", inst, cbuf, u32_offset / 16, | 155 | ctx.AddU32x2("{}={}({}[{}].{}{});", inst, cast, cbuf, u32_offset / 16, |
| 153 | OffsetSwizzle(u32_offset), OffsetSwizzle(u32_offset + 4)); | 156 | OffsetSwizzle(u32_offset), OffsetSwizzle(u32_offset + 4)); |
| 154 | } else { | 157 | } else { |
| 155 | ctx.AddU32x2("{}=uvec2(ftou({}[{}].{}),ftou({}[{}].{}));", inst, cbuf, u32_offset / 16, | 158 | ctx.AddU32x2("{}=uvec2({}({}[{}].{}),{}({}[{}].{}));", inst, cast, cbuf, |
| 156 | OffsetSwizzle(u32_offset), cbuf, (u32_offset + 4) / 16, | 159 | u32_offset / 16, OffsetSwizzle(u32_offset), cast, cbuf, |
| 157 | OffsetSwizzle(u32_offset + 4)); | 160 | (u32_offset + 4) / 16, OffsetSwizzle(u32_offset + 4)); |
| 158 | } | 161 | } |
| 159 | return; | 162 | return; |
| 160 | } | 163 | } |
| 161 | const auto offset_var{ctx.var_alloc.Consume(offset)}; | 164 | const auto offset_var{ctx.var_alloc.Consume(offset)}; |
| 162 | if (!ctx.profile.has_gl_component_indexing_bug) { | 165 | if (!ctx.profile.has_gl_component_indexing_bug) { |
| 163 | ctx.AddU32x2("{}=uvec2(ftou({}[{}>>4][({}>>2)%4]),ftou({}[({}+4)>>4][(({}+4)>>2)%4]));", | 166 | ctx.AddU32x2("{}=uvec2({}({}[{}>>4][({}>>2)%4]),{}({}[({}+4)>>4][(({}+4)>>2)%4]));", inst, |
| 164 | inst, cbuf, offset_var, offset_var, cbuf, offset_var, offset_var); | 167 | cast, cbuf, offset_var, offset_var, cast, cbuf, offset_var, offset_var); |
| 165 | return; | 168 | return; |
| 166 | } | 169 | } |
| 167 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)}; | 170 | const auto ret{ctx.var_alloc.Define(inst, GlslVarType::U32x2)}; |
| 168 | const auto cbuf_offset{fmt::format("{}>>2", offset_var)}; | 171 | const auto cbuf_offset{fmt::format("{}>>2", offset_var)}; |
| 169 | for (u32 swizzle = 0; swizzle < 4; ++swizzle) { | 172 | for (u32 swizzle = 0; swizzle < 4; ++swizzle) { |
| 170 | ctx.Add("if(({}&3)=={}){}=uvec2(ftou({}[{}>>4].{}),ftou({}[({}+4)>>4].{}));", cbuf_offset, | 173 | ctx.Add("if(({}&3)=={}){}=uvec2({}({}[{}>>4].{}),{}({}[({}+4)>>4].{}));", cbuf_offset, |
| 171 | swizzle, ret, cbuf, offset_var, "xyzw"[swizzle], cbuf, offset_var, | 174 | swizzle, ret, cast, cbuf, offset_var, "xyzw"[swizzle], cast, cbuf, offset_var, |
| 172 | "xyzw"[(swizzle + 1) % 4]); | 175 | "xyzw"[(swizzle + 1) % 4]); |
| 173 | } | 176 | } |
| 174 | } | 177 | } |
| @@ -190,18 +193,6 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, | |||
| 190 | ctx.AddF32("{}=in_attr{}{}.{};", inst, index, InputVertexIndex(ctx, vertex), swizzle); | 193 | ctx.AddF32("{}=in_attr{}{}.{};", inst, index, InputVertexIndex(ctx, vertex), swizzle); |
| 191 | return; | 194 | return; |
| 192 | } | 195 | } |
| 193 | // GLSL only exposes 8 legacy texcoords | ||
| 194 | if (attr >= IR::Attribute::FixedFncTexture8S && attr <= IR::Attribute::FixedFncTexture9Q) { | ||
| 195 | LOG_WARNING(Shader_GLSL, "GLSL does not allow access to gl_TexCoord[{}]", | ||
| 196 | TexCoordIndex(attr)); | ||
| 197 | ctx.AddF32("{}=0.f;", inst); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture7Q) { | ||
| 201 | const u32 index{TexCoordIndex(attr)}; | ||
| 202 | ctx.AddF32("{}=gl_TexCoord[{}].{};", inst, index, swizzle); | ||
| 203 | return; | ||
| 204 | } | ||
| 205 | switch (attr) { | 196 | switch (attr) { |
| 206 | case IR::Attribute::PrimitiveId: | 197 | case IR::Attribute::PrimitiveId: |
| 207 | ctx.AddF32("{}=itof(gl_PrimitiveID);", inst); | 198 | ctx.AddF32("{}=itof(gl_PrimitiveID);", inst); |
| @@ -215,16 +206,6 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, | |||
| 215 | ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle); | 206 | ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle); |
| 216 | break; | 207 | break; |
| 217 | } | 208 | } |
| 218 | case IR::Attribute::ColorFrontDiffuseR: | ||
| 219 | case IR::Attribute::ColorFrontDiffuseG: | ||
| 220 | case IR::Attribute::ColorFrontDiffuseB: | ||
| 221 | case IR::Attribute::ColorFrontDiffuseA: | ||
| 222 | if (ctx.stage == Stage::Fragment) { | ||
| 223 | ctx.AddF32("{}=gl_Color.{};", inst, swizzle); | ||
| 224 | } else { | ||
| 225 | ctx.AddF32("{}=gl_FrontColor.{};", inst, swizzle); | ||
| 226 | } | ||
| 227 | break; | ||
| 228 | case IR::Attribute::PointSpriteS: | 209 | case IR::Attribute::PointSpriteS: |
| 229 | case IR::Attribute::PointSpriteT: | 210 | case IR::Attribute::PointSpriteT: |
| 230 | ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle); | 211 | ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle); |
| @@ -247,6 +228,22 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, | |||
| 247 | } | 228 | } |
| 248 | } | 229 | } |
| 249 | 230 | ||
| 231 | void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, std::string_view) { | ||
| 232 | switch (attr) { | ||
| 233 | case IR::Attribute::PrimitiveId: | ||
| 234 | ctx.AddU32("{}=uint(gl_PrimitiveID);", inst); | ||
| 235 | break; | ||
| 236 | case IR::Attribute::InstanceId: | ||
| 237 | ctx.AddU32("{}=uint(gl_InstanceID);", inst); | ||
| 238 | break; | ||
| 239 | case IR::Attribute::VertexId: | ||
| 240 | ctx.AddU32("{}=uint(gl_VertexID);", inst); | ||
| 241 | break; | ||
| 242 | default: | ||
| 243 | throw NotImplementedException("Get U32 attribute {}", attr); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 250 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value, | 247 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value, |
| 251 | [[maybe_unused]] std::string_view vertex) { | 248 | [[maybe_unused]] std::string_view vertex) { |
| 252 | if (IR::IsGeneric(attr)) { | 249 | if (IR::IsGeneric(attr)) { |
| @@ -264,17 +261,6 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val | |||
| 264 | } | 261 | } |
| 265 | const u32 element{static_cast<u32>(attr) % 4}; | 262 | const u32 element{static_cast<u32>(attr) % 4}; |
| 266 | const char swizzle{"xyzw"[element]}; | 263 | const char swizzle{"xyzw"[element]}; |
| 267 | // GLSL only exposes 8 legacy texcoords | ||
| 268 | if (attr >= IR::Attribute::FixedFncTexture8S && attr <= IR::Attribute::FixedFncTexture9Q) { | ||
| 269 | LOG_WARNING(Shader_GLSL, "GLSL does not allow access to gl_TexCoord[{}]", | ||
| 270 | TexCoordIndex(attr)); | ||
| 271 | return; | ||
| 272 | } | ||
| 273 | if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture7Q) { | ||
| 274 | const u32 index{TexCoordIndex(attr)}; | ||
| 275 | ctx.Add("gl_TexCoord[{}].{}={};", index, swizzle, value); | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | switch (attr) { | 264 | switch (attr) { |
| 279 | case IR::Attribute::Layer: | 265 | case IR::Attribute::Layer: |
| 280 | if (ctx.stage != Stage::Geometry && | 266 | if (ctx.stage != Stage::Geometry && |
| @@ -312,33 +298,6 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val | |||
| 312 | case IR::Attribute::PositionW: | 298 | case IR::Attribute::PositionW: |
| 313 | ctx.Add("gl_Position.{}={};", swizzle, value); | 299 | ctx.Add("gl_Position.{}={};", swizzle, value); |
| 314 | break; | 300 | break; |
| 315 | case IR::Attribute::ColorFrontDiffuseR: | ||
| 316 | case IR::Attribute::ColorFrontDiffuseG: | ||
| 317 | case IR::Attribute::ColorFrontDiffuseB: | ||
| 318 | case IR::Attribute::ColorFrontDiffuseA: | ||
| 319 | ctx.Add("gl_FrontColor.{}={};", swizzle, value); | ||
| 320 | break; | ||
| 321 | case IR::Attribute::ColorFrontSpecularR: | ||
| 322 | case IR::Attribute::ColorFrontSpecularG: | ||
| 323 | case IR::Attribute::ColorFrontSpecularB: | ||
| 324 | case IR::Attribute::ColorFrontSpecularA: | ||
| 325 | ctx.Add("gl_FrontSecondaryColor.{}={};", swizzle, value); | ||
| 326 | break; | ||
| 327 | case IR::Attribute::ColorBackDiffuseR: | ||
| 328 | case IR::Attribute::ColorBackDiffuseG: | ||
| 329 | case IR::Attribute::ColorBackDiffuseB: | ||
| 330 | case IR::Attribute::ColorBackDiffuseA: | ||
| 331 | ctx.Add("gl_BackColor.{}={};", swizzle, value); | ||
| 332 | break; | ||
| 333 | case IR::Attribute::ColorBackSpecularR: | ||
| 334 | case IR::Attribute::ColorBackSpecularG: | ||
| 335 | case IR::Attribute::ColorBackSpecularB: | ||
| 336 | case IR::Attribute::ColorBackSpecularA: | ||
| 337 | ctx.Add("gl_BackSecondaryColor.{}={};", swizzle, value); | ||
| 338 | break; | ||
| 339 | case IR::Attribute::FogCoordinate: | ||
| 340 | ctx.Add("gl_FogFragCoord={};", value); | ||
| 341 | break; | ||
| 342 | case IR::Attribute::ClipDistance0: | 301 | case IR::Attribute::ClipDistance0: |
| 343 | case IR::Attribute::ClipDistance1: | 302 | case IR::Attribute::ClipDistance1: |
| 344 | case IR::Attribute::ClipDistance2: | 303 | case IR::Attribute::ClipDistance2: |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp index b765a251b..474189d87 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_floating_point.cpp | |||
| @@ -125,11 +125,11 @@ void EmitFPNeg16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& i | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | 127 | void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { |
| 128 | ctx.AddF32("{}=-({});", inst, value); | 128 | ctx.AddF32("{}=0.f-({});", inst, value); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | 131 | void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { |
| 132 | ctx.AddF64("{}=-({});", inst, value); | 132 | ctx.AddF64("{}=double(0.)-({});", inst, value); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | void EmitFPSin(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | 135 | void EmitFPSin(EmitContext& ctx, IR::Inst& inst, std::string_view value) { |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index f86502e4c..6cabbc717 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h | |||
| @@ -60,6 +60,8 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding | |||
| 60 | const IR::Value& offset); | 60 | const IR::Value& offset); |
| 61 | void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, | 61 | void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, |
| 62 | std::string_view vertex); | 62 | std::string_view vertex); |
| 63 | void EmitGetAttributeU32(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, | ||
| 64 | std::string_view vertex); | ||
| 63 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value, | 65 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view value, |
| 64 | std::string_view vertex); | 66 | std::string_view vertex); |
| 65 | void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset, | 67 | void EmitGetAttributeIndexed(EmitContext& ctx, IR::Inst& inst, std::string_view offset, |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp index 44060df33..b0d85be99 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp | |||
| @@ -87,11 +87,11 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin | |||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | 89 | void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { |
| 90 | ctx.AddU32("{}=uint(-({}));", inst, value); | 90 | ctx.AddU32("{}=uint(int(0)-int({}));", inst, value); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | 93 | void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { |
| 94 | ctx.AddU64("{}=-({});", inst, value); | 94 | ctx.AddU64("{}=uint64_t(int64_t(0)-int64_t({}));", inst, value); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { | 97 | void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp index b8ddafe48..fcf620b79 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_special.cpp | |||
| @@ -90,7 +90,9 @@ void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& | |||
| 90 | if (phi_reg == val_reg) { | 90 | if (phi_reg == val_reg) { |
| 91 | return; | 91 | return; |
| 92 | } | 92 | } |
| 93 | ctx.Add("{}={};", phi_reg, val_reg); | 93 | const bool needs_workaround{ctx.profile.has_gl_bool_ref_bug && phi_type == IR::Type::U1}; |
| 94 | const auto suffix{needs_workaround ? "?true:false" : ""}; | ||
| 95 | ctx.Add("{}={}{};", phi_reg, val_reg, suffix); | ||
| 94 | } | 96 | } |
| 95 | 97 | ||
| 96 | void EmitPrologue(EmitContext& ctx) { | 98 | void EmitPrologue(EmitContext& ctx) { |
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp index 1de017e76..bb7f1a0fd 100644 --- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp | |||
| @@ -211,27 +211,6 @@ std::string_view OutputPrimitive(OutputTopology topology) { | |||
| 211 | throw InvalidArgument("Invalid output topology {}", topology); | 211 | throw InvalidArgument("Invalid output topology {}", topology); |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | void SetupLegacyOutPerVertex(EmitContext& ctx, std::string& header) { | ||
| 215 | if (!ctx.info.stores.Legacy()) { | ||
| 216 | return; | ||
| 217 | } | ||
| 218 | if (ctx.info.stores.FixedFunctionTexture()) { | ||
| 219 | header += "vec4 gl_TexCoord[8];"; | ||
| 220 | } | ||
| 221 | if (ctx.info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) { | ||
| 222 | header += "vec4 gl_FrontColor;"; | ||
| 223 | } | ||
| 224 | if (ctx.info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) { | ||
| 225 | header += "vec4 gl_FrontSecondaryColor;"; | ||
| 226 | } | ||
| 227 | if (ctx.info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) { | ||
| 228 | header += "vec4 gl_BackColor;"; | ||
| 229 | } | ||
| 230 | if (ctx.info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) { | ||
| 231 | header += "vec4 gl_BackSecondaryColor;"; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | void SetupOutPerVertex(EmitContext& ctx, std::string& header) { | 214 | void SetupOutPerVertex(EmitContext& ctx, std::string& header) { |
| 236 | if (!StoresPerVertexAttributes(ctx.stage)) { | 215 | if (!StoresPerVertexAttributes(ctx.stage)) { |
| 237 | return; | 216 | return; |
| @@ -250,7 +229,6 @@ void SetupOutPerVertex(EmitContext& ctx, std::string& header) { | |||
| 250 | ctx.profile.support_viewport_index_layer_non_geometry && ctx.stage != Stage::Geometry) { | 229 | ctx.profile.support_viewport_index_layer_non_geometry && ctx.stage != Stage::Geometry) { |
| 251 | header += "int gl_ViewportIndex;"; | 230 | header += "int gl_ViewportIndex;"; |
| 252 | } | 231 | } |
| 253 | SetupLegacyOutPerVertex(ctx, header); | ||
| 254 | header += "};"; | 232 | header += "};"; |
| 255 | if (ctx.info.stores[IR::Attribute::ViewportIndex] && ctx.stage == Stage::Geometry) { | 233 | if (ctx.info.stores[IR::Attribute::ViewportIndex] && ctx.stage == Stage::Geometry) { |
| 256 | header += "out int gl_ViewportIndex;"; | 234 | header += "out int gl_ViewportIndex;"; |
| @@ -282,21 +260,6 @@ void SetupInPerVertex(EmitContext& ctx, std::string& header) { | |||
| 282 | } | 260 | } |
| 283 | header += "}gl_in[gl_MaxPatchVertices];"; | 261 | header += "}gl_in[gl_MaxPatchVertices];"; |
| 284 | } | 262 | } |
| 285 | |||
| 286 | void SetupLegacyInPerFragment(EmitContext& ctx, std::string& header) { | ||
| 287 | if (!ctx.info.loads.Legacy()) { | ||
| 288 | return; | ||
| 289 | } | ||
| 290 | header += "in gl_PerFragment{"; | ||
| 291 | if (ctx.info.loads.FixedFunctionTexture()) { | ||
| 292 | header += "vec4 gl_TexCoord[8];"; | ||
| 293 | } | ||
| 294 | if (ctx.info.loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) { | ||
| 295 | header += "vec4 gl_Color;"; | ||
| 296 | } | ||
| 297 | header += "};"; | ||
| 298 | } | ||
| 299 | |||
| 300 | } // Anonymous namespace | 263 | } // Anonymous namespace |
| 301 | 264 | ||
| 302 | EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_, | 265 | EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_, |
| @@ -361,7 +324,6 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile | |||
| 361 | } | 324 | } |
| 362 | SetupOutPerVertex(*this, header); | 325 | SetupOutPerVertex(*this, header); |
| 363 | SetupInPerVertex(*this, header); | 326 | SetupInPerVertex(*this, header); |
| 364 | SetupLegacyInPerFragment(*this, header); | ||
| 365 | 327 | ||
| 366 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | 328 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 367 | if (!info.loads.Generic(index) || !runtime_info.previous_stage_stores.Generic(index)) { | 329 | if (!info.loads.Generic(index) || !runtime_info.previous_stage_stores.Generic(index)) { |
| @@ -466,9 +428,10 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) { | |||
| 466 | return; | 428 | return; |
| 467 | } | 429 | } |
| 468 | for (const auto& desc : info.constant_buffer_descriptors) { | 430 | for (const auto& desc : info.constant_buffer_descriptors) { |
| 469 | header += fmt::format( | 431 | const auto cbuf_type{profile.has_gl_cbuf_ftou_bug ? "uvec4" : "vec4"}; |
| 470 | "layout(std140,binding={}) uniform {}_cbuf_{}{{vec4 {}_cbuf{}[{}];}};", | 432 | header += fmt::format("layout(std140,binding={}) uniform {}_cbuf_{}{{{} {}_cbuf{}[{}];}};", |
| 471 | bindings.uniform_buffer, stage_name, desc.index, stage_name, desc.index, 4 * 1024); | 433 | bindings.uniform_buffer, stage_name, desc.index, cbuf_type, |
| 434 | stage_name, desc.index, 4 * 1024); | ||
| 472 | bindings.uniform_buffer += desc.count; | 435 | bindings.uniform_buffer += desc.count; |
| 473 | } | 436 | } |
| 474 | } | 437 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 6ce7ed12a..50918317f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -30,11 +30,20 @@ struct FuncTraits<ReturnType_ (*)(Args...)> { | |||
| 30 | using ArgType = std::tuple_element_t<I, std::tuple<Args...>>; | 30 | using ArgType = std::tuple_element_t<I, std::tuple<Args...>>; |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | #ifdef _MSC_VER | ||
| 34 | #pragma warning(push) | ||
| 35 | #pragma warning(disable : 4702) // Ignore unreachable code warning | ||
| 36 | #endif | ||
| 37 | |||
| 33 | template <auto func, typename... Args> | 38 | template <auto func, typename... Args> |
| 34 | void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { | 39 | void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) { |
| 35 | inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...)); | 40 | inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...)); |
| 36 | } | 41 | } |
| 37 | 42 | ||
| 43 | #ifdef _MSC_VER | ||
| 44 | #pragma warning(pop) | ||
| 45 | #endif | ||
| 46 | |||
| 38 | template <typename ArgType> | 47 | template <typename ArgType> |
| 39 | ArgType Arg(EmitContext& ctx, const IR::Value& arg) { | 48 | ArgType Arg(EmitContext& ctx, const IR::Value& arg) { |
| 40 | if constexpr (std::is_same_v<ArgType, Id>) { | 49 | if constexpr (std::is_same_v<ArgType, Id>) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index ad84966b5..8ea730c80 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -44,14 +44,6 @@ Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | bool IsLegacyAttribute(IR::Attribute attribute) { | ||
| 48 | return (attribute >= IR::Attribute::ColorFrontDiffuseR && | ||
| 49 | attribute <= IR::Attribute::ColorBackSpecularA) || | ||
| 50 | attribute == IR::Attribute::FogCoordinate || | ||
| 51 | (attribute >= IR::Attribute::FixedFncTexture0S && | ||
| 52 | attribute <= IR::Attribute::FixedFncTexture9Q); | ||
| 53 | } | ||
| 54 | |||
| 55 | template <typename... Args> | 47 | template <typename... Args> |
| 56 | Id OutputAccessChain(EmitContext& ctx, Id result_type, Id base, Args&&... args) { | 48 | Id OutputAccessChain(EmitContext& ctx, Id result_type, Id base, Args&&... args) { |
| 57 | if (ctx.stage == Stage::TessellationControl) { | 49 | if (ctx.stage == Stage::TessellationControl) { |
| @@ -83,17 +75,6 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 83 | return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id); | 75 | return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id); |
| 84 | } | 76 | } |
| 85 | } | 77 | } |
| 86 | if (IsLegacyAttribute(attr)) { | ||
| 87 | if (attr == IR::Attribute::FogCoordinate) { | ||
| 88 | return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr), | ||
| 89 | ctx.Const(0u)); | ||
| 90 | } else { | ||
| 91 | const u32 element{static_cast<u32>(attr) % 4}; | ||
| 92 | const Id element_id{ctx.Const(element)}; | ||
| 93 | return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr), | ||
| 94 | element_id); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | switch (attr) { | 78 | switch (attr) { |
| 98 | case IR::Attribute::PointSize: | 79 | case IR::Attribute::PointSize: |
| 99 | return ctx.output_point_size; | 80 | return ctx.output_point_size; |
| @@ -327,18 +308,6 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 327 | const Id value{ctx.OpLoad(type->id, pointer)}; | 308 | const Id value{ctx.OpLoad(type->id, pointer)}; |
| 328 | return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; | 309 | return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; |
| 329 | } | 310 | } |
| 330 | if (IsLegacyAttribute(attr)) { | ||
| 331 | if (attr == IR::Attribute::FogCoordinate) { | ||
| 332 | const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex, | ||
| 333 | ctx.InputLegacyAttribute(attr), ctx.Const(0u))}; | ||
| 334 | return ctx.OpLoad(ctx.F32[1], attr_ptr); | ||
| 335 | } else { | ||
| 336 | const Id element_id{ctx.Const(element)}; | ||
| 337 | const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex, | ||
| 338 | ctx.InputLegacyAttribute(attr), element_id)}; | ||
| 339 | return ctx.OpLoad(ctx.F32[1], attr_ptr); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | switch (attr) { | 311 | switch (attr) { |
| 343 | case IR::Attribute::PrimitiveId: | 312 | case IR::Attribute::PrimitiveId: |
| 344 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); | 313 | return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); |
| @@ -386,6 +355,31 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { | |||
| 386 | } | 355 | } |
| 387 | } | 356 | } |
| 388 | 357 | ||
| 358 | Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id) { | ||
| 359 | switch (attr) { | ||
| 360 | case IR::Attribute::PrimitiveId: | ||
| 361 | return ctx.OpLoad(ctx.U32[1], ctx.primitive_id); | ||
| 362 | case IR::Attribute::InstanceId: | ||
| 363 | if (ctx.profile.support_vertex_instance_id) { | ||
| 364 | return ctx.OpLoad(ctx.U32[1], ctx.instance_id); | ||
| 365 | } else { | ||
| 366 | const Id index{ctx.OpLoad(ctx.U32[1], ctx.instance_index)}; | ||
| 367 | const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_instance)}; | ||
| 368 | return ctx.OpISub(ctx.U32[1], index, base); | ||
| 369 | } | ||
| 370 | case IR::Attribute::VertexId: | ||
| 371 | if (ctx.profile.support_vertex_instance_id) { | ||
| 372 | return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); | ||
| 373 | } else { | ||
| 374 | const Id index{ctx.OpLoad(ctx.U32[1], ctx.vertex_index)}; | ||
| 375 | const Id base{ctx.OpLoad(ctx.U32[1], ctx.base_vertex)}; | ||
| 376 | return ctx.OpISub(ctx.U32[1], index, base); | ||
| 377 | } | ||
| 378 | default: | ||
| 379 | throw NotImplementedException("Read U32 attribute {}", attr); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 389 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, [[maybe_unused]] Id vertex) { | 383 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, [[maybe_unused]] Id vertex) { |
| 390 | const std::optional<OutAttr> output{OutputAttrPointer(ctx, attr)}; | 384 | const std::optional<OutAttr> output{OutputAttrPointer(ctx, attr)}; |
| 391 | if (!output) { | 385 | if (!output) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 6cd22dd3e..887112deb 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -53,6 +53,7 @@ Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| 53 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 53 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); |
| 54 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | 54 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); |
| 55 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex); | 55 | Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex); |
| 56 | Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, Id vertex); | ||
| 56 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex); | 57 | void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, Id vertex); |
| 57 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex); | 58 | Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset, Id vertex); |
| 58 | void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex); | 59 | void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value, Id vertex); |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 4b6f792bf..d3ba66569 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -18,8 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | namespace Shader::Backend::SPIRV { | 19 | namespace Shader::Backend::SPIRV { |
| 20 | namespace { | 20 | namespace { |
| 21 | constexpr size_t NUM_FIXEDFNCTEXTURE = 10; | ||
| 22 | |||
| 23 | enum class Operation { | 21 | enum class Operation { |
| 24 | Increment, | 22 | Increment, |
| 25 | Decrement, | 23 | Decrement, |
| @@ -432,34 +430,6 @@ Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) { | |||
| 432 | return pointer_type; | 430 | return pointer_type; |
| 433 | } | 431 | } |
| 434 | } | 432 | } |
| 435 | |||
| 436 | size_t FindAndSetNextUnusedLocation(std::bitset<IR::NUM_GENERICS>& used_locations, | ||
| 437 | size_t& start_offset) { | ||
| 438 | for (size_t location = start_offset; location < used_locations.size(); ++location) { | ||
| 439 | if (!used_locations.test(location)) { | ||
| 440 | start_offset = location; | ||
| 441 | used_locations.set(location); | ||
| 442 | return location; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | throw RuntimeError("Unable to get an unused location for legacy attribute"); | ||
| 446 | } | ||
| 447 | |||
| 448 | Id DefineLegacyInput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations, | ||
| 449 | size_t& start_offset) { | ||
| 450 | const Id id{DefineInput(ctx, ctx.F32[4], true)}; | ||
| 451 | const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset); | ||
| 452 | ctx.Decorate(id, spv::Decoration::Location, location); | ||
| 453 | return id; | ||
| 454 | } | ||
| 455 | |||
| 456 | Id DefineLegacyOutput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations, | ||
| 457 | size_t& start_offset, std::optional<u32> invocations) { | ||
| 458 | const Id id{DefineOutput(ctx, ctx.F32[4], invocations)}; | ||
| 459 | const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset); | ||
| 460 | ctx.Decorate(id, spv::Decoration::Location, location); | ||
| 461 | return id; | ||
| 462 | } | ||
| 463 | } // Anonymous namespace | 433 | } // Anonymous namespace |
| 464 | 434 | ||
| 465 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | 435 | void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { |
| @@ -543,64 +513,6 @@ Id EmitContext::BitOffset16(const IR::Value& offset) { | |||
| 543 | return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u)); | 513 | return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u)); |
| 544 | } | 514 | } |
| 545 | 515 | ||
| 546 | Id EmitContext::InputLegacyAttribute(IR::Attribute attribute) { | ||
| 547 | if (attribute >= IR::Attribute::ColorFrontDiffuseR && | ||
| 548 | attribute <= IR::Attribute::ColorFrontDiffuseA) { | ||
| 549 | return input_front_color; | ||
| 550 | } | ||
| 551 | if (attribute >= IR::Attribute::ColorFrontSpecularR && | ||
| 552 | attribute <= IR::Attribute::ColorFrontSpecularA) { | ||
| 553 | return input_front_secondary_color; | ||
| 554 | } | ||
| 555 | if (attribute >= IR::Attribute::ColorBackDiffuseR && | ||
| 556 | attribute <= IR::Attribute::ColorBackDiffuseA) { | ||
| 557 | return input_back_color; | ||
| 558 | } | ||
| 559 | if (attribute >= IR::Attribute::ColorBackSpecularR && | ||
| 560 | attribute <= IR::Attribute::ColorBackSpecularA) { | ||
| 561 | return input_back_secondary_color; | ||
| 562 | } | ||
| 563 | if (attribute == IR::Attribute::FogCoordinate) { | ||
| 564 | return input_fog_frag_coord; | ||
| 565 | } | ||
| 566 | if (attribute >= IR::Attribute::FixedFncTexture0S && | ||
| 567 | attribute <= IR::Attribute::FixedFncTexture9Q) { | ||
| 568 | u32 index = | ||
| 569 | (static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4; | ||
| 570 | return input_fixed_fnc_textures[index]; | ||
| 571 | } | ||
| 572 | throw InvalidArgument("Attribute is not legacy attribute {}", attribute); | ||
| 573 | } | ||
| 574 | |||
| 575 | Id EmitContext::OutputLegacyAttribute(IR::Attribute attribute) { | ||
| 576 | if (attribute >= IR::Attribute::ColorFrontDiffuseR && | ||
| 577 | attribute <= IR::Attribute::ColorFrontDiffuseA) { | ||
| 578 | return output_front_color; | ||
| 579 | } | ||
| 580 | if (attribute >= IR::Attribute::ColorFrontSpecularR && | ||
| 581 | attribute <= IR::Attribute::ColorFrontSpecularA) { | ||
| 582 | return output_front_secondary_color; | ||
| 583 | } | ||
| 584 | if (attribute >= IR::Attribute::ColorBackDiffuseR && | ||
| 585 | attribute <= IR::Attribute::ColorBackDiffuseA) { | ||
| 586 | return output_back_color; | ||
| 587 | } | ||
| 588 | if (attribute >= IR::Attribute::ColorBackSpecularR && | ||
| 589 | attribute <= IR::Attribute::ColorBackSpecularA) { | ||
| 590 | return output_back_secondary_color; | ||
| 591 | } | ||
| 592 | if (attribute == IR::Attribute::FogCoordinate) { | ||
| 593 | return output_fog_frag_coord; | ||
| 594 | } | ||
| 595 | if (attribute >= IR::Attribute::FixedFncTexture0S && | ||
| 596 | attribute <= IR::Attribute::FixedFncTexture9Q) { | ||
| 597 | u32 index = | ||
| 598 | (static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4; | ||
| 599 | return output_fixed_fnc_textures[index]; | ||
| 600 | } | ||
| 601 | throw InvalidArgument("Attribute is not legacy attribute {}", attribute); | ||
| 602 | } | ||
| 603 | |||
| 604 | void EmitContext::DefineCommonTypes(const Info& info) { | 516 | void EmitContext::DefineCommonTypes(const Info& info) { |
| 605 | void_id = TypeVoid(); | 517 | void_id = TypeVoid(); |
| 606 | 518 | ||
| @@ -1389,7 +1301,6 @@ void EmitContext::DefineInputs(const IR::Program& program) { | |||
| 1389 | loads[IR::Attribute::TessellationEvaluationPointV]) { | 1301 | loads[IR::Attribute::TessellationEvaluationPointV]) { |
| 1390 | tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord); | 1302 | tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord); |
| 1391 | } | 1303 | } |
| 1392 | std::bitset<IR::NUM_GENERICS> used_locations{}; | ||
| 1393 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | 1304 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 1394 | const AttributeType input_type{runtime_info.generic_input_types[index]}; | 1305 | const AttributeType input_type{runtime_info.generic_input_types[index]}; |
| 1395 | if (!runtime_info.previous_stage_stores.Generic(index)) { | 1306 | if (!runtime_info.previous_stage_stores.Generic(index)) { |
| @@ -1401,7 +1312,6 @@ void EmitContext::DefineInputs(const IR::Program& program) { | |||
| 1401 | if (input_type == AttributeType::Disabled) { | 1312 | if (input_type == AttributeType::Disabled) { |
| 1402 | continue; | 1313 | continue; |
| 1403 | } | 1314 | } |
| 1404 | used_locations.set(index); | ||
| 1405 | const Id type{GetAttributeType(*this, input_type)}; | 1315 | const Id type{GetAttributeType(*this, input_type)}; |
| 1406 | const Id id{DefineInput(*this, type, true)}; | 1316 | const Id id{DefineInput(*this, type, true)}; |
| 1407 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | 1317 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); |
| @@ -1427,30 +1337,6 @@ void EmitContext::DefineInputs(const IR::Program& program) { | |||
| 1427 | break; | 1337 | break; |
| 1428 | } | 1338 | } |
| 1429 | } | 1339 | } |
| 1430 | size_t previous_unused_location = 0; | ||
| 1431 | if (loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) { | ||
| 1432 | input_front_color = DefineLegacyInput(*this, used_locations, previous_unused_location); | ||
| 1433 | } | ||
| 1434 | if (loads.AnyComponent(IR::Attribute::ColorFrontSpecularR)) { | ||
| 1435 | input_front_secondary_color = | ||
| 1436 | DefineLegacyInput(*this, used_locations, previous_unused_location); | ||
| 1437 | } | ||
| 1438 | if (loads.AnyComponent(IR::Attribute::ColorBackDiffuseR)) { | ||
| 1439 | input_back_color = DefineLegacyInput(*this, used_locations, previous_unused_location); | ||
| 1440 | } | ||
| 1441 | if (loads.AnyComponent(IR::Attribute::ColorBackSpecularR)) { | ||
| 1442 | input_back_secondary_color = | ||
| 1443 | DefineLegacyInput(*this, used_locations, previous_unused_location); | ||
| 1444 | } | ||
| 1445 | if (loads.AnyComponent(IR::Attribute::FogCoordinate)) { | ||
| 1446 | input_fog_frag_coord = DefineLegacyInput(*this, used_locations, previous_unused_location); | ||
| 1447 | } | ||
| 1448 | for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) { | ||
| 1449 | if (loads.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) { | ||
| 1450 | input_fixed_fnc_textures[index] = | ||
| 1451 | DefineLegacyInput(*this, used_locations, previous_unused_location); | ||
| 1452 | } | ||
| 1453 | } | ||
| 1454 | if (stage == Stage::TessellationEval) { | 1340 | if (stage == Stage::TessellationEval) { |
| 1455 | for (size_t index = 0; index < info.uses_patches.size(); ++index) { | 1341 | for (size_t index = 0; index < info.uses_patches.size(); ++index) { |
| 1456 | if (!info.uses_patches[index]) { | 1342 | if (!info.uses_patches[index]) { |
| @@ -1501,38 +1387,9 @@ void EmitContext::DefineOutputs(const IR::Program& program) { | |||
| 1501 | viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt, | 1387 | viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt, |
| 1502 | spv::BuiltIn::ViewportMaskNV); | 1388 | spv::BuiltIn::ViewportMaskNV); |
| 1503 | } | 1389 | } |
| 1504 | std::bitset<IR::NUM_GENERICS> used_locations{}; | ||
| 1505 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | 1390 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { |
| 1506 | if (info.stores.Generic(index)) { | 1391 | if (info.stores.Generic(index)) { |
| 1507 | DefineGenericOutput(*this, index, invocations); | 1392 | DefineGenericOutput(*this, index, invocations); |
| 1508 | used_locations.set(index); | ||
| 1509 | } | ||
| 1510 | } | ||
| 1511 | size_t previous_unused_location = 0; | ||
| 1512 | if (info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) { | ||
| 1513 | output_front_color = | ||
| 1514 | DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations); | ||
| 1515 | } | ||
| 1516 | if (info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) { | ||
| 1517 | output_front_secondary_color = | ||
| 1518 | DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations); | ||
| 1519 | } | ||
| 1520 | if (info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) { | ||
| 1521 | output_back_color = | ||
| 1522 | DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations); | ||
| 1523 | } | ||
| 1524 | if (info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) { | ||
| 1525 | output_back_secondary_color = | ||
| 1526 | DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations); | ||
| 1527 | } | ||
| 1528 | if (info.stores.AnyComponent(IR::Attribute::FogCoordinate)) { | ||
| 1529 | output_fog_frag_coord = | ||
| 1530 | DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations); | ||
| 1531 | } | ||
| 1532 | for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) { | ||
| 1533 | if (info.stores.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) { | ||
| 1534 | output_fixed_fnc_textures[index] = | ||
| 1535 | DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations); | ||
| 1536 | } | 1393 | } |
| 1537 | } | 1394 | } |
| 1538 | switch (stage) { | 1395 | switch (stage) { |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 63f8185d9..f87138f7e 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -113,9 +113,6 @@ public: | |||
| 113 | [[nodiscard]] Id BitOffset8(const IR::Value& offset); | 113 | [[nodiscard]] Id BitOffset8(const IR::Value& offset); |
| 114 | [[nodiscard]] Id BitOffset16(const IR::Value& offset); | 114 | [[nodiscard]] Id BitOffset16(const IR::Value& offset); |
| 115 | 115 | ||
| 116 | Id InputLegacyAttribute(IR::Attribute attribute); | ||
| 117 | Id OutputLegacyAttribute(IR::Attribute attribute); | ||
| 118 | |||
| 119 | Id Const(u32 value) { | 116 | Id Const(u32 value) { |
| 120 | return Constant(U32[1], value); | 117 | return Constant(U32[1], value); |
| 121 | } | 118 | } |
| @@ -281,22 +278,10 @@ public: | |||
| 281 | Id write_global_func_u32x4{}; | 278 | Id write_global_func_u32x4{}; |
| 282 | 279 | ||
| 283 | Id input_position{}; | 280 | Id input_position{}; |
| 284 | Id input_front_color{}; | ||
| 285 | Id input_front_secondary_color{}; | ||
| 286 | Id input_back_color{}; | ||
| 287 | Id input_back_secondary_color{}; | ||
| 288 | Id input_fog_frag_coord{}; | ||
| 289 | std::array<Id, 10> input_fixed_fnc_textures{}; | ||
| 290 | std::array<Id, 32> input_generics{}; | 281 | std::array<Id, 32> input_generics{}; |
| 291 | 282 | ||
| 292 | Id output_point_size{}; | 283 | Id output_point_size{}; |
| 293 | Id output_position{}; | 284 | Id output_position{}; |
| 294 | Id output_front_color{}; | ||
| 295 | Id output_front_secondary_color{}; | ||
| 296 | Id output_back_color{}; | ||
| 297 | Id output_back_secondary_color{}; | ||
| 298 | Id output_fog_frag_coord{}; | ||
| 299 | std::array<Id, 10> output_fixed_fnc_textures{}; | ||
| 300 | std::array<std::array<GenericElementInfo, 4>, 32> output_generics{}; | 285 | std::array<std::array<GenericElementInfo, 4>, 32> output_generics{}; |
| 301 | 286 | ||
| 302 | Id output_tess_level_outer{}; | 287 | Id output_tess_level_outer{}; |
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index b4df73e8a..db16429d4 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h | |||
| @@ -31,6 +31,8 @@ public: | |||
| 31 | 31 | ||
| 32 | [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0; | 32 | [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0; |
| 33 | 33 | ||
| 34 | virtual void Dump(u64 hash) = 0; | ||
| 35 | |||
| 34 | [[nodiscard]] const ProgramHeader& SPH() const noexcept { | 36 | [[nodiscard]] const ProgramHeader& SPH() const noexcept { |
| 35 | return sph; | 37 | return sph; |
| 36 | } | 38 | } |
diff --git a/src/shader_recompiler/frontend/ir/attribute.h b/src/shader_recompiler/frontend/ir/attribute.h index ca1199494..3bbd38a03 100644 --- a/src/shader_recompiler/frontend/ir/attribute.h +++ b/src/shader_recompiler/frontend/ir/attribute.h | |||
| @@ -224,6 +224,8 @@ enum class Attribute : u64 { | |||
| 224 | 224 | ||
| 225 | constexpr size_t NUM_GENERICS = 32; | 225 | constexpr size_t NUM_GENERICS = 32; |
| 226 | 226 | ||
| 227 | constexpr size_t NUM_FIXEDFNCTEXTURE = 10; | ||
| 228 | |||
| 227 | [[nodiscard]] bool IsGeneric(Attribute attribute) noexcept; | 229 | [[nodiscard]] bool IsGeneric(Attribute attribute) noexcept; |
| 228 | 230 | ||
| 229 | [[nodiscard]] u32 GenericAttributeIndex(Attribute attribute); | 231 | [[nodiscard]] u32 GenericAttributeIndex(Attribute attribute); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 6929919df..b94ce7406 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -40,6 +40,7 @@ OPCODE(GetCbufU32, U32, U32, | |||
| 40 | OPCODE(GetCbufF32, F32, U32, U32, ) | 40 | OPCODE(GetCbufF32, F32, U32, U32, ) |
| 41 | OPCODE(GetCbufU32x2, U32x2, U32, U32, ) | 41 | OPCODE(GetCbufU32x2, U32x2, U32, U32, ) |
| 42 | OPCODE(GetAttribute, F32, Attribute, U32, ) | 42 | OPCODE(GetAttribute, F32, Attribute, U32, ) |
| 43 | OPCODE(GetAttributeU32, U32, Attribute, U32, ) | ||
| 43 | OPCODE(SetAttribute, Void, Attribute, F32, U32, ) | 44 | OPCODE(SetAttribute, Void, Attribute, F32, U32, ) |
| 44 | OPCODE(GetAttributeIndexed, F32, U32, U32, ) | 45 | OPCODE(GetAttributeIndexed, F32, U32, U32, ) |
| 45 | OPCODE(SetAttributeIndexed, Void, U32, F32, U32, ) | 46 | OPCODE(SetAttributeIndexed, Void, U32, F32, U32, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 267ebe4af..248ad3ced 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | #include <queue> | ||
| 8 | 9 | ||
| 9 | #include "common/settings.h" | 10 | #include "common/settings.h" |
| 10 | #include "shader_recompiler/exception.h" | 11 | #include "shader_recompiler/exception.h" |
| @@ -127,6 +128,42 @@ void AddNVNStorageBuffers(IR::Program& program) { | |||
| 127 | }); | 128 | }); |
| 128 | } | 129 | } |
| 129 | } | 130 | } |
| 131 | |||
| 132 | bool IsLegacyAttribute(IR::Attribute attribute) { | ||
| 133 | return (attribute >= IR::Attribute::ColorFrontDiffuseR && | ||
| 134 | attribute <= IR::Attribute::ColorBackSpecularA) || | ||
| 135 | attribute == IR::Attribute::FogCoordinate || | ||
| 136 | (attribute >= IR::Attribute::FixedFncTexture0S && | ||
| 137 | attribute <= IR::Attribute::FixedFncTexture9Q); | ||
| 138 | } | ||
| 139 | |||
| 140 | std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings( | ||
| 141 | const VaryingState& state, std::queue<IR::Attribute> ununsed_generics) { | ||
| 142 | std::map<IR::Attribute, IR::Attribute> mapping; | ||
| 143 | for (size_t index = 0; index < 4; ++index) { | ||
| 144 | auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4; | ||
| 145 | if (state.AnyComponent(attr)) { | ||
| 146 | for (size_t i = 0; i < 4; ++i) { | ||
| 147 | mapping.insert({attr + i, ununsed_generics.front() + i}); | ||
| 148 | } | ||
| 149 | ununsed_generics.pop(); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | if (state[IR::Attribute::FogCoordinate]) { | ||
| 153 | mapping.insert({IR::Attribute::FogCoordinate, ununsed_generics.front()}); | ||
| 154 | ununsed_generics.pop(); | ||
| 155 | } | ||
| 156 | for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) { | ||
| 157 | auto attr = IR::Attribute::FixedFncTexture0S + index * 4; | ||
| 158 | if (state.AnyComponent(attr)) { | ||
| 159 | for (size_t i = 0; i < 4; ++i) { | ||
| 160 | mapping.insert({attr + i, ununsed_generics.front() + i}); | ||
| 161 | } | ||
| 162 | ununsed_generics.pop(); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | return mapping; | ||
| 166 | } | ||
| 130 | } // Anonymous namespace | 167 | } // Anonymous namespace |
| 131 | 168 | ||
| 132 | IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, | 169 | IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, |
| @@ -226,4 +263,62 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b | |||
| 226 | return result; | 263 | return result; |
| 227 | } | 264 | } |
| 228 | 265 | ||
| 266 | void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) { | ||
| 267 | auto& stores = program.info.stores; | ||
| 268 | if (stores.Legacy()) { | ||
| 269 | std::queue<IR::Attribute> ununsed_output_generics{}; | ||
| 270 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | ||
| 271 | if (!stores.Generic(index)) { | ||
| 272 | ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | auto mappings = GenerateLegacyToGenericMappings(stores, ununsed_output_generics); | ||
| 276 | for (IR::Block* const block : program.post_order_blocks) { | ||
| 277 | for (IR::Inst& inst : block->Instructions()) { | ||
| 278 | switch (inst.GetOpcode()) { | ||
| 279 | case IR::Opcode::SetAttribute: { | ||
| 280 | const auto attr = inst.Arg(0).Attribute(); | ||
| 281 | if (IsLegacyAttribute(attr)) { | ||
| 282 | stores.Set(mappings[attr], true); | ||
| 283 | inst.SetArg(0, Shader::IR::Value(mappings[attr])); | ||
| 284 | } | ||
| 285 | break; | ||
| 286 | } | ||
| 287 | default: | ||
| 288 | break; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | } | ||
| 293 | |||
| 294 | auto& loads = program.info.loads; | ||
| 295 | if (loads.Legacy()) { | ||
| 296 | std::queue<IR::Attribute> ununsed_input_generics{}; | ||
| 297 | for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { | ||
| 298 | const AttributeType input_type{runtime_info.generic_input_types[index]}; | ||
| 299 | if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) || | ||
| 300 | input_type == AttributeType::Disabled) { | ||
| 301 | ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | auto mappings = GenerateLegacyToGenericMappings(loads, ununsed_input_generics); | ||
| 305 | for (IR::Block* const block : program.post_order_blocks) { | ||
| 306 | for (IR::Inst& inst : block->Instructions()) { | ||
| 307 | switch (inst.GetOpcode()) { | ||
| 308 | case IR::Opcode::GetAttribute: { | ||
| 309 | const auto attr = inst.Arg(0).Attribute(); | ||
| 310 | if (IsLegacyAttribute(attr)) { | ||
| 311 | loads.Set(mappings[attr], true); | ||
| 312 | inst.SetArg(0, Shader::IR::Value(mappings[attr])); | ||
| 313 | } | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | default: | ||
| 317 | break; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 229 | } // namespace Shader::Maxwell | 324 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index a84814811..cd535f20d 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "shader_recompiler/frontend/maxwell/control_flow.h" | 10 | #include "shader_recompiler/frontend/maxwell/control_flow.h" |
| 11 | #include "shader_recompiler/host_translate_info.h" | 11 | #include "shader_recompiler/host_translate_info.h" |
| 12 | #include "shader_recompiler/object_pool.h" | 12 | #include "shader_recompiler/object_pool.h" |
| 13 | #include "shader_recompiler/runtime_info.h" | ||
| 13 | 14 | ||
| 14 | namespace Shader::Maxwell { | 15 | namespace Shader::Maxwell { |
| 15 | 16 | ||
| @@ -20,4 +21,7 @@ namespace Shader::Maxwell { | |||
| 20 | [[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b, | 21 | [[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b, |
| 21 | Environment& env_vertex_b); | 22 | Environment& env_vertex_b); |
| 22 | 23 | ||
| 24 | [[nodiscard]] void ConvertLegacyToGeneric(IR::Program& program, | ||
| 25 | const Shader::RuntimeInfo& runtime_info); | ||
| 26 | |||
| 23 | } // namespace Shader::Maxwell | 27 | } // namespace Shader::Maxwell |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 1e476d83d..a78c469be 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -389,6 +389,7 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 389 | info.uses_demote_to_helper_invocation = true; | 389 | info.uses_demote_to_helper_invocation = true; |
| 390 | break; | 390 | break; |
| 391 | case IR::Opcode::GetAttribute: | 391 | case IR::Opcode::GetAttribute: |
| 392 | case IR::Opcode::GetAttributeU32: | ||
| 392 | info.loads.mask[static_cast<size_t>(inst.Arg(0).Attribute())] = true; | 393 | info.loads.mask[static_cast<size_t>(inst.Arg(0).Attribute())] = true; |
| 393 | break; | 394 | break; |
| 394 | case IR::Opcode::SetAttribute: | 395 | case IR::Opcode::SetAttribute: |
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp index d089fdd12..c134a12bc 100644 --- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp +++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp | |||
| @@ -505,6 +505,29 @@ void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) { | |||
| 505 | return; | 505 | return; |
| 506 | } | 506 | } |
| 507 | } | 507 | } |
| 508 | if constexpr (op == IR::Opcode::BitCastU32F32) { | ||
| 509 | // Workaround for new NVIDIA driver bug, where: | ||
| 510 | // uint attr = ftou(itof(gl_InstanceID)); | ||
| 511 | // always returned 0. | ||
| 512 | // We can instead manually optimize this and work around the driver bug: | ||
| 513 | // uint attr = uint(gl_InstanceID); | ||
| 514 | if (arg_inst->GetOpcode() == IR::Opcode::GetAttribute) { | ||
| 515 | const IR::Attribute attr{arg_inst->Arg(0).Attribute()}; | ||
| 516 | switch (attr) { | ||
| 517 | case IR::Attribute::PrimitiveId: | ||
| 518 | case IR::Attribute::InstanceId: | ||
| 519 | case IR::Attribute::VertexId: | ||
| 520 | break; | ||
| 521 | default: | ||
| 522 | return; | ||
| 523 | } | ||
| 524 | // Replace the bitcasts with an integer attribute get | ||
| 525 | inst.ReplaceOpcode(IR::Opcode::GetAttributeU32); | ||
| 526 | inst.SetArg(0, arg_inst->Arg(0)); | ||
| 527 | inst.SetArg(1, arg_inst->Arg(1)); | ||
| 528 | return; | ||
| 529 | } | ||
| 530 | } | ||
| 508 | } | 531 | } |
| 509 | 532 | ||
| 510 | void FoldInverseFunc(IR::Inst& inst, IR::Opcode reverse) { | 533 | void FoldInverseFunc(IR::Inst& inst, IR::Opcode reverse) { |
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index f0c3b3b17..dc4c806ff 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h | |||
| @@ -65,6 +65,10 @@ struct Profile { | |||
| 65 | bool has_gl_component_indexing_bug{}; | 65 | bool has_gl_component_indexing_bug{}; |
| 66 | /// The precise type qualifier is broken in the fragment stage of some drivers | 66 | /// The precise type qualifier is broken in the fragment stage of some drivers |
| 67 | bool has_gl_precise_bug{}; | 67 | bool has_gl_precise_bug{}; |
| 68 | /// Some drivers do not properly support floatBitsToUint when used on cbufs | ||
| 69 | bool has_gl_cbuf_ftou_bug{}; | ||
| 70 | /// Some drivers poorly optimize boolean variable references | ||
| 71 | bool has_gl_bool_ref_bug{}; | ||
| 68 | /// Ignores SPIR-V ordered vs unordered using GLSL semantics | 72 | /// Ignores SPIR-V ordered vs unordered using GLSL semantics |
| 69 | bool ignore_nan_fp_comparisons{}; | 73 | bool ignore_nan_fp_comparisons{}; |
| 70 | 74 | ||
diff --git a/src/shader_recompiler/varying_state.h b/src/shader_recompiler/varying_state.h index 9d7b24a76..bc4f273c8 100644 --- a/src/shader_recompiler/varying_state.h +++ b/src/shader_recompiler/varying_state.h | |||
| @@ -53,7 +53,8 @@ struct VaryingState { | |||
| 53 | return AnyComponent(IR::Attribute::ColorFrontDiffuseR) || | 53 | return AnyComponent(IR::Attribute::ColorFrontDiffuseR) || |
| 54 | AnyComponent(IR::Attribute::ColorFrontSpecularR) || | 54 | AnyComponent(IR::Attribute::ColorFrontSpecularR) || |
| 55 | AnyComponent(IR::Attribute::ColorBackDiffuseR) || | 55 | AnyComponent(IR::Attribute::ColorBackDiffuseR) || |
| 56 | AnyComponent(IR::Attribute::ColorBackSpecularR) || FixedFunctionTexture(); | 56 | AnyComponent(IR::Attribute::ColorBackSpecularR) || FixedFunctionTexture() || |
| 57 | mask[static_cast<size_t>(IR::Attribute::FogCoordinate)]; | ||
| 57 | } | 58 | } |
| 58 | 59 | ||
| 59 | [[nodiscard]] bool FixedFunctionTexture() const noexcept { | 60 | [[nodiscard]] bool FixedFunctionTexture() const noexcept { |
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index c4c012f3d..4a20c0768 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt | |||
| @@ -10,11 +10,12 @@ add_executable(tests | |||
| 10 | core/network/network.cpp | 10 | core/network/network.cpp |
| 11 | tests.cpp | 11 | tests.cpp |
| 12 | video_core/buffer_base.cpp | 12 | video_core/buffer_base.cpp |
| 13 | input_common/calibration_configuration_job.cpp | ||
| 13 | ) | 14 | ) |
| 14 | 15 | ||
| 15 | create_target_directory_groups(tests) | 16 | create_target_directory_groups(tests) |
| 16 | 17 | ||
| 17 | target_link_libraries(tests PRIVATE common core) | 18 | target_link_libraries(tests PRIVATE common core input_common) |
| 18 | target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads) | 19 | target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads) |
| 19 | 20 | ||
| 20 | add_test(NAME tests COMMAND tests) | 21 | add_test(NAME tests COMMAND tests) |
diff --git a/src/tests/input_common/calibration_configuration_job.cpp b/src/tests/input_common/calibration_configuration_job.cpp new file mode 100644 index 000000000..8c77d81e9 --- /dev/null +++ b/src/tests/input_common/calibration_configuration_job.cpp | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <string> | ||
| 7 | #include <thread> | ||
| 8 | #include <boost/asio.hpp> | ||
| 9 | #include <boost/crc.hpp> | ||
| 10 | #include <catch2/catch.hpp> | ||
| 11 | |||
| 12 | #include "input_common/drivers/udp_client.h" | ||
| 13 | #include "input_common/helpers/udp_protocol.h" | ||
| 14 | |||
| 15 | class FakeCemuhookServer { | ||
| 16 | public: | ||
| 17 | FakeCemuhookServer() | ||
| 18 | : socket(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)) {} | ||
| 19 | |||
| 20 | ~FakeCemuhookServer() { | ||
| 21 | is_running = false; | ||
| 22 | boost::system::error_code error_code; | ||
| 23 | socket.shutdown(boost::asio::socket_base::shutdown_both, error_code); | ||
| 24 | socket.close(); | ||
| 25 | if (handler.joinable()) { | ||
| 26 | handler.join(); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | u16 GetPort() { | ||
| 31 | return socket.local_endpoint().port(); | ||
| 32 | } | ||
| 33 | |||
| 34 | std::string GetHost() { | ||
| 35 | return socket.local_endpoint().address().to_string(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void Run(const std::vector<InputCommon::CemuhookUDP::Response::TouchPad> touch_movement_path) { | ||
| 39 | constexpr size_t HeaderSize = sizeof(InputCommon::CemuhookUDP::Header); | ||
| 40 | constexpr size_t PadDataSize = | ||
| 41 | sizeof(InputCommon::CemuhookUDP::Message<InputCommon::CemuhookUDP::Response::PadData>); | ||
| 42 | |||
| 43 | REQUIRE(touch_movement_path.size() > 0); | ||
| 44 | is_running = true; | ||
| 45 | handler = std::thread([touch_movement_path, this]() { | ||
| 46 | auto current_touch_position = touch_movement_path.begin(); | ||
| 47 | while (is_running) { | ||
| 48 | boost::asio::ip::udp::endpoint sender_endpoint; | ||
| 49 | boost::system::error_code error_code; | ||
| 50 | auto received_size = socket.receive_from(boost::asio::buffer(receive_buffer), | ||
| 51 | sender_endpoint, 0, error_code); | ||
| 52 | |||
| 53 | if (received_size < HeaderSize) { | ||
| 54 | continue; | ||
| 55 | } | ||
| 56 | |||
| 57 | InputCommon::CemuhookUDP::Header header{}; | ||
| 58 | std::memcpy(&header, receive_buffer.data(), HeaderSize); | ||
| 59 | switch (header.type) { | ||
| 60 | case InputCommon::CemuhookUDP::Type::PadData: { | ||
| 61 | InputCommon::CemuhookUDP::Response::PadData pad_data{}; | ||
| 62 | pad_data.touch[0] = *current_touch_position; | ||
| 63 | const auto pad_message = InputCommon::CemuhookUDP::CreateMessage( | ||
| 64 | InputCommon::CemuhookUDP::SERVER_MAGIC, pad_data, 0); | ||
| 65 | std::memcpy(send_buffer.data(), &pad_message, PadDataSize); | ||
| 66 | socket.send_to(boost::asio::buffer(send_buffer, PadDataSize), sender_endpoint, | ||
| 67 | 0, error_code); | ||
| 68 | |||
| 69 | bool can_advance = | ||
| 70 | std::next(current_touch_position) != touch_movement_path.end(); | ||
| 71 | if (can_advance) { | ||
| 72 | std::advance(current_touch_position, 1); | ||
| 73 | } | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | case InputCommon::CemuhookUDP::Type::PortInfo: | ||
| 77 | case InputCommon::CemuhookUDP::Type::Version: | ||
| 78 | default: | ||
| 79 | break; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | }); | ||
| 83 | } | ||
| 84 | |||
| 85 | private: | ||
| 86 | boost::asio::io_service io_service; | ||
| 87 | boost::asio::ip::udp::socket socket; | ||
| 88 | std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> send_buffer; | ||
| 89 | std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> receive_buffer; | ||
| 90 | bool is_running = false; | ||
| 91 | std::thread handler; | ||
| 92 | }; | ||
| 93 | |||
| 94 | TEST_CASE("CalibrationConfigurationJob completed", "[input_common]") { | ||
| 95 | Common::Event complete_event; | ||
| 96 | FakeCemuhookServer server; | ||
| 97 | server.Run({{ | ||
| 98 | .is_active = 1, | ||
| 99 | .x = 0, | ||
| 100 | .y = 0, | ||
| 101 | }, | ||
| 102 | { | ||
| 103 | .is_active = 1, | ||
| 104 | .x = 200, | ||
| 105 | .y = 200, | ||
| 106 | }}); | ||
| 107 | |||
| 108 | InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status{}; | ||
| 109 | u16 min_x{}; | ||
| 110 | u16 min_y{}; | ||
| 111 | u16 max_x{}; | ||
| 112 | u16 max_y{}; | ||
| 113 | InputCommon::CemuhookUDP::CalibrationConfigurationJob job( | ||
| 114 | server.GetHost(), server.GetPort(), | ||
| 115 | [&status, | ||
| 116 | &complete_event](InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status_) { | ||
| 117 | status = status_; | ||
| 118 | if (status == | ||
| 119 | InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed) { | ||
| 120 | complete_event.Set(); | ||
| 121 | } | ||
| 122 | }, | ||
| 123 | [&](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) { | ||
| 124 | min_x = min_x_; | ||
| 125 | min_y = min_y_; | ||
| 126 | max_x = max_x_; | ||
| 127 | max_y = max_y_; | ||
| 128 | }); | ||
| 129 | |||
| 130 | complete_event.WaitUntil(std::chrono::system_clock::now() + std::chrono::seconds(10)); | ||
| 131 | REQUIRE(status == InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed); | ||
| 132 | REQUIRE(min_x == 0); | ||
| 133 | REQUIRE(min_y == 0); | ||
| 134 | REQUIRE(max_x == 200); | ||
| 135 | REQUIRE(max_y == 200); | ||
| 136 | } | ||
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 2a532b883..04d0f3a2f 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp | |||
| @@ -32,7 +32,7 @@ constexpr std::array PREFERRED_GPU_DECODERS = { | |||
| 32 | #ifdef _WIN32 | 32 | #ifdef _WIN32 |
| 33 | AV_HWDEVICE_TYPE_D3D11VA, | 33 | AV_HWDEVICE_TYPE_D3D11VA, |
| 34 | AV_HWDEVICE_TYPE_DXVA2, | 34 | AV_HWDEVICE_TYPE_DXVA2, |
| 35 | #elif defined(__linux__) | 35 | #elif defined(__unix__) |
| 36 | AV_HWDEVICE_TYPE_VAAPI, | 36 | AV_HWDEVICE_TYPE_VAAPI, |
| 37 | AV_HWDEVICE_TYPE_VDPAU, | 37 | AV_HWDEVICE_TYPE_VDPAU, |
| 38 | #endif | 38 | #endif |
| @@ -130,6 +130,12 @@ bool Codec::CreateGpuAvDevice() { | |||
| 130 | } | 130 | } |
| 131 | if (config->methods & HW_CONFIG_METHOD && config->device_type == type) { | 131 | if (config->methods & HW_CONFIG_METHOD && config->device_type == type) { |
| 132 | av_codec_ctx->pix_fmt = config->pix_fmt; | 132 | av_codec_ctx->pix_fmt = config->pix_fmt; |
| 133 | if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { | ||
| 134 | // skip zero-copy decoders, we don't currently support them | ||
| 135 | LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.", | ||
| 136 | av_hwdevice_get_type_name(type), config->methods); | ||
| 137 | continue; | ||
| 138 | } | ||
| 133 | LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); | 139 | LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); |
| 134 | return true; | 140 | return true; |
| 135 | } | 141 | } |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 8788f5148..705765c99 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | #include "core/frontend/emu_window.h" | 17 | #include "core/frontend/emu_window.h" |
| 18 | #include "core/hardware_interrupt_manager.h" | 18 | #include "core/hardware_interrupt_manager.h" |
| 19 | #include "core/hle/service/nvdrv/nvdata.h" | 19 | #include "core/hle/service/nvdrv/nvdata.h" |
| 20 | #include "core/hle/service/nvflinger/buffer_queue.h" | ||
| 21 | #include "core/perf_stats.h" | 20 | #include "core/perf_stats.h" |
| 22 | #include "video_core/cdma_pusher.h" | 21 | #include "video_core/cdma_pusher.h" |
| 23 | #include "video_core/dma_pusher.h" | 22 | #include "video_core/dma_pusher.h" |
| @@ -312,6 +311,12 @@ struct GPU::Impl { | |||
| 312 | cpu_context->MakeCurrent(); | 311 | cpu_context->MakeCurrent(); |
| 313 | } | 312 | } |
| 314 | 313 | ||
| 314 | void NotifyShutdown() { | ||
| 315 | std::unique_lock lk{sync_mutex}; | ||
| 316 | shutting_down.store(true, std::memory_order::relaxed); | ||
| 317 | sync_cv.notify_all(); | ||
| 318 | } | ||
| 319 | |||
| 315 | /// Obtain the CPU Context | 320 | /// Obtain the CPU Context |
| 316 | void ObtainContext() { | 321 | void ObtainContext() { |
| 317 | cpu_context->MakeCurrent(); | 322 | cpu_context->MakeCurrent(); |
| @@ -859,6 +864,10 @@ void GPU::Start() { | |||
| 859 | impl->Start(); | 864 | impl->Start(); |
| 860 | } | 865 | } |
| 861 | 866 | ||
| 867 | void GPU::NotifyShutdown() { | ||
| 868 | impl->NotifyShutdown(); | ||
| 869 | } | ||
| 870 | |||
| 862 | void GPU::ObtainContext() { | 871 | void GPU::ObtainContext() { |
| 863 | impl->ObtainContext(); | 872 | impl->ObtainContext(); |
| 864 | } | 873 | } |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 500411176..3188b83ed 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -232,6 +232,9 @@ public: | |||
| 232 | /// core timing events. | 232 | /// core timing events. |
| 233 | void Start(); | 233 | void Start(); |
| 234 | 234 | ||
| 235 | /// Performs any additional necessary steps to shutdown GPU emulation. | ||
| 236 | void NotifyShutdown(); | ||
| 237 | |||
| 235 | /// Obtain the CPU Context | 238 | /// Obtain the CPU Context |
| 236 | void ObtainContext(); | 239 | void ObtainContext(); |
| 237 | 240 | ||
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 0764ea6e0..e62912a22 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -182,17 +182,13 @@ Device::Device() { | |||
| 182 | shader_backend = Settings::ShaderBackend::GLSL; | 182 | shader_backend = Settings::ShaderBackend::GLSL; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia && | 185 | if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia) { |
| 186 | !Settings::values.renderer_debug) { | ||
| 187 | const std::string_view driver_version = version.substr(13); | 186 | const std::string_view driver_version = version.substr(13); |
| 188 | const int version_major = | 187 | const int version_major = |
| 189 | std::atoi(driver_version.substr(0, driver_version.find(".")).data()); | 188 | std::atoi(driver_version.substr(0, driver_version.find(".")).data()); |
| 190 | |||
| 191 | if (version_major >= 495) { | 189 | if (version_major >= 495) { |
| 192 | LOG_WARNING(Render_OpenGL, "NVIDIA drivers 495 and later causes significant problems " | 190 | has_cbuf_ftou_bug = true; |
| 193 | "with yuzu. Forcing GLASM as a mitigation."); | 191 | has_bool_ref_bug = true; |
| 194 | shader_backend = Settings::ShaderBackend::GLASM; | ||
| 195 | use_assembly_shaders = true; | ||
| 196 | } | 192 | } |
| 197 | } | 193 | } |
| 198 | 194 | ||
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index de9e41659..95c2e8d38 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -152,6 +152,14 @@ public: | |||
| 152 | return need_fastmath_off; | 152 | return need_fastmath_off; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | bool HasCbufFtouBug() const { | ||
| 156 | return has_cbuf_ftou_bug; | ||
| 157 | } | ||
| 158 | |||
| 159 | bool HasBoolRefBug() const { | ||
| 160 | return has_bool_ref_bug; | ||
| 161 | } | ||
| 162 | |||
| 155 | Settings::ShaderBackend GetShaderBackend() const { | 163 | Settings::ShaderBackend GetShaderBackend() const { |
| 156 | return shader_backend; | 164 | return shader_backend; |
| 157 | } | 165 | } |
| @@ -200,6 +208,8 @@ private: | |||
| 200 | bool has_sparse_texture_2{}; | 208 | bool has_sparse_texture_2{}; |
| 201 | bool warp_size_potentially_larger_than_guest{}; | 209 | bool warp_size_potentially_larger_than_guest{}; |
| 202 | bool need_fastmath_off{}; | 210 | bool need_fastmath_off{}; |
| 211 | bool has_cbuf_ftou_bug{}; | ||
| 212 | bool has_bool_ref_bug{}; | ||
| 203 | 213 | ||
| 204 | std::string vendor_name; | 214 | std::string vendor_name; |
| 205 | }; | 215 | }; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 42ef67628..f71e01a34 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -42,6 +42,7 @@ namespace { | |||
| 42 | using Shader::Backend::GLASM::EmitGLASM; | 42 | using Shader::Backend::GLASM::EmitGLASM; |
| 43 | using Shader::Backend::GLSL::EmitGLSL; | 43 | using Shader::Backend::GLSL::EmitGLSL; |
| 44 | using Shader::Backend::SPIRV::EmitSPIRV; | 44 | using Shader::Backend::SPIRV::EmitSPIRV; |
| 45 | using Shader::Maxwell::ConvertLegacyToGeneric; | ||
| 45 | using Shader::Maxwell::MergeDualVertexPrograms; | 46 | using Shader::Maxwell::MergeDualVertexPrograms; |
| 46 | using Shader::Maxwell::TranslateProgram; | 47 | using Shader::Maxwell::TranslateProgram; |
| 47 | using VideoCommon::ComputeEnvironment; | 48 | using VideoCommon::ComputeEnvironment; |
| @@ -213,6 +214,8 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 213 | .has_broken_fp16_float_controls = false, | 214 | .has_broken_fp16_float_controls = false, |
| 214 | .has_gl_component_indexing_bug = device.HasComponentIndexingBug(), | 215 | .has_gl_component_indexing_bug = device.HasComponentIndexingBug(), |
| 215 | .has_gl_precise_bug = device.HasPreciseBug(), | 216 | .has_gl_precise_bug = device.HasPreciseBug(), |
| 217 | .has_gl_cbuf_ftou_bug = device.HasCbufFtouBug(), | ||
| 218 | .has_gl_bool_ref_bug = device.HasBoolRefBug(), | ||
| 216 | .ignore_nan_fp_comparisons = true, | 219 | .ignore_nan_fp_comparisons = true, |
| 217 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), | 220 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), |
| 218 | }, | 221 | }, |
| @@ -422,6 +425,11 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( | |||
| 422 | 425 | ||
| 423 | const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; | 426 | const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; |
| 424 | Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); | 427 | Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); |
| 428 | |||
| 429 | if (Settings::values.dump_shaders) { | ||
| 430 | env.Dump(key.unique_hashes[index]); | ||
| 431 | } | ||
| 432 | |||
| 425 | if (!uses_vertex_a || index != 1) { | 433 | if (!uses_vertex_a || index != 1) { |
| 426 | // Normal path | 434 | // Normal path |
| 427 | programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info); | 435 | programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info); |
| @@ -462,12 +470,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( | |||
| 462 | MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm)}; | 470 | MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm)}; |
| 463 | switch (device.GetShaderBackend()) { | 471 | switch (device.GetShaderBackend()) { |
| 464 | case Settings::ShaderBackend::GLSL: | 472 | case Settings::ShaderBackend::GLSL: |
| 473 | ConvertLegacyToGeneric(program, runtime_info); | ||
| 465 | sources[stage_index] = EmitGLSL(profile, runtime_info, program, binding); | 474 | sources[stage_index] = EmitGLSL(profile, runtime_info, program, binding); |
| 466 | break; | 475 | break; |
| 467 | case Settings::ShaderBackend::GLASM: | 476 | case Settings::ShaderBackend::GLASM: |
| 468 | sources[stage_index] = EmitGLASM(profile, runtime_info, program, binding); | 477 | sources[stage_index] = EmitGLASM(profile, runtime_info, program, binding); |
| 469 | break; | 478 | break; |
| 470 | case Settings::ShaderBackend::SPIRV: | 479 | case Settings::ShaderBackend::SPIRV: |
| 480 | ConvertLegacyToGeneric(program, runtime_info); | ||
| 471 | sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding); | 481 | sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding); |
| 472 | break; | 482 | break; |
| 473 | } | 483 | } |
| @@ -506,8 +516,12 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline( | |||
| 506 | LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash()); | 516 | LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash()); |
| 507 | 517 | ||
| 508 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | 518 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| 509 | auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; | ||
| 510 | 519 | ||
| 520 | if (Settings::values.dump_shaders) { | ||
| 521 | env.Dump(key.Hash()); | ||
| 522 | } | ||
| 523 | |||
| 524 | auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; | ||
| 511 | const u32 num_storage_buffers{Shader::NumDescriptors(program.info.storage_buffers_descriptors)}; | 525 | const u32 num_storage_buffers{Shader::NumDescriptors(program.info.storage_buffers_descriptors)}; |
| 512 | Shader::RuntimeInfo info; | 526 | Shader::RuntimeInfo info; |
| 513 | info.glasm_use_storage_buffers = num_storage_buffers <= device.GetMaxGLASMStorageBufferBlocks(); | 527 | info.glasm_use_storage_buffers = num_storage_buffers <= device.GetMaxGLASMStorageBufferBlocks(); |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 14e6522f2..3c1f79a27 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -1047,7 +1047,7 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1047 | } | 1047 | } |
| 1048 | 1048 | ||
| 1049 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | 1049 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, |
| 1050 | ImageId image_id_, Image& image) | 1050 | ImageId image_id_, Image& image, const SlotVector<Image>&) |
| 1051 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { | 1051 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} { |
| 1052 | const Device& device = runtime.device; | 1052 | const Device& device = runtime.device; |
| 1053 | if (True(image.flags & ImageFlagBits::Converted)) { | 1053 | if (True(image.flags & ImageFlagBits::Converted)) { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 37d5e6a6b..7f425631f 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -36,6 +36,7 @@ using VideoCommon::ImageViewType; | |||
| 36 | using VideoCommon::NUM_RT; | 36 | using VideoCommon::NUM_RT; |
| 37 | using VideoCommon::Region2D; | 37 | using VideoCommon::Region2D; |
| 38 | using VideoCommon::RenderTargets; | 38 | using VideoCommon::RenderTargets; |
| 39 | using VideoCommon::SlotVector; | ||
| 39 | 40 | ||
| 40 | struct ImageBufferMap { | 41 | struct ImageBufferMap { |
| 41 | ~ImageBufferMap(); | 42 | ~ImageBufferMap(); |
| @@ -92,7 +93,7 @@ public: | |||
| 92 | 93 | ||
| 93 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 94 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 94 | 95 | ||
| 95 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) { | 96 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { |
| 96 | UNIMPLEMENTED(); | 97 | UNIMPLEMENTED(); |
| 97 | } | 98 | } |
| 98 | 99 | ||
| @@ -234,7 +235,8 @@ class ImageView : public VideoCommon::ImageViewBase { | |||
| 234 | friend Image; | 235 | friend Image; |
| 235 | 236 | ||
| 236 | public: | 237 | public: |
| 237 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); | 238 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&, |
| 239 | const SlotVector<Image>&); | ||
| 238 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, | 240 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, |
| 239 | const VideoCommon::ImageViewInfo&, GPUVAddr); | 241 | const VideoCommon::ImageViewInfo&, GPUVAddr); |
| 240 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 242 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 28daacd82..f81c1b233 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -437,39 +437,29 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 437 | 437 | ||
| 438 | glBindTextureUnit(0, fxaa_texture.handle); | 438 | glBindTextureUnit(0, fxaa_texture.handle); |
| 439 | } | 439 | } |
| 440 | |||
| 441 | // Set projection matrix | ||
| 442 | const std::array ortho_matrix = | 440 | const std::array ortho_matrix = |
| 443 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); | 441 | MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height)); |
| 444 | 442 | ||
| 445 | GLuint fragment_handle; | 443 | const auto fragment_handle = [this]() { |
| 446 | const auto filter = Settings::values.scaling_filter.GetValue(); | 444 | switch (Settings::values.scaling_filter.GetValue()) { |
| 447 | switch (filter) { | 445 | case Settings::ScalingFilter::NearestNeighbor: |
| 448 | case Settings::ScalingFilter::NearestNeighbor: | 446 | case Settings::ScalingFilter::Bilinear: |
| 449 | fragment_handle = present_bilinear_fragment.handle; | 447 | return present_bilinear_fragment.handle; |
| 450 | break; | 448 | case Settings::ScalingFilter::Bicubic: |
| 451 | case Settings::ScalingFilter::Bilinear: | 449 | return present_bicubic_fragment.handle; |
| 452 | fragment_handle = present_bilinear_fragment.handle; | 450 | case Settings::ScalingFilter::Gaussian: |
| 453 | break; | 451 | return present_gaussian_fragment.handle; |
| 454 | case Settings::ScalingFilter::Bicubic: | 452 | case Settings::ScalingFilter::ScaleForce: |
| 455 | fragment_handle = present_bicubic_fragment.handle; | 453 | return present_scaleforce_fragment.handle; |
| 456 | break; | 454 | case Settings::ScalingFilter::Fsr: |
| 457 | case Settings::ScalingFilter::Gaussian: | 455 | LOG_WARNING( |
| 458 | fragment_handle = present_gaussian_fragment.handle; | 456 | Render_OpenGL, |
| 459 | break; | 457 | "FidelityFX Super Resolution is not supported in OpenGL, changing to ScaleForce"); |
| 460 | case Settings::ScalingFilter::ScaleForce: | 458 | return present_scaleforce_fragment.handle; |
| 461 | fragment_handle = present_scaleforce_fragment.handle; | 459 | default: |
| 462 | break; | 460 | return present_bilinear_fragment.handle; |
| 463 | case Settings::ScalingFilter::Fsr: | 461 | } |
| 464 | LOG_WARNING( | 462 | }(); |
| 465 | Render_OpenGL, | ||
| 466 | "FidelityFX FSR Super Sampling is not supported in OpenGL, changing to ScaleForce"); | ||
| 467 | fragment_handle = present_scaleforce_fragment.handle; | ||
| 468 | break; | ||
| 469 | default: | ||
| 470 | fragment_handle = present_bilinear_fragment.handle; | ||
| 471 | break; | ||
| 472 | } | ||
| 473 | program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle); | 463 | program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle); |
| 474 | glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, | 464 | glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE, |
| 475 | ortho_matrix.data()); | 465 | ortho_matrix.data()); |
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 9a38b6b34..2c3914459 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | 6 | ||
| 7 | #include "common/settings.h" | ||
| 7 | #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" | 8 | #include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h" |
| 8 | #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" | 9 | #include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h" |
| 9 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" | 10 | #include "video_core/host_shaders/convert_depth_to_float_frag_spv.h" |
| @@ -335,6 +336,17 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi | |||
| 335 | cmdbuf.SetScissor(0, scissor); | 336 | cmdbuf.SetScissor(0, scissor); |
| 336 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); | 337 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); |
| 337 | } | 338 | } |
| 339 | |||
| 340 | VkExtent2D GetConversionExtent(const ImageView& src_image_view) { | ||
| 341 | const auto& resolution = Settings::values.resolution_info; | ||
| 342 | const bool is_rescaled = src_image_view.IsRescaled(); | ||
| 343 | u32 width = src_image_view.size.width; | ||
| 344 | u32 height = src_image_view.size.height; | ||
| 345 | return VkExtent2D{ | ||
| 346 | .width = is_rescaled ? resolution.ScaleUp(width) : width, | ||
| 347 | .height = is_rescaled ? resolution.ScaleUp(height) : height, | ||
| 348 | }; | ||
| 349 | } | ||
| 338 | } // Anonymous namespace | 350 | } // Anonymous namespace |
| 339 | 351 | ||
| 340 | BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, | 352 | BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_, |
| @@ -425,108 +437,52 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, | |||
| 425 | } | 437 | } |
| 426 | 438 | ||
| 427 | void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer, | 439 | void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer, |
| 428 | const ImageView& src_image_view, u32 up_scale, | 440 | const ImageView& src_image_view) { |
| 429 | u32 down_shift) { | ||
| 430 | ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass()); | 441 | ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass()); |
| 431 | Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); | 442 | Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view); |
| 432 | } | 443 | } |
| 433 | 444 | ||
| 434 | void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer, | 445 | void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer, |
| 435 | const ImageView& src_image_view, u32 up_scale, | 446 | const ImageView& src_image_view) { |
| 436 | u32 down_shift) { | ||
| 437 | ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass()); | 447 | ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass()); |
| 438 | Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); | 448 | Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view); |
| 439 | } | 449 | } |
| 440 | 450 | ||
| 441 | void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer, | 451 | void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer, |
| 442 | const ImageView& src_image_view, u32 up_scale, | 452 | const ImageView& src_image_view) { |
| 443 | u32 down_shift) { | ||
| 444 | ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass()); | 453 | ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass()); |
| 445 | Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); | 454 | Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view); |
| 446 | } | 455 | } |
| 447 | 456 | ||
| 448 | void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, | 457 | void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, |
| 449 | const ImageView& src_image_view, u32 up_scale, | 458 | const ImageView& src_image_view) { |
| 450 | u32 down_shift) { | ||
| 451 | ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass()); | 459 | ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass()); |
| 452 | Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift); | 460 | Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view); |
| 453 | } | 461 | } |
| 454 | 462 | ||
| 455 | void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, | 463 | void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, |
| 456 | ImageView& src_image_view, u32 up_scale, u32 down_shift) { | 464 | const ImageView& src_image_view) { |
| 457 | ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), | 465 | ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(), |
| 458 | convert_abgr8_to_d24s8_frag, true); | 466 | convert_abgr8_to_d24s8_frag); |
| 459 | ConvertColor(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale, | 467 | Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view); |
| 460 | down_shift); | ||
| 461 | } | 468 | } |
| 462 | 469 | ||
| 463 | void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, | 470 | void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, |
| 464 | ImageView& src_image_view, u32 up_scale, u32 down_shift) { | 471 | ImageView& src_image_view) { |
| 465 | ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), | 472 | ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(), |
| 466 | convert_d24s8_to_abgr8_frag, false); | 473 | convert_d24s8_to_abgr8_frag); |
| 467 | ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale, | 474 | ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view); |
| 468 | down_shift); | ||
| 469 | } | 475 | } |
| 470 | 476 | ||
| 471 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 477 | void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 472 | const ImageView& src_image_view, u32 up_scale, u32 down_shift) { | 478 | const ImageView& src_image_view) { |
| 473 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | 479 | const VkPipelineLayout layout = *one_texture_pipeline_layout; |
| 474 | const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); | 480 | const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); |
| 475 | const VkSampler sampler = *nearest_sampler; | 481 | const VkSampler sampler = *nearest_sampler; |
| 476 | const VkExtent2D extent{ | 482 | const VkExtent2D extent = GetConversionExtent(src_image_view); |
| 477 | .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U), | ||
| 478 | .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U), | ||
| 479 | }; | ||
| 480 | scheduler.RequestRenderpass(dst_framebuffer); | ||
| 481 | scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift, | ||
| 482 | this](vk::CommandBuffer cmdbuf) { | ||
| 483 | const VkOffset2D offset{ | ||
| 484 | .x = 0, | ||
| 485 | .y = 0, | ||
| 486 | }; | ||
| 487 | const VkViewport viewport{ | ||
| 488 | .x = 0.0f, | ||
| 489 | .y = 0.0f, | ||
| 490 | .width = static_cast<float>(extent.width), | ||
| 491 | .height = static_cast<float>(extent.height), | ||
| 492 | .minDepth = 0.0f, | ||
| 493 | .maxDepth = 0.0f, | ||
| 494 | }; | ||
| 495 | const VkRect2D scissor{ | ||
| 496 | .offset = offset, | ||
| 497 | .extent = extent, | ||
| 498 | }; | ||
| 499 | const PushConstants push_constants{ | ||
| 500 | .tex_scale = {viewport.width, viewport.height}, | ||
| 501 | .tex_offset = {0.0f, 0.0f}, | ||
| 502 | }; | ||
| 503 | const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); | ||
| 504 | UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view); | ||
| 505 | |||
| 506 | // TODO: Barriers | ||
| 507 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | ||
| 508 | cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set, | ||
| 509 | nullptr); | ||
| 510 | cmdbuf.SetViewport(0, viewport); | ||
| 511 | cmdbuf.SetScissor(0, scissor); | ||
| 512 | cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants); | ||
| 513 | cmdbuf.Draw(3, 1, 0, 0); | ||
| 514 | }); | ||
| 515 | scheduler.InvalidateState(); | ||
| 516 | } | ||
| 517 | 483 | ||
| 518 | void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 519 | ImageView& src_image_view, u32 up_scale, u32 down_shift) { | ||
| 520 | const VkPipelineLayout layout = *one_texture_pipeline_layout; | ||
| 521 | const VkImageView src_view = src_image_view.ColorView(); | ||
| 522 | const VkSampler sampler = *nearest_sampler; | ||
| 523 | const VkExtent2D extent{ | ||
| 524 | .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U), | ||
| 525 | .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U), | ||
| 526 | }; | ||
| 527 | scheduler.RequestRenderpass(dst_framebuffer); | 484 | scheduler.RequestRenderpass(dst_framebuffer); |
| 528 | scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift, | 485 | scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) { |
| 529 | this](vk::CommandBuffer cmdbuf) { | ||
| 530 | const VkOffset2D offset{ | 486 | const VkOffset2D offset{ |
| 531 | .x = 0, | 487 | .x = 0, |
| 532 | .y = 0, | 488 | .y = 0, |
| @@ -563,18 +519,16 @@ void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_f | |||
| 563 | } | 519 | } |
| 564 | 520 | ||
| 565 | void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 521 | void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 566 | ImageView& src_image_view, u32 up_scale, u32 down_shift) { | 522 | ImageView& src_image_view) { |
| 567 | const VkPipelineLayout layout = *two_textures_pipeline_layout; | 523 | const VkPipelineLayout layout = *two_textures_pipeline_layout; |
| 568 | const VkImageView src_depth_view = src_image_view.DepthView(); | 524 | const VkImageView src_depth_view = src_image_view.DepthView(); |
| 569 | const VkImageView src_stencil_view = src_image_view.StencilView(); | 525 | const VkImageView src_stencil_view = src_image_view.StencilView(); |
| 570 | const VkSampler sampler = *nearest_sampler; | 526 | const VkSampler sampler = *nearest_sampler; |
| 571 | const VkExtent2D extent{ | 527 | const VkExtent2D extent = GetConversionExtent(src_image_view); |
| 572 | .width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U), | 528 | |
| 573 | .height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U), | ||
| 574 | }; | ||
| 575 | scheduler.RequestRenderpass(dst_framebuffer); | 529 | scheduler.RequestRenderpass(dst_framebuffer); |
| 576 | scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale, | 530 | scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, |
| 577 | down_shift, this](vk::CommandBuffer cmdbuf) { | 531 | this](vk::CommandBuffer cmdbuf) { |
| 578 | const VkOffset2D offset{ | 532 | const VkOffset2D offset{ |
| 579 | .x = 0, | 533 | .x = 0, |
| 580 | .y = 0, | 534 | .y = 0, |
| @@ -695,11 +649,14 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip | |||
| 695 | return *blit_depth_stencil_pipelines.back(); | 649 | return *blit_depth_stencil_pipelines.back(); |
| 696 | } | 650 | } |
| 697 | 651 | ||
| 698 | void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { | 652 | void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 653 | bool is_target_depth) { | ||
| 699 | if (pipeline) { | 654 | if (pipeline) { |
| 700 | return; | 655 | return; |
| 701 | } | 656 | } |
| 702 | const std::array stages = MakeStages(*full_screen_vert, *convert_depth_to_float_frag); | 657 | VkShaderModule frag_shader = |
| 658 | is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag; | ||
| 659 | const std::array stages = MakeStages(*full_screen_vert, frag_shader); | ||
| 703 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | 660 | pipeline = device.GetLogical().CreateGraphicsPipeline({ |
| 704 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 661 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| 705 | .pNext = nullptr, | 662 | .pNext = nullptr, |
| @@ -712,8 +669,9 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend | |||
| 712 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | 669 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| 713 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | 670 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, |
| 714 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | 671 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| 715 | .pDepthStencilState = nullptr, | 672 | .pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr, |
| 716 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, | 673 | .pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO |
| 674 | : &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO, | ||
| 717 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | 675 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, |
| 718 | .layout = *one_texture_pipeline_layout, | 676 | .layout = *one_texture_pipeline_layout, |
| 719 | .renderPass = renderpass, | 677 | .renderPass = renderpass, |
| @@ -723,37 +681,17 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend | |||
| 723 | }); | 681 | }); |
| 724 | } | 682 | } |
| 725 | 683 | ||
| 684 | void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { | ||
| 685 | ConvertPipeline(pipeline, renderpass, false); | ||
| 686 | } | ||
| 687 | |||
| 726 | void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { | 688 | void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) { |
| 727 | if (pipeline) { | 689 | ConvertPipeline(pipeline, renderpass, true); |
| 728 | return; | ||
| 729 | } | ||
| 730 | const std::array stages = MakeStages(*full_screen_vert, *convert_float_to_depth_frag); | ||
| 731 | pipeline = device.GetLogical().CreateGraphicsPipeline({ | ||
| 732 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | ||
| 733 | .pNext = nullptr, | ||
| 734 | .flags = 0, | ||
| 735 | .stageCount = static_cast<u32>(stages.size()), | ||
| 736 | .pStages = stages.data(), | ||
| 737 | .pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | ||
| 738 | .pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | ||
| 739 | .pTessellationState = nullptr, | ||
| 740 | .pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 741 | .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | ||
| 742 | .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | ||
| 743 | .pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | ||
| 744 | .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO, | ||
| 745 | .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| 746 | .layout = *one_texture_pipeline_layout, | ||
| 747 | .renderPass = renderpass, | ||
| 748 | .subpass = 0, | ||
| 749 | .basePipelineHandle = VK_NULL_HANDLE, | ||
| 750 | .basePipelineIndex = 0, | ||
| 751 | }); | ||
| 752 | } | 690 | } |
| 753 | 691 | ||
| 754 | void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 692 | void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 755 | vk::ShaderModule& module, bool is_target_depth, | 693 | vk::ShaderModule& module, bool single_texture, |
| 756 | bool single_texture) { | 694 | bool is_target_depth) { |
| 757 | if (pipeline) { | 695 | if (pipeline) { |
| 758 | return; | 696 | return; |
| 759 | } | 697 | } |
| @@ -782,13 +720,13 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren | |||
| 782 | } | 720 | } |
| 783 | 721 | ||
| 784 | void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 722 | void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 785 | vk::ShaderModule& module, bool single_texture) { | 723 | vk::ShaderModule& module) { |
| 786 | ConvertPipelineEx(pipeline, renderpass, module, false, single_texture); | 724 | ConvertPipelineEx(pipeline, renderpass, module, false, false); |
| 787 | } | 725 | } |
| 788 | 726 | ||
| 789 | void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 727 | void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 790 | vk::ShaderModule& module, bool single_texture) { | 728 | vk::ShaderModule& module) { |
| 791 | ConvertPipelineEx(pipeline, renderpass, module, true, single_texture); | 729 | ConvertPipelineEx(pipeline, renderpass, module, true, true); |
| 792 | } | 730 | } |
| 793 | 731 | ||
| 794 | } // namespace Vulkan | 732 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h index b1a717090..85e7dca5b 100644 --- a/src/video_core/renderer_vulkan/blit_image.h +++ b/src/video_core/renderer_vulkan/blit_image.h | |||
| @@ -44,50 +44,43 @@ public: | |||
| 44 | const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, | 44 | const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, |
| 45 | Tegra::Engines::Fermi2D::Operation operation); | 45 | Tegra::Engines::Fermi2D::Operation operation); |
| 46 | 46 | ||
| 47 | void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 47 | void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); |
| 48 | u32 up_scale, u32 down_shift); | ||
| 49 | 48 | ||
| 50 | void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 49 | void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); |
| 51 | u32 up_scale, u32 down_shift); | ||
| 52 | 50 | ||
| 53 | void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 51 | void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); |
| 54 | u32 up_scale, u32 down_shift); | ||
| 55 | 52 | ||
| 56 | void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, | 53 | void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); |
| 57 | u32 up_scale, u32 down_shift); | ||
| 58 | 54 | ||
| 59 | void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, | 55 | void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); |
| 60 | u32 up_scale, u32 down_shift); | ||
| 61 | 56 | ||
| 62 | void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view, | 57 | void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view); |
| 63 | u32 up_scale, u32 down_shift); | ||
| 64 | 58 | ||
| 65 | private: | 59 | private: |
| 66 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 60 | void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 67 | const ImageView& src_image_view, u32 up_scale, u32 down_shift); | 61 | const ImageView& src_image_view); |
| 68 | |||
| 69 | void ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | ||
| 70 | ImageView& src_image_view, u32 up_scale, u32 down_shift); | ||
| 71 | 62 | ||
| 72 | void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, | 63 | void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, |
| 73 | ImageView& src_image_view, u32 up_scale, u32 down_shift); | 64 | ImageView& src_image_view); |
| 74 | 65 | ||
| 75 | [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key); | 66 | [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key); |
| 76 | 67 | ||
| 77 | [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); | 68 | [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key); |
| 78 | 69 | ||
| 70 | void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth); | ||
| 71 | |||
| 79 | void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | 72 | void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); |
| 80 | 73 | ||
| 81 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); | 74 | void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass); |
| 82 | 75 | ||
| 83 | void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 76 | void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 84 | vk::ShaderModule& module, bool is_target_depth, bool single_texture); | 77 | vk::ShaderModule& module, bool single_texture, bool is_target_depth); |
| 85 | 78 | ||
| 86 | void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 79 | void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 87 | vk::ShaderModule& module, bool single_texture); | 80 | vk::ShaderModule& module); |
| 88 | 81 | ||
| 89 | void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, | 82 | void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass, |
| 90 | vk::ShaderModule& module, bool single_texture); | 83 | vk::ShaderModule& module); |
| 91 | 84 | ||
| 92 | const Device& device; | 85 | const Device& device; |
| 93 | VKScheduler& scheduler; | 86 | VKScheduler& scheduler; |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 1e447e621..c71a1f44d 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -391,28 +391,23 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 391 | .offset = {0, 0}, | 391 | .offset = {0, 0}, |
| 392 | .extent = size, | 392 | .extent = size, |
| 393 | }; | 393 | }; |
| 394 | const auto filter = Settings::values.scaling_filter.GetValue(); | ||
| 395 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); | 394 | cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); |
| 396 | switch (filter) { | 395 | auto graphics_pipeline = [this]() { |
| 397 | case Settings::ScalingFilter::NearestNeighbor: | 396 | switch (Settings::values.scaling_filter.GetValue()) { |
| 398 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline); | 397 | case Settings::ScalingFilter::NearestNeighbor: |
| 399 | break; | 398 | case Settings::ScalingFilter::Bilinear: |
| 400 | case Settings::ScalingFilter::Bilinear: | 399 | return *bilinear_pipeline; |
| 401 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline); | 400 | case Settings::ScalingFilter::Bicubic: |
| 402 | break; | 401 | return *bicubic_pipeline; |
| 403 | case Settings::ScalingFilter::Bicubic: | 402 | case Settings::ScalingFilter::Gaussian: |
| 404 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bicubic_pipeline); | 403 | return *gaussian_pipeline; |
| 405 | break; | 404 | case Settings::ScalingFilter::ScaleForce: |
| 406 | case Settings::ScalingFilter::Gaussian: | 405 | return *scaleforce_pipeline; |
| 407 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *gaussian_pipeline); | 406 | default: |
| 408 | break; | 407 | return *bilinear_pipeline; |
| 409 | case Settings::ScalingFilter::ScaleForce: | 408 | } |
| 410 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *scaleforce_pipeline); | 409 | }(); |
| 411 | break; | 410 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); |
| 412 | default: | ||
| 413 | cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline); | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | cmdbuf.SetViewport(0, viewport); | 411 | cmdbuf.SetViewport(0, viewport); |
| 417 | cmdbuf.SetScissor(0, scissor); | 412 | cmdbuf.SetScissor(0, scissor); |
| 418 | 413 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 616a7b457..d514b71d0 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -605,7 +605,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 605 | .flags = 0, | 605 | .flags = 0, |
| 606 | .topology = input_assembly_topology, | 606 | .topology = input_assembly_topology, |
| 607 | .primitiveRestartEnable = key.state.primitive_restart_enable != 0 && | 607 | .primitiveRestartEnable = key.state.primitive_restart_enable != 0 && |
| 608 | SupportsPrimitiveRestart(input_assembly_topology), | 608 | ((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && |
| 609 | device.IsTopologyListPrimitiveRestartSupported()) || | ||
| 610 | SupportsPrimitiveRestart(input_assembly_topology) || | ||
| 611 | (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && | ||
| 612 | device.IsPatchListPrimitiveRestartSupported())), | ||
| 609 | }; | 613 | }; |
| 610 | const VkPipelineTessellationStateCreateInfo tessellation_ci{ | 614 | const VkPipelineTessellationStateCreateInfo tessellation_ci{ |
| 611 | .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, | 615 | .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, |
| @@ -613,7 +617,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 613 | .flags = 0, | 617 | .flags = 0, |
| 614 | .patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1, | 618 | .patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1, |
| 615 | }; | 619 | }; |
| 616 | |||
| 617 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; | 620 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; |
| 618 | std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); | 621 | std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); |
| 619 | const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | 622 | const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ |
| @@ -748,8 +751,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 748 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | 751 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| 749 | .pNext = nullptr, | 752 | .pNext = nullptr, |
| 750 | .flags = 0, | 753 | .flags = 0, |
| 751 | .logicOpEnable = VK_FALSE, | 754 | .logicOpEnable = key.state.logic_op_enable != 0, |
| 752 | .logicOp = VK_LOGIC_OP_COPY, | 755 | .logicOp = static_cast<VkLogicOp>(key.state.logic_op.Value()), |
| 753 | .attachmentCount = static_cast<u32>(cb_attachments.size()), | 756 | .attachmentCount = static_cast<u32>(cb_attachments.size()), |
| 754 | .pAttachments = cb_attachments.data(), | 757 | .pAttachments = cb_attachments.data(), |
| 755 | .blendConstants = {}, | 758 | .blendConstants = {}, |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index eb8b4e08b..a633b73e5 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -48,6 +48,7 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache); | |||
| 48 | 48 | ||
| 49 | namespace { | 49 | namespace { |
| 50 | using Shader::Backend::SPIRV::EmitSPIRV; | 50 | using Shader::Backend::SPIRV::EmitSPIRV; |
| 51 | using Shader::Maxwell::ConvertLegacyToGeneric; | ||
| 51 | using Shader::Maxwell::MergeDualVertexPrograms; | 52 | using Shader::Maxwell::MergeDualVertexPrograms; |
| 52 | using Shader::Maxwell::TranslateProgram; | 53 | using Shader::Maxwell::TranslateProgram; |
| 53 | using VideoCommon::ComputeEnvironment; | 54 | using VideoCommon::ComputeEnvironment; |
| @@ -516,6 +517,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 516 | 517 | ||
| 517 | const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; | 518 | const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))}; |
| 518 | Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); | 519 | Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0); |
| 520 | if (Settings::values.dump_shaders) { | ||
| 521 | env.Dump(key.unique_hashes[index]); | ||
| 522 | } | ||
| 519 | if (!uses_vertex_a || index != 1) { | 523 | if (!uses_vertex_a || index != 1) { |
| 520 | // Normal path | 524 | // Normal path |
| 521 | programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info); | 525 | programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info); |
| @@ -543,6 +547,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 543 | infos[stage_index] = &program.info; | 547 | infos[stage_index] = &program.info; |
| 544 | 548 | ||
| 545 | const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)}; | 549 | const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)}; |
| 550 | ConvertLegacyToGeneric(program, runtime_info); | ||
| 546 | const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)}; | 551 | const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)}; |
| 547 | device.SaveShader(code); | 552 | device.SaveShader(code); |
| 548 | modules[stage_index] = BuildShader(device, code); | 553 | modules[stage_index] = BuildShader(device, code); |
| @@ -611,6 +616,12 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( | |||
| 611 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); | 616 | LOG_INFO(Render_Vulkan, "0x{:016x}", key.Hash()); |
| 612 | 617 | ||
| 613 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | 618 | Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; |
| 619 | |||
| 620 | // Dump it before error. | ||
| 621 | if (Settings::values.dump_shaders) { | ||
| 622 | env.Dump(key.Hash()); | ||
| 623 | } | ||
| 624 | |||
| 614 | auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; | 625 | auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; |
| 615 | const std::vector<u32> code{EmitSPIRV(profile, program)}; | 626 | const std::vector<u32> code{EmitSPIRV(profile, program)}; |
| 616 | device.SaveShader(code); | 627 | device.SaveShader(code); |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 197cba8e3..0ba56ff1e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -1057,37 +1057,37 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst | |||
| 1057 | }); | 1057 | }); |
| 1058 | } | 1058 | } |
| 1059 | 1059 | ||
| 1060 | void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, | 1060 | void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { |
| 1061 | bool rescaled) { | ||
| 1062 | const u32 up_scale = rescaled ? resolution.up_scale : 1; | ||
| 1063 | const u32 down_shift = rescaled ? resolution.down_shift : 0; | ||
| 1064 | switch (dst_view.format) { | 1061 | switch (dst_view.format) { |
| 1065 | case PixelFormat::R16_UNORM: | 1062 | case PixelFormat::R16_UNORM: |
| 1066 | if (src_view.format == PixelFormat::D16_UNORM) { | 1063 | if (src_view.format == PixelFormat::D16_UNORM) { |
| 1067 | return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift); | 1064 | return blit_image_helper.ConvertD16ToR16(dst, src_view); |
| 1068 | } | 1065 | } |
| 1069 | break; | 1066 | break; |
| 1070 | case PixelFormat::A8B8G8R8_UNORM: | 1067 | case PixelFormat::A8B8G8R8_UNORM: |
| 1071 | if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { | 1068 | if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) { |
| 1072 | return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift); | 1069 | return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view); |
| 1073 | } | 1070 | } |
| 1074 | break; | 1071 | break; |
| 1075 | case PixelFormat::R32_FLOAT: | 1072 | case PixelFormat::R32_FLOAT: |
| 1076 | if (src_view.format == PixelFormat::D32_FLOAT) { | 1073 | if (src_view.format == PixelFormat::D32_FLOAT) { |
| 1077 | return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift); | 1074 | return blit_image_helper.ConvertD32ToR32(dst, src_view); |
| 1078 | } | 1075 | } |
| 1079 | break; | 1076 | break; |
| 1080 | case PixelFormat::D16_UNORM: | 1077 | case PixelFormat::D16_UNORM: |
| 1081 | if (src_view.format == PixelFormat::R16_UNORM) { | 1078 | if (src_view.format == PixelFormat::R16_UNORM) { |
| 1082 | return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift); | 1079 | return blit_image_helper.ConvertR16ToD16(dst, src_view); |
| 1083 | } | 1080 | } |
| 1084 | break; | 1081 | break; |
| 1085 | case PixelFormat::S8_UINT_D24_UNORM: | 1082 | case PixelFormat::S8_UINT_D24_UNORM: |
| 1086 | return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift); | 1083 | if (src_view.format == PixelFormat::A8B8G8R8_UNORM || |
| 1084 | src_view.format == PixelFormat::B8G8R8A8_UNORM) { | ||
| 1085 | return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view); | ||
| 1086 | } | ||
| 1087 | break; | 1087 | break; |
| 1088 | case PixelFormat::D32_FLOAT: | 1088 | case PixelFormat::D32_FLOAT: |
| 1089 | if (src_view.format == PixelFormat::R32_FLOAT) { | 1089 | if (src_view.format == PixelFormat::R32_FLOAT) { |
| 1090 | return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift); | 1090 | return blit_image_helper.ConvertR32ToD32(dst, src_view); |
| 1091 | } | 1091 | } |
| 1092 | break; | 1092 | break; |
| 1093 | default: | 1093 | default: |
| @@ -1329,6 +1329,10 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm | |||
| 1329 | } | 1329 | } |
| 1330 | } | 1330 | } |
| 1331 | 1331 | ||
| 1332 | bool Image::IsRescaled() const noexcept { | ||
| 1333 | return True(flags & ImageFlagBits::Rescaled); | ||
| 1334 | } | ||
| 1335 | |||
| 1332 | bool Image::ScaleUp(bool ignore) { | 1336 | bool Image::ScaleUp(bool ignore) { |
| 1333 | if (True(flags & ImageFlagBits::Rescaled)) { | 1337 | if (True(flags & ImageFlagBits::Rescaled)) { |
| 1334 | return false; | 1338 | return false; |
| @@ -1340,7 +1344,6 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1340 | return false; | 1344 | return false; |
| 1341 | } | 1345 | } |
| 1342 | has_scaled = true; | 1346 | has_scaled = true; |
| 1343 | const auto& device = runtime->device; | ||
| 1344 | if (!scaled_image) { | 1347 | if (!scaled_image) { |
| 1345 | const bool is_2d = info.type == ImageType::e2D; | 1348 | const bool is_2d = info.type == ImageType::e2D; |
| 1346 | const u32 scaled_width = resolution.ScaleUp(info.size.width); | 1349 | const u32 scaled_width = resolution.ScaleUp(info.size.width); |
| @@ -1348,7 +1351,7 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1348 | auto scaled_info = info; | 1351 | auto scaled_info = info; |
| 1349 | scaled_info.size.width = scaled_width; | 1352 | scaled_info.size.width = scaled_width; |
| 1350 | scaled_info.size.height = scaled_height; | 1353 | scaled_info.size.height = scaled_height; |
| 1351 | scaled_image = MakeImage(device, scaled_info); | 1354 | scaled_image = MakeImage(runtime->device, scaled_info); |
| 1352 | auto& allocator = runtime->memory_allocator; | 1355 | auto& allocator = runtime->memory_allocator; |
| 1353 | scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal)); | 1356 | scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal)); |
| 1354 | ignore = false; | 1357 | ignore = false; |
| @@ -1357,18 +1360,13 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1357 | if (ignore) { | 1360 | if (ignore) { |
| 1358 | return true; | 1361 | return true; |
| 1359 | } | 1362 | } |
| 1360 | |||
| 1361 | if (aspect_mask == 0) { | 1363 | if (aspect_mask == 0) { |
| 1362 | aspect_mask = ImageAspectMask(info.format); | 1364 | aspect_mask = ImageAspectMask(info.format); |
| 1363 | } | 1365 | } |
| 1364 | static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal; | 1366 | if (NeedsScaleHelper()) { |
| 1365 | const PixelFormat format = StorageFormat(info.format); | ||
| 1366 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; | ||
| 1367 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; | ||
| 1368 | if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { | ||
| 1369 | BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution); | ||
| 1370 | } else { | ||
| 1371 | return BlitScaleHelper(true); | 1367 | return BlitScaleHelper(true); |
| 1368 | } else { | ||
| 1369 | BlitScale(*scheduler, *original_image, *scaled_image, info, aspect_mask, resolution); | ||
| 1372 | } | 1370 | } |
| 1373 | return true; | 1371 | return true; |
| 1374 | } | 1372 | } |
| @@ -1390,15 +1388,10 @@ bool Image::ScaleDown(bool ignore) { | |||
| 1390 | if (aspect_mask == 0) { | 1388 | if (aspect_mask == 0) { |
| 1391 | aspect_mask = ImageAspectMask(info.format); | 1389 | aspect_mask = ImageAspectMask(info.format); |
| 1392 | } | 1390 | } |
| 1393 | static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal; | 1391 | if (NeedsScaleHelper()) { |
| 1394 | const PixelFormat format = StorageFormat(info.format); | ||
| 1395 | const auto& device = runtime->device; | ||
| 1396 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; | ||
| 1397 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; | ||
| 1398 | if (device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT)) { | ||
| 1399 | BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false); | ||
| 1400 | } else { | ||
| 1401 | return BlitScaleHelper(false); | 1392 | return BlitScaleHelper(false); |
| 1393 | } else { | ||
| 1394 | BlitScale(*scheduler, *scaled_image, *original_image, info, aspect_mask, resolution, false); | ||
| 1402 | } | 1395 | } |
| 1403 | return true; | 1396 | return true; |
| 1404 | } | 1397 | } |
| @@ -1466,10 +1459,24 @@ bool Image::BlitScaleHelper(bool scale_up) { | |||
| 1466 | return true; | 1459 | return true; |
| 1467 | } | 1460 | } |
| 1468 | 1461 | ||
| 1462 | bool Image::NeedsScaleHelper() const { | ||
| 1463 | const auto& device = runtime->device; | ||
| 1464 | const bool needs_msaa_helper = info.num_samples > 1 && device.CantBlitMSAA(); | ||
| 1465 | if (needs_msaa_helper) { | ||
| 1466 | return true; | ||
| 1467 | } | ||
| 1468 | static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal; | ||
| 1469 | const PixelFormat format = StorageFormat(info.format); | ||
| 1470 | const auto vk_format = MaxwellToVK::SurfaceFormat(device, OPTIMAL_FORMAT, false, format).format; | ||
| 1471 | const auto blit_usage = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; | ||
| 1472 | const bool needs_blit_helper = !device.IsFormatSupported(vk_format, blit_usage, OPTIMAL_FORMAT); | ||
| 1473 | return needs_blit_helper; | ||
| 1474 | } | ||
| 1475 | |||
| 1469 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | 1476 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, |
| 1470 | ImageId image_id_, Image& image) | 1477 | ImageId image_id_, Image& image) |
| 1471 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, | 1478 | : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, |
| 1472 | image_handle{image.Handle()}, samples{ConvertSampleCount(image.info.num_samples)} { | 1479 | image_handle{image.Handle()}, samples(ConvertSampleCount(image.info.num_samples)) { |
| 1473 | using Shader::TextureType; | 1480 | using Shader::TextureType; |
| 1474 | 1481 | ||
| 1475 | const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); | 1482 | const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); |
| @@ -1552,6 +1559,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI | |||
| 1552 | } | 1559 | } |
| 1553 | } | 1560 | } |
| 1554 | 1561 | ||
| 1562 | ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, | ||
| 1563 | ImageId image_id_, Image& image, const SlotVector<Image>& slot_imgs) | ||
| 1564 | : ImageView{runtime, info, image_id_, image} { | ||
| 1565 | slot_images = &slot_imgs; | ||
| 1566 | } | ||
| 1567 | |||
| 1555 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, | 1568 | ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, |
| 1556 | const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) | 1569 | const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_) |
| 1557 | : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, | 1570 | : VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_}, |
| @@ -1607,6 +1620,15 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, | |||
| 1607 | return *view; | 1620 | return *view; |
| 1608 | } | 1621 | } |
| 1609 | 1622 | ||
| 1623 | bool ImageView::IsRescaled() const noexcept { | ||
| 1624 | if (!slot_images) { | ||
| 1625 | return false; | ||
| 1626 | } | ||
| 1627 | const auto& slots = *slot_images; | ||
| 1628 | const auto& src_image = slots[image_id]; | ||
| 1629 | return src_image.IsRescaled(); | ||
| 1630 | } | ||
| 1631 | |||
| 1610 | vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) { | 1632 | vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) { |
| 1611 | return device->GetLogical().CreateImageView({ | 1633 | return device->GetLogical().CreateImageView({ |
| 1612 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 1634 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 753e3e8a1..c81130dd2 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -23,6 +23,7 @@ using VideoCommon::ImageId; | |||
| 23 | using VideoCommon::NUM_RT; | 23 | using VideoCommon::NUM_RT; |
| 24 | using VideoCommon::Region2D; | 24 | using VideoCommon::Region2D; |
| 25 | using VideoCommon::RenderTargets; | 25 | using VideoCommon::RenderTargets; |
| 26 | using VideoCommon::SlotVector; | ||
| 26 | using VideoCore::Surface::PixelFormat; | 27 | using VideoCore::Surface::PixelFormat; |
| 27 | 28 | ||
| 28 | class ASTCDecoderPass; | 29 | class ASTCDecoderPass; |
| @@ -65,7 +66,7 @@ public: | |||
| 65 | 66 | ||
| 66 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); | 67 | void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); |
| 67 | 68 | ||
| 68 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled); | 69 | void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view); |
| 69 | 70 | ||
| 70 | bool CanAccelerateImageUpload(Image&) const noexcept { | 71 | bool CanAccelerateImageUpload(Image&) const noexcept { |
| 71 | return false; | 72 | return false; |
| @@ -139,6 +140,8 @@ public: | |||
| 139 | return std::exchange(initialized, true); | 140 | return std::exchange(initialized, true); |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 143 | bool IsRescaled() const noexcept; | ||
| 144 | |||
| 142 | bool ScaleUp(bool ignore = false); | 145 | bool ScaleUp(bool ignore = false); |
| 143 | 146 | ||
| 144 | bool ScaleDown(bool ignore = false); | 147 | bool ScaleDown(bool ignore = false); |
| @@ -146,6 +149,8 @@ public: | |||
| 146 | private: | 149 | private: |
| 147 | bool BlitScaleHelper(bool scale_up); | 150 | bool BlitScaleHelper(bool scale_up); |
| 148 | 151 | ||
| 152 | bool NeedsScaleHelper() const; | ||
| 153 | |||
| 149 | VKScheduler* scheduler{}; | 154 | VKScheduler* scheduler{}; |
| 150 | TextureCacheRuntime* runtime{}; | 155 | TextureCacheRuntime* runtime{}; |
| 151 | 156 | ||
| @@ -168,6 +173,8 @@ private: | |||
| 168 | class ImageView : public VideoCommon::ImageViewBase { | 173 | class ImageView : public VideoCommon::ImageViewBase { |
| 169 | public: | 174 | public: |
| 170 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); | 175 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); |
| 176 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&, | ||
| 177 | const SlotVector<Image>&); | ||
| 171 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, | 178 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, |
| 172 | const VideoCommon::ImageViewInfo&, GPUVAddr); | 179 | const VideoCommon::ImageViewInfo&, GPUVAddr); |
| 173 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&); | 180 | explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&); |
| @@ -189,6 +196,8 @@ public: | |||
| 189 | [[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type, | 196 | [[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type, |
| 190 | Shader::ImageFormat image_format); | 197 | Shader::ImageFormat image_format); |
| 191 | 198 | ||
| 199 | [[nodiscard]] bool IsRescaled() const noexcept; | ||
| 200 | |||
| 192 | [[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept { | 201 | [[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept { |
| 193 | return *image_views[static_cast<size_t>(texture_type)]; | 202 | return *image_views[static_cast<size_t>(texture_type)]; |
| 194 | } | 203 | } |
| @@ -222,6 +231,8 @@ private: | |||
| 222 | [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); | 231 | [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); |
| 223 | 232 | ||
| 224 | const Device* device = nullptr; | 233 | const Device* device = nullptr; |
| 234 | const SlotVector<Image>* slot_images = nullptr; | ||
| 235 | |||
| 225 | std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views; | 236 | std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views; |
| 226 | std::unique_ptr<StorageViews> storage_views; | 237 | std::unique_ptr<StorageViews> storage_views; |
| 227 | vk::ImageView depth_view; | 238 | vk::ImageView depth_view; |
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index 05850afd0..7d3ae0de4 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <bit> | ||
| 6 | #include <filesystem> | 7 | #include <filesystem> |
| 7 | #include <fstream> | 8 | #include <fstream> |
| 8 | #include <memory> | 9 | #include <memory> |
| @@ -14,6 +15,7 @@ | |||
| 14 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 15 | #include "common/div_ceil.h" | 16 | #include "common/div_ceil.h" |
| 16 | #include "common/fs/fs.h" | 17 | #include "common/fs/fs.h" |
| 18 | #include "common/fs/path_util.h" | ||
| 17 | #include "common/logging/log.h" | 19 | #include "common/logging/log.h" |
| 18 | #include "shader_recompiler/environment.h" | 20 | #include "shader_recompiler/environment.h" |
| 19 | #include "video_core/engines/kepler_compute.h" | 21 | #include "video_core/engines/kepler_compute.h" |
| @@ -57,6 +59,47 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) { | |||
| 57 | } | 59 | } |
| 58 | } | 60 | } |
| 59 | 61 | ||
| 62 | static std::string_view StageToPrefix(Shader::Stage stage) { | ||
| 63 | switch (stage) { | ||
| 64 | case Shader::Stage::VertexB: | ||
| 65 | return "VB"; | ||
| 66 | case Shader::Stage::TessellationControl: | ||
| 67 | return "TC"; | ||
| 68 | case Shader::Stage::TessellationEval: | ||
| 69 | return "TE"; | ||
| 70 | case Shader::Stage::Geometry: | ||
| 71 | return "GS"; | ||
| 72 | case Shader::Stage::Fragment: | ||
| 73 | return "FS"; | ||
| 74 | case Shader::Stage::Compute: | ||
| 75 | return "CS"; | ||
| 76 | case Shader::Stage::VertexA: | ||
| 77 | return "VA"; | ||
| 78 | default: | ||
| 79 | return "UK"; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | static void DumpImpl(u64 hash, const u64* code, u32 read_highest, u32 read_lowest, | ||
| 84 | u32 initial_offset, Shader::Stage stage) { | ||
| 85 | const auto shader_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)}; | ||
| 86 | const auto base_dir{shader_dir / "shaders"}; | ||
| 87 | if (!Common::FS::CreateDir(shader_dir) || !Common::FS::CreateDir(base_dir)) { | ||
| 88 | LOG_ERROR(Common_Filesystem, "Failed to create shader dump directories"); | ||
| 89 | return; | ||
| 90 | } | ||
| 91 | const auto prefix = StageToPrefix(stage); | ||
| 92 | const auto name{base_dir / fmt::format("{}{:016x}.ash", prefix, hash)}; | ||
| 93 | const size_t real_size = read_highest - read_lowest + initial_offset; | ||
| 94 | const size_t padding_needed = ((32 - (real_size % 32)) % 32); | ||
| 95 | std::fstream shader_file(name, std::ios::out | std::ios::binary); | ||
| 96 | const size_t jump_index = initial_offset / sizeof(u64); | ||
| 97 | shader_file.write(reinterpret_cast<const char*>(code + jump_index), real_size); | ||
| 98 | for (size_t i = 0; i < padding_needed; i++) { | ||
| 99 | shader_file.put(0); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 60 | GenericEnvironment::GenericEnvironment(Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_, | 103 | GenericEnvironment::GenericEnvironment(Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_, |
| 61 | u32 start_address_) | 104 | u32 start_address_) |
| 62 | : gpu_memory{&gpu_memory_}, program_base{program_base_} { | 105 | : gpu_memory{&gpu_memory_}, program_base{program_base_} { |
| @@ -128,6 +171,10 @@ u64 GenericEnvironment::CalculateHash() const { | |||
| 128 | return Common::CityHash64(data.get(), size); | 171 | return Common::CityHash64(data.get(), size); |
| 129 | } | 172 | } |
| 130 | 173 | ||
| 174 | void GenericEnvironment::Dump(u64 hash) { | ||
| 175 | DumpImpl(hash, code.data(), read_highest, read_lowest, initial_offset, stage); | ||
| 176 | } | ||
| 177 | |||
| 131 | void GenericEnvironment::Serialize(std::ofstream& file) const { | 178 | void GenericEnvironment::Serialize(std::ofstream& file) const { |
| 132 | const u64 code_size{static_cast<u64>(CachedSize())}; | 179 | const u64 code_size{static_cast<u64>(CachedSize())}; |
| 133 | const u64 num_texture_types{static_cast<u64>(texture_types.size())}; | 180 | const u64 num_texture_types{static_cast<u64>(texture_types.size())}; |
| @@ -207,6 +254,7 @@ GraphicsEnvironment::GraphicsEnvironment(Tegra::Engines::Maxwell3D& maxwell3d_, | |||
| 207 | u32 start_address_) | 254 | u32 start_address_) |
| 208 | : GenericEnvironment{gpu_memory_, program_base_, start_address_}, maxwell3d{&maxwell3d_} { | 255 | : GenericEnvironment{gpu_memory_, program_base_, start_address_}, maxwell3d{&maxwell3d_} { |
| 209 | gpu_memory->ReadBlock(program_base + start_address, &sph, sizeof(sph)); | 256 | gpu_memory->ReadBlock(program_base + start_address, &sph, sizeof(sph)); |
| 257 | initial_offset = sizeof(sph); | ||
| 210 | gp_passthrough_mask = maxwell3d->regs.gp_passthrough_mask; | 258 | gp_passthrough_mask = maxwell3d->regs.gp_passthrough_mask; |
| 211 | switch (program) { | 259 | switch (program) { |
| 212 | case Maxwell::ShaderProgram::VertexA: | 260 | case Maxwell::ShaderProgram::VertexA: |
| @@ -323,14 +371,20 @@ void FileEnvironment::Deserialize(std::ifstream& file) { | |||
| 323 | if (stage == Shader::Stage::Compute) { | 371 | if (stage == Shader::Stage::Compute) { |
| 324 | file.read(reinterpret_cast<char*>(&workgroup_size), sizeof(workgroup_size)) | 372 | file.read(reinterpret_cast<char*>(&workgroup_size), sizeof(workgroup_size)) |
| 325 | .read(reinterpret_cast<char*>(&shared_memory_size), sizeof(shared_memory_size)); | 373 | .read(reinterpret_cast<char*>(&shared_memory_size), sizeof(shared_memory_size)); |
| 374 | initial_offset = 0; | ||
| 326 | } else { | 375 | } else { |
| 327 | file.read(reinterpret_cast<char*>(&sph), sizeof(sph)); | 376 | file.read(reinterpret_cast<char*>(&sph), sizeof(sph)); |
| 377 | initial_offset = sizeof(sph); | ||
| 328 | if (stage == Shader::Stage::Geometry) { | 378 | if (stage == Shader::Stage::Geometry) { |
| 329 | file.read(reinterpret_cast<char*>(&gp_passthrough_mask), sizeof(gp_passthrough_mask)); | 379 | file.read(reinterpret_cast<char*>(&gp_passthrough_mask), sizeof(gp_passthrough_mask)); |
| 330 | } | 380 | } |
| 331 | } | 381 | } |
| 332 | } | 382 | } |
| 333 | 383 | ||
| 384 | void FileEnvironment::Dump(u64 [[maybe_unused]] hash) { | ||
| 385 | DumpImpl(hash, code.get(), read_highest, read_lowest, initial_offset, stage); | ||
| 386 | } | ||
| 387 | |||
| 334 | u64 FileEnvironment::ReadInstruction(u32 address) { | 388 | u64 FileEnvironment::ReadInstruction(u32 address) { |
| 335 | if (address < read_lowest || address > read_highest) { | 389 | if (address < read_lowest || address > read_highest) { |
| 336 | throw Shader::LogicError("Out of bounds address {}", address); | 390 | throw Shader::LogicError("Out of bounds address {}", address); |
diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index 6640e53d0..aae762b27 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h | |||
| @@ -57,6 +57,8 @@ public: | |||
| 57 | 57 | ||
| 58 | [[nodiscard]] u64 CalculateHash() const; | 58 | [[nodiscard]] u64 CalculateHash() const; |
| 59 | 59 | ||
| 60 | void Dump(u64 hash) override; | ||
| 61 | |||
| 60 | void Serialize(std::ofstream& file) const; | 62 | void Serialize(std::ofstream& file) const; |
| 61 | 63 | ||
| 62 | protected: | 64 | protected: |
| @@ -82,6 +84,7 @@ protected: | |||
| 82 | 84 | ||
| 83 | u32 cached_lowest = std::numeric_limits<u32>::max(); | 85 | u32 cached_lowest = std::numeric_limits<u32>::max(); |
| 84 | u32 cached_highest = 0; | 86 | u32 cached_highest = 0; |
| 87 | u32 initial_offset = 0; | ||
| 85 | 88 | ||
| 86 | bool has_unbound_instructions = false; | 89 | bool has_unbound_instructions = false; |
| 87 | }; | 90 | }; |
| @@ -149,6 +152,8 @@ public: | |||
| 149 | 152 | ||
| 150 | [[nodiscard]] std::array<u32, 3> WorkgroupSize() const override; | 153 | [[nodiscard]] std::array<u32, 3> WorkgroupSize() const override; |
| 151 | 154 | ||
| 155 | void Dump(u64 hash) override; | ||
| 156 | |||
| 152 | private: | 157 | private: |
| 153 | std::unique_ptr<u64[]> code; | 158 | std::unique_ptr<u64[]> code; |
| 154 | std::unordered_map<u32, Shader::TextureType> texture_types; | 159 | std::unordered_map<u32, Shader::TextureType> texture_types; |
| @@ -159,6 +164,7 @@ private: | |||
| 159 | u32 texture_bound{}; | 164 | u32 texture_bound{}; |
| 160 | u32 read_lowest{}; | 165 | u32 read_lowest{}; |
| 161 | u32 read_highest{}; | 166 | u32 read_highest{}; |
| 167 | u32 initial_offset{}; | ||
| 162 | }; | 168 | }; |
| 163 | 169 | ||
| 164 | void SerializePipeline(std::span<const char> key, std::span<const GenericEnvironment* const> envs, | 170 | void SerializePipeline(std::span<const char> key, std::span<const GenericEnvironment* const> envs, |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 5aaeb16ca..b494152b8 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -1397,7 +1397,8 @@ ImageViewId TextureCache<P>::FindOrEmplaceImageView(ImageId image_id, const Imag | |||
| 1397 | if (const ImageViewId image_view_id = image.FindView(info); image_view_id) { | 1397 | if (const ImageViewId image_view_id = image.FindView(info); image_view_id) { |
| 1398 | return image_view_id; | 1398 | return image_view_id; |
| 1399 | } | 1399 | } |
| 1400 | const ImageViewId image_view_id = slot_image_views.insert(runtime, info, image_id, image); | 1400 | const ImageViewId image_view_id = |
| 1401 | slot_image_views.insert(runtime, info, image_id, image, slot_images); | ||
| 1401 | image.InsertView(info, image_view_id); | 1402 | image.InsertView(info, image_view_id); |
| 1402 | return image_view_id; | 1403 | return image_view_id; |
| 1403 | } | 1404 | } |
| @@ -1855,9 +1856,20 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag | |||
| 1855 | .height = std::min(dst_view.size.height, src_view.size.height), | 1856 | .height = std::min(dst_view.size.height, src_view.size.height), |
| 1856 | .depth = std::min(dst_view.size.depth, src_view.size.depth), | 1857 | .depth = std::min(dst_view.size.depth, src_view.size.depth), |
| 1857 | }; | 1858 | }; |
| 1858 | UNIMPLEMENTED_IF(copy.extent != expected_size); | 1859 | const Extent3D scaled_extent = [is_rescaled, expected_size]() { |
| 1860 | if (!is_rescaled) { | ||
| 1861 | return expected_size; | ||
| 1862 | } | ||
| 1863 | const auto& resolution = Settings::values.resolution_info; | ||
| 1864 | return Extent3D{ | ||
| 1865 | .width = resolution.ScaleUp(expected_size.width), | ||
| 1866 | .height = resolution.ScaleUp(expected_size.height), | ||
| 1867 | .depth = expected_size.depth, | ||
| 1868 | }; | ||
| 1869 | }(); | ||
| 1870 | UNIMPLEMENTED_IF(copy.extent != scaled_extent); | ||
| 1859 | 1871 | ||
| 1860 | runtime.ConvertImage(dst_framebuffer, dst_view, src_view, is_rescaled); | 1872 | runtime.ConvertImage(dst_framebuffer, dst_view, src_view); |
| 1861 | } | 1873 | } |
| 1862 | } | 1874 | } |
| 1863 | 1875 | ||
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 7bd31b211..d8e19cb2f 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -364,14 +364,14 @@ template <u32 GOB_EXTENT> | |||
| 364 | 364 | ||
| 365 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress2D( | 365 | [[nodiscard]] std::optional<SubresourceExtent> ResolveOverlapRightAddress2D( |
| 366 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { | 366 | const ImageInfo& new_info, GPUVAddr gpu_addr, const ImageBase& overlap, bool strict_size) { |
| 367 | const u32 layer_stride = new_info.layer_stride; | 367 | const u64 layer_stride = new_info.layer_stride; |
| 368 | const s32 new_size = layer_stride * new_info.resources.layers; | 368 | const u64 new_size = layer_stride * new_info.resources.layers; |
| 369 | const s32 diff = static_cast<s32>(overlap.gpu_addr - gpu_addr); | 369 | const u64 diff = overlap.gpu_addr - gpu_addr; |
| 370 | if (diff > new_size) { | 370 | if (diff > new_size) { |
| 371 | return std::nullopt; | 371 | return std::nullopt; |
| 372 | } | 372 | } |
| 373 | const s32 base_layer = diff / layer_stride; | 373 | const s32 base_layer = static_cast<s32>(diff / layer_stride); |
| 374 | const s32 mip_offset = diff % layer_stride; | 374 | const s32 mip_offset = static_cast<s32>(diff % layer_stride); |
| 375 | const std::array offsets = CalculateMipLevelOffsets(new_info); | 375 | const std::array offsets = CalculateMipLevelOffsets(new_info); |
| 376 | const auto end = offsets.begin() + new_info.resources.levels; | 376 | const auto end = offsets.begin() + new_info.resources.levels; |
| 377 | const auto it = std::find(offsets.begin(), end, static_cast<u32>(mip_offset)); | 377 | const auto it = std::find(offsets.begin(), end, static_cast<u32>(mip_offset)); |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 7bf5b6578..3d78efddc 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -271,7 +271,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 271 | .tessellationShader = true, | 271 | .tessellationShader = true, |
| 272 | .sampleRateShading = true, | 272 | .sampleRateShading = true, |
| 273 | .dualSrcBlend = true, | 273 | .dualSrcBlend = true, |
| 274 | .logicOp = false, | 274 | .logicOp = true, |
| 275 | .multiDrawIndirect = false, | 275 | .multiDrawIndirect = false, |
| 276 | .drawIndirectFirstInstance = false, | 276 | .drawIndirectFirstInstance = false, |
| 277 | .depthClamp = true, | 277 | .depthClamp = true, |
| @@ -433,6 +433,19 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 433 | LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); | 433 | LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); |
| 434 | } | 434 | } |
| 435 | 435 | ||
| 436 | VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart; | ||
| 437 | if (is_topology_list_restart_supported || is_patch_list_restart_supported) { | ||
| 438 | primitive_topology_list_restart = { | ||
| 439 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT, | ||
| 440 | .pNext = nullptr, | ||
| 441 | .primitiveTopologyListRestart = is_topology_list_restart_supported, | ||
| 442 | .primitiveTopologyPatchListRestart = is_patch_list_restart_supported, | ||
| 443 | }; | ||
| 444 | SetNext(next, primitive_topology_list_restart); | ||
| 445 | } else { | ||
| 446 | LOG_INFO(Render_Vulkan, "Device doesn't support list topology primitive restart"); | ||
| 447 | } | ||
| 448 | |||
| 436 | VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; | 449 | VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; |
| 437 | if (ext_transform_feedback) { | 450 | if (ext_transform_feedback) { |
| 438 | transform_feedback = { | 451 | transform_feedback = { |
| @@ -625,15 +638,20 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 625 | } | 638 | } |
| 626 | } | 639 | } |
| 627 | 640 | ||
| 628 | if (ext_vertex_input_dynamic_state && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { | 641 | const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS; |
| 642 | if (ext_vertex_input_dynamic_state && is_intel_windows) { | ||
| 629 | LOG_WARNING(Render_Vulkan, "Blacklisting Intel for VK_EXT_vertex_input_dynamic_state"); | 643 | LOG_WARNING(Render_Vulkan, "Blacklisting Intel for VK_EXT_vertex_input_dynamic_state"); |
| 630 | ext_vertex_input_dynamic_state = false; | 644 | ext_vertex_input_dynamic_state = false; |
| 631 | } | 645 | } |
| 632 | if (is_float16_supported && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { | 646 | if (is_float16_supported && is_intel_windows) { |
| 633 | // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being. | 647 | // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being. |
| 634 | LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math"); | 648 | LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math"); |
| 635 | is_float16_supported = false; | 649 | is_float16_supported = false; |
| 636 | } | 650 | } |
| 651 | if (is_intel_windows) { | ||
| 652 | LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits"); | ||
| 653 | cant_blit_msaa = true; | ||
| 654 | } | ||
| 637 | 655 | ||
| 638 | supports_d24_depth = | 656 | supports_d24_depth = |
| 639 | IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT, | 657 | IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT, |
| @@ -891,6 +909,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 891 | bool has_ext_provoking_vertex{}; | 909 | bool has_ext_provoking_vertex{}; |
| 892 | bool has_ext_vertex_input_dynamic_state{}; | 910 | bool has_ext_vertex_input_dynamic_state{}; |
| 893 | bool has_ext_line_rasterization{}; | 911 | bool has_ext_line_rasterization{}; |
| 912 | bool has_ext_primitive_topology_list_restart{}; | ||
| 894 | for (const std::string& extension : supported_extensions) { | 913 | for (const std::string& extension : supported_extensions) { |
| 895 | const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, | 914 | const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, |
| 896 | bool push) { | 915 | bool push) { |
| @@ -915,6 +934,8 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 915 | test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); | 934 | test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); |
| 916 | test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); | 935 | test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); |
| 917 | test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); | 936 | test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); |
| 937 | test(has_ext_primitive_topology_list_restart, | ||
| 938 | VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, true); | ||
| 918 | test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true); | 939 | test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true); |
| 919 | test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, | 940 | test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, |
| 920 | true); | 941 | true); |
| @@ -1113,6 +1134,19 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) { | |||
| 1113 | khr_pipeline_executable_properties = true; | 1134 | khr_pipeline_executable_properties = true; |
| 1114 | } | 1135 | } |
| 1115 | } | 1136 | } |
| 1137 | if (has_ext_primitive_topology_list_restart) { | ||
| 1138 | VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart{}; | ||
| 1139 | primitive_topology_list_restart.sType = | ||
| 1140 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; | ||
| 1141 | primitive_topology_list_restart.pNext = nullptr; | ||
| 1142 | features.pNext = &primitive_topology_list_restart; | ||
| 1143 | physical.GetFeatures2KHR(features); | ||
| 1144 | |||
| 1145 | is_topology_list_restart_supported = | ||
| 1146 | primitive_topology_list_restart.primitiveTopologyListRestart; | ||
| 1147 | is_patch_list_restart_supported = | ||
| 1148 | primitive_topology_list_restart.primitiveTopologyPatchListRestart; | ||
| 1149 | } | ||
| 1116 | if (has_khr_image_format_list && has_khr_swapchain_mutable_format) { | 1150 | if (has_khr_image_format_list && has_khr_swapchain_mutable_format) { |
| 1117 | extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME); | 1151 | extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME); |
| 1118 | extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME); | 1152 | extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME); |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 10653ac6b..37d140ebd 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -238,6 +238,16 @@ public: | |||
| 238 | return khr_workgroup_memory_explicit_layout; | 238 | return khr_workgroup_memory_explicit_layout; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | /// Returns true if the device supports VK_EXT_primitive_topology_list_restart. | ||
| 242 | bool IsTopologyListPrimitiveRestartSupported() const { | ||
| 243 | return is_topology_list_restart_supported; | ||
| 244 | } | ||
| 245 | |||
| 246 | /// Returns true if the device supports VK_EXT_primitive_topology_list_restart. | ||
| 247 | bool IsPatchListPrimitiveRestartSupported() const { | ||
| 248 | return is_patch_list_restart_supported; | ||
| 249 | } | ||
| 250 | |||
| 241 | /// Returns true if the device supports VK_EXT_index_type_uint8. | 251 | /// Returns true if the device supports VK_EXT_index_type_uint8. |
| 242 | bool IsExtIndexTypeUint8Supported() const { | 252 | bool IsExtIndexTypeUint8Supported() const { |
| 243 | return ext_index_type_uint8; | 253 | return ext_index_type_uint8; |
| @@ -340,6 +350,10 @@ public: | |||
| 340 | return supports_d24_depth; | 350 | return supports_d24_depth; |
| 341 | } | 351 | } |
| 342 | 352 | ||
| 353 | bool CantBlitMSAA() const { | ||
| 354 | return cant_blit_msaa; | ||
| 355 | } | ||
| 356 | |||
| 343 | private: | 357 | private: |
| 344 | /// Checks if the physical device is suitable. | 358 | /// Checks if the physical device is suitable. |
| 345 | void CheckSuitability(bool requires_swapchain) const; | 359 | void CheckSuitability(bool requires_swapchain) const; |
| @@ -401,6 +415,9 @@ private: | |||
| 401 | bool is_shader_int16_supported{}; ///< Support for int16. | 415 | bool is_shader_int16_supported{}; ///< Support for int16. |
| 402 | bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images. | 416 | bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images. |
| 403 | bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. | 417 | bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. |
| 418 | bool is_topology_list_restart_supported{}; ///< Support for primitive restart with list | ||
| 419 | ///< topologies. | ||
| 420 | bool is_patch_list_restart_supported{}; ///< Support for primitive restart with list patch. | ||
| 404 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. | 421 | bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. |
| 405 | bool nv_viewport_array2{}; ///< Support for VK_NV_viewport_array2. | 422 | bool nv_viewport_array2{}; ///< Support for VK_NV_viewport_array2. |
| 406 | bool nv_geometry_shader_passthrough{}; ///< Support for VK_NV_geometry_shader_passthrough. | 423 | bool nv_geometry_shader_passthrough{}; ///< Support for VK_NV_geometry_shader_passthrough. |
| @@ -430,6 +447,7 @@ private: | |||
| 430 | bool has_renderdoc{}; ///< Has RenderDoc attached | 447 | bool has_renderdoc{}; ///< Has RenderDoc attached |
| 431 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached | 448 | bool has_nsight_graphics{}; ///< Has Nsight Graphics attached |
| 432 | bool supports_d24_depth{}; ///< Supports D24 depth buffers. | 449 | bool supports_d24_depth{}; ///< Supports D24 depth buffers. |
| 450 | bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting. | ||
| 433 | 451 | ||
| 434 | // Telemetry parameters | 452 | // Telemetry parameters |
| 435 | std::string vendor_name; ///< Device's driver name. | 453 | std::string vendor_name; ///< Device's driver name. |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 732e8c276..30902101d 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -251,6 +251,9 @@ target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | |||
| 251 | if (NOT WIN32) | 251 | if (NOT WIN32) |
| 252 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) | 252 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) |
| 253 | endif() | 253 | endif() |
| 254 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | ||
| 255 | target_link_libraries(yuzu PRIVATE Qt5::DBus) | ||
| 256 | endif() | ||
| 254 | 257 | ||
| 255 | target_compile_definitions(yuzu PRIVATE | 258 | target_compile_definitions(yuzu PRIVATE |
| 256 | # Use QStringBuilder for string concatenation to reduce | 259 | # Use QStringBuilder for string concatenation to reduce |
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index c5685db2e..4239c17f5 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include "core/hid/emulated_controller.h" | 12 | #include "core/hid/emulated_controller.h" |
| 13 | #include "core/hid/hid_core.h" | 13 | #include "core/hid/hid_core.h" |
| 14 | #include "core/hid/hid_types.h" | 14 | #include "core/hid/hid_types.h" |
| 15 | #include "core/hle/lock.h" | ||
| 16 | #include "core/hle/service/hid/controllers/npad.h" | 15 | #include "core/hle/service/hid/controllers/npad.h" |
| 17 | #include "core/hle/service/hid/hid.h" | 16 | #include "core/hle/service/hid/hid.h" |
| 18 | #include "core/hle/service/sm/sm.h" | 17 | #include "core/hle/service/sm/sm.h" |
| @@ -34,7 +33,7 @@ void UpdateController(Core::HID::EmulatedController* controller, | |||
| 34 | } | 33 | } |
| 35 | controller->SetNpadStyleIndex(controller_type); | 34 | controller->SetNpadStyleIndex(controller_type); |
| 36 | if (connected) { | 35 | if (connected) { |
| 37 | controller->Connect(); | 36 | controller->Connect(true); |
| 38 | } | 37 | } |
| 39 | } | 38 | } |
| 40 | 39 | ||
| @@ -401,36 +400,66 @@ void QtControllerSelectorDialog::SetSupportedControllers() { | |||
| 401 | } | 400 | } |
| 402 | 401 | ||
| 403 | void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) { | 402 | void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) { |
| 403 | const auto npad_style_set = system.HIDCore().GetSupportedStyleTag(); | ||
| 404 | auto& pairs = index_controller_type_pairs[player_index]; | 404 | auto& pairs = index_controller_type_pairs[player_index]; |
| 405 | 405 | ||
| 406 | pairs.clear(); | 406 | pairs.clear(); |
| 407 | emulated_controllers[player_index]->clear(); | 407 | emulated_controllers[player_index]->clear(); |
| 408 | 408 | ||
| 409 | pairs.emplace_back(emulated_controllers[player_index]->count(), | 409 | const auto add_item = [&](Core::HID::NpadStyleIndex controller_type, |
| 410 | Core::HID::NpadStyleIndex::ProController); | 410 | const QString& controller_name) { |
| 411 | emulated_controllers[player_index]->addItem(tr("Pro Controller")); | 411 | pairs.emplace_back(emulated_controllers[player_index]->count(), controller_type); |
| 412 | emulated_controllers[player_index]->addItem(controller_name); | ||
| 413 | }; | ||
| 412 | 414 | ||
| 413 | pairs.emplace_back(emulated_controllers[player_index]->count(), | 415 | if (npad_style_set.fullkey == 1) { |
| 414 | Core::HID::NpadStyleIndex::JoyconDual); | 416 | add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); |
| 415 | emulated_controllers[player_index]->addItem(tr("Dual Joycons")); | 417 | } |
| 416 | 418 | ||
| 417 | pairs.emplace_back(emulated_controllers[player_index]->count(), | 419 | if (npad_style_set.joycon_dual == 1) { |
| 418 | Core::HID::NpadStyleIndex::JoyconLeft); | 420 | add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons")); |
| 419 | emulated_controllers[player_index]->addItem(tr("Left Joycon")); | 421 | } |
| 420 | 422 | ||
| 421 | pairs.emplace_back(emulated_controllers[player_index]->count(), | 423 | if (npad_style_set.joycon_left == 1) { |
| 422 | Core::HID::NpadStyleIndex::JoyconRight); | 424 | add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon")); |
| 423 | emulated_controllers[player_index]->addItem(tr("Right Joycon")); | 425 | } |
| 424 | 426 | ||
| 425 | if (player_index == 0) { | 427 | if (npad_style_set.joycon_right == 1) { |
| 426 | pairs.emplace_back(emulated_controllers[player_index]->count(), | 428 | add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon")); |
| 427 | Core::HID::NpadStyleIndex::Handheld); | ||
| 428 | emulated_controllers[player_index]->addItem(tr("Handheld")); | ||
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | pairs.emplace_back(emulated_controllers[player_index]->count(), | 431 | if (player_index == 0 && npad_style_set.handheld == 1) { |
| 432 | Core::HID::NpadStyleIndex::GameCube); | 432 | add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld")); |
| 433 | emulated_controllers[player_index]->addItem(tr("GameCube Controller")); | 433 | } |
| 434 | |||
| 435 | if (npad_style_set.gamecube == 1) { | ||
| 436 | add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller")); | ||
| 437 | } | ||
| 438 | |||
| 439 | // Disable all unsupported controllers | ||
| 440 | if (!Settings::values.enable_all_controllers) { | ||
| 441 | return; | ||
| 442 | } | ||
| 443 | |||
| 444 | if (npad_style_set.palma == 1) { | ||
| 445 | add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus")); | ||
| 446 | } | ||
| 447 | |||
| 448 | if (npad_style_set.lark == 1) { | ||
| 449 | add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller")); | ||
| 450 | } | ||
| 451 | |||
| 452 | if (npad_style_set.lucia == 1) { | ||
| 453 | add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller")); | ||
| 454 | } | ||
| 455 | |||
| 456 | if (npad_style_set.lagoon == 1) { | ||
| 457 | add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller")); | ||
| 458 | } | ||
| 459 | |||
| 460 | if (npad_style_set.lager == 1) { | ||
| 461 | add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis")); | ||
| 462 | } | ||
| 434 | } | 463 | } |
| 435 | 464 | ||
| 436 | Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex( | 465 | Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex( |
| @@ -664,7 +693,5 @@ void QtControllerSelector::ReconfigureControllers( | |||
| 664 | } | 693 | } |
| 665 | 694 | ||
| 666 | void QtControllerSelector::MainWindowReconfigureFinished() { | 695 | void QtControllerSelector::MainWindowReconfigureFinished() { |
| 667 | // Acquire the HLE mutex | ||
| 668 | std::lock_guard lock(HLE::g_hle_lock); | ||
| 669 | callback(); | 696 | callback(); |
| 670 | } | 697 | } |
diff --git a/src/yuzu/applets/qt_error.cpp b/src/yuzu/applets/qt_error.cpp index 45cf64603..879e73660 100644 --- a/src/yuzu/applets/qt_error.cpp +++ b/src/yuzu/applets/qt_error.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <QDateTime> | 5 | #include <QDateTime> |
| 6 | #include "core/hle/lock.h" | ||
| 7 | #include "yuzu/applets/qt_error.h" | 6 | #include "yuzu/applets/qt_error.h" |
| 8 | #include "yuzu/main.h" | 7 | #include "yuzu/main.h" |
| 9 | 8 | ||
| @@ -57,7 +56,5 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te | |||
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | void QtErrorDisplay::MainWindowFinishedError() { | 58 | void QtErrorDisplay::MainWindowFinishedError() { |
| 60 | // Acquire the HLE mutex | ||
| 61 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 62 | callback(); | 59 | callback(); |
| 63 | } | 60 | } |
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index 7b19f1f8d..5b32da923 100644 --- a/src/yuzu/applets/qt_profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include "common/fs/path_util.h" | 14 | #include "common/fs/path_util.h" |
| 15 | #include "common/string_util.h" | 15 | #include "common/string_util.h" |
| 16 | #include "core/constants.h" | 16 | #include "core/constants.h" |
| 17 | #include "core/hle/lock.h" | ||
| 18 | #include "yuzu/applets/qt_profile_select.h" | 17 | #include "yuzu/applets/qt_profile_select.h" |
| 19 | #include "yuzu/main.h" | 18 | #include "yuzu/main.h" |
| 20 | #include "yuzu/util/controller_navigation.h" | 19 | #include "yuzu/util/controller_navigation.h" |
| @@ -170,7 +169,5 @@ void QtProfileSelector::SelectProfile( | |||
| 170 | } | 169 | } |
| 171 | 170 | ||
| 172 | void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { | 171 | void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { |
| 173 | // Acquire the HLE mutex | ||
| 174 | std::lock_guard lock{HLE::g_hle_lock}; | ||
| 175 | callback(uuid); | 172 | callback(uuid); |
| 176 | } | 173 | } |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 463d500c2..0f679c37e 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -776,6 +776,7 @@ void Config::ReadUIGamelistValues() { | |||
| 776 | ReadBasicSetting(UISettings::values.row_1_text_id); | 776 | ReadBasicSetting(UISettings::values.row_1_text_id); |
| 777 | ReadBasicSetting(UISettings::values.row_2_text_id); | 777 | ReadBasicSetting(UISettings::values.row_2_text_id); |
| 778 | ReadBasicSetting(UISettings::values.cache_game_list); | 778 | ReadBasicSetting(UISettings::values.cache_game_list); |
| 779 | ReadBasicSetting(UISettings::values.favorites_expanded); | ||
| 779 | const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); | 780 | const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); |
| 780 | for (int i = 0; i < favorites_size; i++) { | 781 | for (int i = 0; i < favorites_size; i++) { |
| 781 | qt_config->setArrayIndex(i); | 782 | qt_config->setArrayIndex(i); |
| @@ -1300,6 +1301,7 @@ void Config::SaveUIGamelistValues() { | |||
| 1300 | WriteBasicSetting(UISettings::values.row_1_text_id); | 1301 | WriteBasicSetting(UISettings::values.row_1_text_id); |
| 1301 | WriteBasicSetting(UISettings::values.row_2_text_id); | 1302 | WriteBasicSetting(UISettings::values.row_2_text_id); |
| 1302 | WriteBasicSetting(UISettings::values.cache_game_list); | 1303 | WriteBasicSetting(UISettings::values.cache_game_list); |
| 1304 | WriteBasicSetting(UISettings::values.favorites_expanded); | ||
| 1303 | qt_config->beginWriteArray(QStringLiteral("favorites")); | 1305 | qt_config->beginWriteArray(QStringLiteral("favorites")); |
| 1304 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { | 1306 | for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { |
| 1305 | qt_config->setArrayIndex(i); | 1307 | qt_config->setArrayIndex(i); |
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 633fc295b..c1cf4050c 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -51,6 +51,8 @@ void ConfigureDebug::SetConfiguration() { | |||
| 51 | ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue()); | 51 | ui->enable_cpu_debugging->setChecked(Settings::values.cpu_debug_mode.GetValue()); |
| 52 | ui->enable_nsight_aftermath->setEnabled(runtime_lock); | 52 | ui->enable_nsight_aftermath->setEnabled(runtime_lock); |
| 53 | ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue()); | 53 | ui->enable_nsight_aftermath->setChecked(Settings::values.enable_nsight_aftermath.GetValue()); |
| 54 | ui->dump_shaders->setEnabled(runtime_lock); | ||
| 55 | ui->dump_shaders->setChecked(Settings::values.dump_shaders.GetValue()); | ||
| 54 | ui->disable_macro_jit->setEnabled(runtime_lock); | 56 | ui->disable_macro_jit->setEnabled(runtime_lock); |
| 55 | ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); | 57 | ui->disable_macro_jit->setChecked(Settings::values.disable_macro_jit.GetValue()); |
| 56 | ui->disable_loop_safety_checks->setEnabled(runtime_lock); | 58 | ui->disable_loop_safety_checks->setEnabled(runtime_lock); |
| @@ -73,6 +75,7 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 73 | Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); | 75 | Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); |
| 74 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); | 76 | Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); |
| 75 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); | 77 | Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); |
| 78 | Settings::values.dump_shaders = ui->dump_shaders->isChecked(); | ||
| 76 | Settings::values.disable_shader_loop_safety_checks = | 79 | Settings::values.disable_shader_loop_safety_checks = |
| 77 | ui->disable_loop_safety_checks->isChecked(); | 80 | ui->disable_loop_safety_checks->isChecked(); |
| 78 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); | 81 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 0f3b51c8d..4dd870855 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -105,6 +105,19 @@ | |||
| 105 | </property> | 105 | </property> |
| 106 | </widget> | 106 | </widget> |
| 107 | </item> | 107 | </item> |
| 108 | <item row="2" column="1"> | ||
| 109 | <widget class="QCheckBox" name="dump_shaders"> | ||
| 110 | <property name="enabled"> | ||
| 111 | <bool>true</bool> | ||
| 112 | </property> | ||
| 113 | <property name="toolTip"> | ||
| 114 | <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string> | ||
| 115 | </property> | ||
| 116 | <property name="text"> | ||
| 117 | <string>Dump Game Shaders</string> | ||
| 118 | </property> | ||
| 119 | </widget> | ||
| 120 | </item> | ||
| 108 | <item row="0" column="1"> | 121 | <item row="0" column="1"> |
| 109 | <widget class="QCheckBox" name="disable_macro_jit"> | 122 | <widget class="QCheckBox" name="disable_macro_jit"> |
| 110 | <property name="enabled"> | 123 | <property name="enabled"> |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 8a8be8e40..8c6249fc2 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -599,11 +599,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 599 | if (is_connected) { | 599 | if (is_connected) { |
| 600 | if (type == Core::HID::NpadStyleIndex::Handheld) { | 600 | if (type == Core::HID::NpadStyleIndex::Handheld) { |
| 601 | emulated_controller_p1->Disconnect(); | 601 | emulated_controller_p1->Disconnect(); |
| 602 | emulated_controller_handheld->Connect(); | 602 | emulated_controller_handheld->Connect(true); |
| 603 | emulated_controller = emulated_controller_handheld; | 603 | emulated_controller = emulated_controller_handheld; |
| 604 | } else { | 604 | } else { |
| 605 | emulated_controller_handheld->Disconnect(); | 605 | emulated_controller_handheld->Disconnect(); |
| 606 | emulated_controller_p1->Connect(); | 606 | emulated_controller_p1->Connect(true); |
| 607 | emulated_controller = emulated_controller_p1; | 607 | emulated_controller = emulated_controller_p1; |
| 608 | } | 608 | } |
| 609 | } | 609 | } |
| @@ -718,7 +718,7 @@ void ConfigureInputPlayer::LoadConfiguration() { | |||
| 718 | void ConfigureInputPlayer::ConnectPlayer(bool connected) { | 718 | void ConfigureInputPlayer::ConnectPlayer(bool connected) { |
| 719 | ui->groupConnectedController->setChecked(connected); | 719 | ui->groupConnectedController->setChecked(connected); |
| 720 | if (connected) { | 720 | if (connected) { |
| 721 | emulated_controller->Connect(); | 721 | emulated_controller->Connect(true); |
| 722 | } else { | 722 | } else { |
| 723 | emulated_controller->Disconnect(); | 723 | emulated_controller->Disconnect(); |
| 724 | } | 724 | } |
| @@ -907,78 +907,63 @@ void ConfigureInputPlayer::UpdateUI() { | |||
| 907 | } | 907 | } |
| 908 | 908 | ||
| 909 | void ConfigureInputPlayer::SetConnectableControllers() { | 909 | void ConfigureInputPlayer::SetConnectableControllers() { |
| 910 | Core::HID::NpadStyleTag npad_style_set = hid_core.GetSupportedStyleTag(); | 910 | const auto npad_style_set = hid_core.GetSupportedStyleTag(); |
| 911 | index_controller_type_pairs.clear(); | 911 | index_controller_type_pairs.clear(); |
| 912 | ui->comboControllerType->clear(); | 912 | ui->comboControllerType->clear(); |
| 913 | 913 | ||
| 914 | const auto add_item = [&](Core::HID::NpadStyleIndex controller_type, | ||
| 915 | const QString& controller_name) { | ||
| 916 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), controller_type); | ||
| 917 | ui->comboControllerType->addItem(controller_name); | ||
| 918 | }; | ||
| 919 | |||
| 914 | if (npad_style_set.fullkey == 1) { | 920 | if (npad_style_set.fullkey == 1) { |
| 915 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 921 | add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); |
| 916 | Core::HID::NpadStyleIndex::ProController); | ||
| 917 | ui->comboControllerType->addItem(tr("Pro Controller")); | ||
| 918 | } | 922 | } |
| 919 | 923 | ||
| 920 | if (npad_style_set.joycon_dual == 1) { | 924 | if (npad_style_set.joycon_dual == 1) { |
| 921 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 925 | add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons")); |
| 922 | Core::HID::NpadStyleIndex::JoyconDual); | ||
| 923 | ui->comboControllerType->addItem(tr("Dual Joycons")); | ||
| 924 | } | 926 | } |
| 925 | 927 | ||
| 926 | if (npad_style_set.joycon_left == 1) { | 928 | if (npad_style_set.joycon_left == 1) { |
| 927 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 929 | add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon")); |
| 928 | Core::HID::NpadStyleIndex::JoyconLeft); | ||
| 929 | ui->comboControllerType->addItem(tr("Left Joycon")); | ||
| 930 | } | 930 | } |
| 931 | 931 | ||
| 932 | if (npad_style_set.joycon_right == 1) { | 932 | if (npad_style_set.joycon_right == 1) { |
| 933 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 933 | add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon")); |
| 934 | Core::HID::NpadStyleIndex::JoyconRight); | ||
| 935 | ui->comboControllerType->addItem(tr("Right Joycon")); | ||
| 936 | } | 934 | } |
| 937 | 935 | ||
| 938 | if (player_index == 0 && npad_style_set.handheld == 1) { | 936 | if (player_index == 0 && npad_style_set.handheld == 1) { |
| 939 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 937 | add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld")); |
| 940 | Core::HID::NpadStyleIndex::Handheld); | ||
| 941 | ui->comboControllerType->addItem(tr("Handheld")); | ||
| 942 | } | 938 | } |
| 943 | 939 | ||
| 944 | if (npad_style_set.gamecube == 1) { | 940 | if (npad_style_set.gamecube == 1) { |
| 945 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 941 | add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller")); |
| 946 | Core::HID::NpadStyleIndex::GameCube); | ||
| 947 | ui->comboControllerType->addItem(tr("GameCube Controller")); | ||
| 948 | } | 942 | } |
| 949 | 943 | ||
| 950 | // Disable all unsupported controllers | 944 | // Disable all unsupported controllers |
| 951 | if (!Settings::values.enable_all_controllers) { | 945 | if (!Settings::values.enable_all_controllers) { |
| 952 | return; | 946 | return; |
| 953 | } | 947 | } |
| 948 | |||
| 954 | if (npad_style_set.palma == 1) { | 949 | if (npad_style_set.palma == 1) { |
| 955 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 950 | add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus")); |
| 956 | Core::HID::NpadStyleIndex::Pokeball); | ||
| 957 | ui->comboControllerType->addItem(tr("Poke Ball Plus")); | ||
| 958 | } | 951 | } |
| 959 | 952 | ||
| 960 | if (npad_style_set.lark == 1) { | 953 | if (npad_style_set.lark == 1) { |
| 961 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 954 | add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller")); |
| 962 | Core::HID::NpadStyleIndex::NES); | ||
| 963 | ui->comboControllerType->addItem(tr("NES Controller")); | ||
| 964 | } | 955 | } |
| 965 | 956 | ||
| 966 | if (npad_style_set.lucia == 1) { | 957 | if (npad_style_set.lucia == 1) { |
| 967 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 958 | add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller")); |
| 968 | Core::HID::NpadStyleIndex::SNES); | ||
| 969 | ui->comboControllerType->addItem(tr("SNES Controller")); | ||
| 970 | } | 959 | } |
| 971 | 960 | ||
| 972 | if (npad_style_set.lagoon == 1) { | 961 | if (npad_style_set.lagoon == 1) { |
| 973 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 962 | add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller")); |
| 974 | Core::HID::NpadStyleIndex::N64); | ||
| 975 | ui->comboControllerType->addItem(tr("N64 Controller")); | ||
| 976 | } | 963 | } |
| 977 | 964 | ||
| 978 | if (npad_style_set.lager == 1) { | 965 | if (npad_style_set.lager == 1) { |
| 979 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | 966 | add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis")); |
| 980 | Core::HID::NpadStyleIndex::SegaGenesis); | ||
| 981 | ui->comboControllerType->addItem(tr("Sega Genesis")); | ||
| 982 | } | 967 | } |
| 983 | } | 968 | } |
| 984 | 969 | ||
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 1a5e41588..8b5c4a10a 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -173,13 +173,17 @@ void GameList::OnItemExpanded(const QModelIndex& item) { | |||
| 173 | const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || | 173 | const bool is_dir = type == GameListItemType::CustomDir || type == GameListItemType::SdmcDir || |
| 174 | type == GameListItemType::UserNandDir || | 174 | type == GameListItemType::UserNandDir || |
| 175 | type == GameListItemType::SysNandDir; | 175 | type == GameListItemType::SysNandDir; |
| 176 | 176 | const bool is_fave = type == GameListItemType::Favorites; | |
| 177 | if (!is_dir) { | 177 | if (!is_dir && !is_fave) { |
| 178 | return; | 178 | return; |
| 179 | } | 179 | } |
| 180 | 180 | const bool is_expanded = tree_view->isExpanded(item); | |
| 181 | UISettings::values.game_dirs[item.data(GameListDir::GameDirRole).toInt()].expanded = | 181 | if (is_fave) { |
| 182 | tree_view->isExpanded(item); | 182 | UISettings::values.favorites_expanded = is_expanded; |
| 183 | return; | ||
| 184 | } | ||
| 185 | const int item_dir_index = item.data(GameListDir::GameDirRole).toInt(); | ||
| 186 | UISettings::values.game_dirs[item_dir_index].expanded = is_expanded; | ||
| 183 | } | 187 | } |
| 184 | 188 | ||
| 185 | // Event in order to filter the gamelist after editing the searchfield | 189 | // Event in order to filter the gamelist after editing the searchfield |
| @@ -458,10 +462,13 @@ void GameList::DonePopulating(const QStringList& watch_list) { | |||
| 458 | emit ShowList(!IsEmpty()); | 462 | emit ShowList(!IsEmpty()); |
| 459 | 463 | ||
| 460 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); | 464 | item_model->invisibleRootItem()->appendRow(new GameListAddDir()); |
| 465 | |||
| 466 | // Add favorites row | ||
| 461 | item_model->invisibleRootItem()->insertRow(0, new GameListFavorites()); | 467 | item_model->invisibleRootItem()->insertRow(0, new GameListFavorites()); |
| 462 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), | 468 | tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), |
| 463 | UISettings::values.favorited_ids.size() == 0); | 469 | UISettings::values.favorited_ids.size() == 0); |
| 464 | tree_view->expand(item_model->invisibleRootItem()->child(0)->index()); | 470 | tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(), |
| 471 | UISettings::values.favorites_expanded.GetValue()); | ||
| 465 | for (const auto id : UISettings::values.favorited_ids) { | 472 | for (const auto id : UISettings::values.favorited_ids) { |
| 466 | AddFavorite(id); | 473 | AddFavorite(id); |
| 467 | } | 474 | } |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b7bb43348..53f11a9ac 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1236,11 +1236,58 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | |||
| 1236 | } | 1236 | } |
| 1237 | } | 1237 | } |
| 1238 | 1238 | ||
| 1239 | #ifdef __linux__ | ||
| 1240 | static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) { | ||
| 1241 | if (!QDBusConnection::sessionBus().isConnected()) { | ||
| 1242 | return {}; | ||
| 1243 | } | ||
| 1244 | // reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit | ||
| 1245 | QDBusInterface xdp(QString::fromLatin1("org.freedesktop.portal.Desktop"), | ||
| 1246 | QString::fromLatin1("/org/freedesktop/portal/desktop"), | ||
| 1247 | QString::fromLatin1("org.freedesktop.portal.Inhibit")); | ||
| 1248 | if (!xdp.isValid()) { | ||
| 1249 | LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint"); | ||
| 1250 | return {}; | ||
| 1251 | } | ||
| 1252 | QVariantMap options = {}; | ||
| 1253 | //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the | ||
| 1254 | //: computer from sleeping | ||
| 1255 | options.insert(QString::fromLatin1("reason"), | ||
| 1256 | QCoreApplication::translate("GMainWindow", "yuzu is running a game")); | ||
| 1257 | // 0x4: Suspend lock; 0x8: Idle lock | ||
| 1258 | QDBusReply<QDBusObjectPath> reply = | ||
| 1259 | xdp.call(QString::fromLatin1("Inhibit"), | ||
| 1260 | QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options); | ||
| 1261 | |||
| 1262 | if (reply.isValid()) { | ||
| 1263 | return reply.value(); | ||
| 1264 | } | ||
| 1265 | LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}", | ||
| 1266 | reply.error().message().toStdString()); | ||
| 1267 | return {}; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | static void ReleaseWakeLockLinux(QDBusObjectPath lock) { | ||
| 1271 | if (!QDBusConnection::sessionBus().isConnected()) { | ||
| 1272 | return; | ||
| 1273 | } | ||
| 1274 | QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(), | ||
| 1275 | QString::fromLatin1("org.freedesktop.portal.Request")); | ||
| 1276 | unlocker.call(QString::fromLatin1("Close")); | ||
| 1277 | } | ||
| 1278 | #endif // __linux__ | ||
| 1279 | |||
| 1239 | void GMainWindow::PreventOSSleep() { | 1280 | void GMainWindow::PreventOSSleep() { |
| 1240 | #ifdef _WIN32 | 1281 | #ifdef _WIN32 |
| 1241 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); | 1282 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); |
| 1242 | #elif defined(HAVE_SDL2) | 1283 | #elif defined(HAVE_SDL2) |
| 1243 | SDL_DisableScreenSaver(); | 1284 | SDL_DisableScreenSaver(); |
| 1285 | #ifdef __linux__ | ||
| 1286 | auto reply = HoldWakeLockLinux(winId()); | ||
| 1287 | if (reply) { | ||
| 1288 | wake_lock = std::move(reply.value()); | ||
| 1289 | } | ||
| 1290 | #endif | ||
| 1244 | #endif | 1291 | #endif |
| 1245 | } | 1292 | } |
| 1246 | 1293 | ||
| @@ -1249,6 +1296,11 @@ void GMainWindow::AllowOSSleep() { | |||
| 1249 | SetThreadExecutionState(ES_CONTINUOUS); | 1296 | SetThreadExecutionState(ES_CONTINUOUS); |
| 1250 | #elif defined(HAVE_SDL2) | 1297 | #elif defined(HAVE_SDL2) |
| 1251 | SDL_EnableScreenSaver(); | 1298 | SDL_EnableScreenSaver(); |
| 1299 | #ifdef __linux__ | ||
| 1300 | if (!wake_lock.path().isEmpty()) { | ||
| 1301 | ReleaseWakeLockLinux(wake_lock); | ||
| 1302 | } | ||
| 1303 | #endif | ||
| 1252 | #endif | 1304 | #endif |
| 1253 | } | 1305 | } |
| 1254 | 1306 | ||
| @@ -1495,6 +1547,8 @@ void GMainWindow::ShutdownGame() { | |||
| 1495 | emu_thread->wait(); | 1547 | emu_thread->wait(); |
| 1496 | emu_thread = nullptr; | 1548 | emu_thread = nullptr; |
| 1497 | 1549 | ||
| 1550 | emulation_running = false; | ||
| 1551 | |||
| 1498 | discord_rpc->Update(); | 1552 | discord_rpc->Update(); |
| 1499 | 1553 | ||
| 1500 | // The emulation is stopped, so closing the window or not does not matter anymore | 1554 | // The emulation is stopped, so closing the window or not does not matter anymore |
| @@ -1533,8 +1587,6 @@ void GMainWindow::ShutdownGame() { | |||
| 1533 | emu_frametime_label->setVisible(false); | 1587 | emu_frametime_label->setVisible(false); |
| 1534 | renderer_status_button->setEnabled(true); | 1588 | renderer_status_button->setEnabled(true); |
| 1535 | 1589 | ||
| 1536 | emulation_running = false; | ||
| 1537 | |||
| 1538 | game_path.clear(); | 1590 | game_path.clear(); |
| 1539 | 1591 | ||
| 1540 | // When closing the game, destroy the GLWindow to clear the context after the game is closed | 1592 | // When closing the game, destroy the GLWindow to clear the context after the game is closed |
| @@ -2546,39 +2598,30 @@ void GMainWindow::ToggleFullscreen() { | |||
| 2546 | } | 2598 | } |
| 2547 | 2599 | ||
| 2548 | void GMainWindow::ShowFullscreen() { | 2600 | void GMainWindow::ShowFullscreen() { |
| 2601 | const auto show_fullscreen = [](QWidget* window) { | ||
| 2602 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | ||
| 2603 | window->showFullScreen(); | ||
| 2604 | return; | ||
| 2605 | } | ||
| 2606 | window->hide(); | ||
| 2607 | window->setWindowFlags(window->windowFlags() | Qt::FramelessWindowHint); | ||
| 2608 | const auto screen_geometry = QApplication::desktop()->screenGeometry(window); | ||
| 2609 | window->setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(), | ||
| 2610 | screen_geometry.height() + 1); | ||
| 2611 | window->raise(); | ||
| 2612 | window->showNormal(); | ||
| 2613 | }; | ||
| 2614 | |||
| 2549 | if (ui->action_Single_Window_Mode->isChecked()) { | 2615 | if (ui->action_Single_Window_Mode->isChecked()) { |
| 2550 | UISettings::values.geometry = saveGeometry(); | 2616 | UISettings::values.geometry = saveGeometry(); |
| 2551 | 2617 | ||
| 2552 | ui->menubar->hide(); | 2618 | ui->menubar->hide(); |
| 2553 | statusBar()->hide(); | 2619 | statusBar()->hide(); |
| 2554 | 2620 | ||
| 2555 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | 2621 | show_fullscreen(this); |
| 2556 | showFullScreen(); | ||
| 2557 | return; | ||
| 2558 | } | ||
| 2559 | |||
| 2560 | hide(); | ||
| 2561 | setWindowFlags(windowFlags() | Qt::FramelessWindowHint); | ||
| 2562 | const auto screen_geometry = QApplication::desktop()->screenGeometry(this); | ||
| 2563 | setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(), | ||
| 2564 | screen_geometry.height() + 1); | ||
| 2565 | raise(); | ||
| 2566 | showNormal(); | ||
| 2567 | } else { | 2622 | } else { |
| 2568 | UISettings::values.renderwindow_geometry = render_window->saveGeometry(); | 2623 | UISettings::values.renderwindow_geometry = render_window->saveGeometry(); |
| 2569 | 2624 | show_fullscreen(render_window); | |
| 2570 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) { | ||
| 2571 | render_window->showFullScreen(); | ||
| 2572 | return; | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | render_window->hide(); | ||
| 2576 | render_window->setWindowFlags(windowFlags() | Qt::FramelessWindowHint); | ||
| 2577 | const auto screen_geometry = QApplication::desktop()->screenGeometry(this); | ||
| 2578 | render_window->setGeometry(screen_geometry.x(), screen_geometry.y(), | ||
| 2579 | screen_geometry.width(), screen_geometry.height() + 1); | ||
| 2580 | render_window->raise(); | ||
| 2581 | render_window->showNormal(); | ||
| 2582 | } | 2625 | } |
| 2583 | } | 2626 | } |
| 2584 | 2627 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 0fd41ed4f..7870bb963 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -17,6 +17,12 @@ | |||
| 17 | #include "yuzu/compatibility_list.h" | 17 | #include "yuzu/compatibility_list.h" |
| 18 | #include "yuzu/hotkeys.h" | 18 | #include "yuzu/hotkeys.h" |
| 19 | 19 | ||
| 20 | #ifdef __linux__ | ||
| 21 | #include <QVariant> | ||
| 22 | #include <QtDBus/QDBusInterface> | ||
| 23 | #include <QtDBus/QtDBus> | ||
| 24 | #endif | ||
| 25 | |||
| 20 | class Config; | 26 | class Config; |
| 21 | class EmuThread; | 27 | class EmuThread; |
| 22 | class GameList; | 28 | class GameList; |
| @@ -394,6 +400,9 @@ private: | |||
| 394 | 400 | ||
| 395 | // Applets | 401 | // Applets |
| 396 | QtSoftwareKeyboardDialog* software_keyboard = nullptr; | 402 | QtSoftwareKeyboardDialog* software_keyboard = nullptr; |
| 403 | #ifdef __linux__ | ||
| 404 | QDBusObjectPath wake_lock{}; | ||
| 405 | #endif | ||
| 397 | 406 | ||
| 398 | protected: | 407 | protected: |
| 399 | void dropEvent(QDropEvent* event) override; | 408 | void dropEvent(QDropEvent* event) override; |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 936914ef3..a610e7e25 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -74,7 +74,6 @@ struct Values { | |||
| 74 | QString game_dir_deprecated; | 74 | QString game_dir_deprecated; |
| 75 | bool game_dir_deprecated_deepscan; | 75 | bool game_dir_deprecated_deepscan; |
| 76 | QVector<UISettings::GameDir> game_dirs; | 76 | QVector<UISettings::GameDir> game_dirs; |
| 77 | QVector<u64> favorited_ids; | ||
| 78 | QStringList recent_files; | 77 | QStringList recent_files; |
| 79 | QString language; | 78 | QString language; |
| 80 | 79 | ||
| @@ -96,6 +95,8 @@ struct Values { | |||
| 96 | Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"}; | 95 | Settings::BasicSetting<uint8_t> row_2_text_id{2, "row_2_text_id"}; |
| 97 | std::atomic_bool is_game_list_reload_pending{false}; | 96 | std::atomic_bool is_game_list_reload_pending{false}; |
| 98 | Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"}; | 97 | Settings::BasicSetting<bool> cache_game_list{true, "cache_game_list"}; |
| 98 | Settings::BasicSetting<bool> favorites_expanded{true, "favorites_expanded"}; | ||
| 99 | QVector<u64> favorited_ids; | ||
| 99 | 100 | ||
| 100 | bool configuration_applied; | 101 | bool configuration_applied; |
| 101 | bool reset_to_defaults; | 102 | bool reset_to_defaults; |