diff options
Diffstat (limited to '')
47 files changed, 1441 insertions, 713 deletions
diff --git a/.ci/scripts/common/post-upload.sh b/.ci/scripts/common/post-upload.sh index bb4e9d328..b80868635 100644 --- a/.ci/scripts/common/post-upload.sh +++ b/.ci/scripts/common/post-upload.sh @@ -1,12 +1,12 @@ #!/bin/bash -ex # Copy documentation -cp license.txt "$REV_NAME" -cp README.md "$REV_NAME" +cp license.txt "$DIR_NAME" +cp README.md "$DIR_NAME" -tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$REV_NAME" +tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$DIR_NAME" -mv "$REV_NAME" $RELEASE_NAME +mv "$DIR_NAME" $RELEASE_NAME 7z a "$REV_NAME.7z" $RELEASE_NAME diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 090ca75f1..5559a527c 100644 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh @@ -11,5 +11,4 @@ ninja ccache -s -# Ignore zlib's tests, since they aren't gated behind a CMake option. -ctest -VV -E "(example|example64)" -C Release +ctest -VV -C Release diff --git a/.ci/scripts/linux/upload.sh b/.ci/scripts/linux/upload.sh index 0d131d1dd..ecd77e267 100644 --- a/.ci/scripts/linux/upload.sh +++ b/.ci/scripts/linux/upload.sh @@ -6,9 +6,15 @@ REV_NAME="yuzu-linux-${GITDATE}-${GITREV}" ARCHIVE_NAME="${REV_NAME}.tar.xz" COMPRESSION_FLAGS="-cJvf" -mkdir "$REV_NAME" +if [ "${RELEASE_NAME}" = "mainline" ]; then + DIR_NAME="${REV_NAME}_${RELEASE_NAME}" +else + DIR_NAME="${REV_NAME}" +fi -cp build/bin/yuzu-cmd "$REV_NAME" -cp build/bin/yuzu "$REV_NAME" +mkdir "$DIR_NAME" + +cp build/bin/yuzu-cmd "$DIR_NAME" +cp build/bin/yuzu "$DIR_NAME" . .ci/scripts/common/post-upload.sh diff --git a/.ci/scripts/windows/upload.ps1 b/.ci/scripts/windows/upload.ps1 index 3cb709924..9fb99eaa3 100644 --- a/.ci/scripts/windows/upload.ps1 +++ b/.ci/scripts/windows/upload.ps1 @@ -1,6 +1,13 @@ +param($BUILD_NAME) + $GITDATE = $(git show -s --date=short --format='%ad') -replace "-","" $GITREV = $(git show -s --format='%h') -$RELEASE_DIST = "yuzu-windows-msvc" + +if ("$BUILD_NAME" -eq "mainline") { + $RELEASE_DIST = "yuzu-windows-msvc-$BUILD_NAME" +} else { + $RELEASE_DIST = "yuzu-windows-msvc" +} $MSVC_BUILD_ZIP = "yuzu-windows-msvc-$GITDATE-$GITREV.zip" -replace " ", "" $MSVC_BUILD_PDB = "yuzu-windows-msvc-$GITDATE-$GITREV-debugsymbols.zip" -replace " ", "" diff --git a/.ci/scripts/windows/upload.sh b/.ci/scripts/windows/upload.sh index de73d3541..41d87159f 100644 --- a/.ci/scripts/windows/upload.sh +++ b/.ci/scripts/windows/upload.sh @@ -6,8 +6,14 @@ REV_NAME="yuzu-windows-mingw-${GITDATE}-${GITREV}" ARCHIVE_NAME="${REV_NAME}.tar.gz" COMPRESSION_FLAGS="-czvf" -mkdir "$REV_NAME" +if [ "${RELEASE_NAME}" = "mainline" ]; then + DIR_NAME="${REV_NAME}_${RELEASE_NAME}" +else + DIR_NAME="${REV_NAME}" +fi + +mkdir "$DIR_NAME" # get around the permission issues -cp -r package/* "$REV_NAME" +cp -r package/* "$DIR_NAME" . .ci/scripts/common/post-upload.sh diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index b44a08247..52cebaee0 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml @@ -17,6 +17,7 @@ steps: inputs: targetType: 'filePath' filePath: './.ci/scripts/windows/upload.ps1' + arguments: '$(BuildName)' - publish: artifacts artifact: 'yuzu-$(BuildName)-windows-msvc' displayName: 'Upload Artifacts' diff --git a/.gitmodules b/.gitmodules index ee0dc6c19..63bf2cda0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,8 +47,8 @@ path = externals/sirit url = https://github.com/ReinUsesLisp/sirit [submodule "libzip"] - path = externals/libzip - url = https://github.com/DarkLordZach/libzip + path = externals/libzip/libzip + url = https://github.com/nih-at/libzip.git [submodule "zlib"] - path = externals/zlib - url = https://github.com/madler/zlib + path = externals/zlib/zlib + url = https://github.com/madler/zlib.git diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index ac7529edd..61ad3487a 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -76,6 +76,7 @@ endif() # zlib add_subdirectory(zlib EXCLUDE_FROM_ALL) +set(ZLIB_LIBRARIES z) # libzip add_subdirectory(libzip EXCLUDE_FROM_ALL) diff --git a/externals/libzip b/externals/libzip deleted file mode 160000 -Subproject bd7a8103e96bc6d50164447f6b7b57bb786d8e2 diff --git a/externals/libzip/CMakeLists.txt b/externals/libzip/CMakeLists.txt new file mode 100644 index 000000000..ea5329fa0 --- /dev/null +++ b/externals/libzip/CMakeLists.txt @@ -0,0 +1,564 @@ +# TODO: +# create usable libtool .la file + +CMAKE_MINIMUM_REQUIRED(VERSION 3.0.2) + +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libzip") + +PROJECT(libzip C) + +OPTION(ENABLE_COMMONCRYPTO "Enable use of CommonCrypto" ON) +OPTION(ENABLE_GNUTLS "Enable use of GnuTLS" ON) +OPTION(ENABLE_MBEDTLS "Enable use of mbed TLS" ON) +OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON) +OPTION(ENABLE_WINDOWS_CRYPTO "Enable use of Windows cryptography libraries" ON) + +OPTION(ENABLE_BZIP2 "Enable use of BZip2" OFF) +OPTION(ENABLE_LZMA "Enable use of LZMA" OFF) + +INCLUDE(CheckFunctionExists) +INCLUDE(CheckIncludeFiles) +INCLUDE(CheckSymbolExists) +INCLUDE(CheckTypeSize) +INCLUDE(CheckCSourceRuns) +INCLUDE(CheckCSourceCompiles) +INCLUDE(CheckStructHasMember) +INCLUDE(TestBigEndian) +INCLUDE(GNUInstallDirs) +IF(ENABLE_COMMONCRYPTO) + CHECK_INCLUDE_FILES(CommonCrypto/CommonCrypto.h COMMONCRYPTO_FOUND) +ELSE() + SET(COMMONCRYPTO_FOUND FALSE) +ENDIF() +IF(ENABLE_GNUTLS) + INCLUDE(FindNettle) + INCLUDE(FindGnuTLS) +ELSE() + SET(GNUTLS_FOUND FALSE) +ENDIF() +IF(ENABLE_MBEDTLS) + FIND_PATH(MBEDTLS_INCLUDE_DIR mbedtls/aes.h) + FIND_LIBRARY(MBEDTLS_LIBRARIES NAMES mbedcrypto) +ELSE() + SET(MBEDTLS_LIBRARIES FALSE) +ENDIF() +IF(ENABLE_OPENSSL) + INCLUDE(FindOpenSSL) +ELSE() + SET(OPENSSL_FOUND FALSE) +ENDIF() +IF(WIN32) + IF(ENABLE_WINDOWS_CRYPTO) + SET(WINDOWS_CRYPTO_FOUND TRUE) + ENDIF() +ELSE() + SET(WINDOWS_CRYPTO_FOUND FALSE) +ENDIF() + +OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON) +OPTION(SHARED_LIB_VERSIONNING "Add SO version in .so build" ON) + +SET(PACKAGE "libzip") +SET(PACKAGE_NAME ${PACKAGE}) +SET(PACKAGE_VERSION_MAJOR "1") +SET(PACKAGE_VERSION_MINOR "5") +SET(PACKAGE_VERSION_MICRO "2a") +#SET(VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}") +SET(VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_MICRO}") +SET(PACKAGE_VERSION ${VERSION}) +SET(LIBZIP_VERSION ${PACKAGE_VERSION}) +SET(LIBZIP_VERSION_MAJOR ${PACKAGE_VERSION_MAJOR}) +SET(LIBZIP_VERSION_MINOR ${PACKAGE_VERSION_MINOR}) +SET(LIBZIP_VERSION_MICRO ${PACKAGE_VERSION_MICRO}) +SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") + +SET(ARCHIVE_NAME ${PACKAGE_NAME}-${PACKAGE_VERSION}) +IF(NOT TARGET dist) +ADD_CUSTOM_TARGET(dist + COMMAND git config tar.tar.xz.command "xz -c" + COMMAND git archive --prefix=${ARCHIVE_NAME}/ -o ${ARCHIVE_NAME}.tar.gz HEAD + COMMAND git archive --prefix=${ARCHIVE_NAME}/ -o ${ARCHIVE_NAME}.tar.xz HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) +ADD_CUSTOM_TARGET(distcheck + COMMAND chmod -R u+w ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest 2>/dev/null || true + COMMAND rm -rf ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest + COMMAND cmake -E tar xf ${ARCHIVE_NAME}.tar.gz + COMMAND chmod -R u-w ${ARCHIVE_NAME} + COMMAND mkdir ${ARCHIVE_NAME}-build + COMMAND mkdir ${ARCHIVE_NAME}-dest + COMMAND cd ${ARCHIVE_NAME}-build && cmake -DCMAKE_INSTALL_PREFIX=../${ARCHIVE_NAME}-dest ../${ARCHIVE_NAME} + COMMAND cd ${ARCHIVE_NAME}-build && make -j4 + COMMAND cd ${ARCHIVE_NAME}-build && make test + COMMAND cd ${ARCHIVE_NAME}-build && make install +# COMMAND cd ${ARCHIVE_NAME}-build && make uninstall +# COMMAND if [ `find ${ARCHIVE_NAME}-dest ! -type d | wc -l` -ne 0 ]; then echo leftover files in ${ARCHIVE_NAME}-dest; false; fi + COMMAND cd ${ARCHIVE_NAME}-build && make clean + COMMAND chmod -R u+w ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest + COMMAND rm -rf ${ARCHIVE_NAME} ${ARCHIVE_NAME}-build ${ARCHIVE_NAME}-dest + COMMAND echo "${ARCHIVE_NAME}.tar.gz is ready for distribution." + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) +ADD_DEPENDENCIES(distcheck dist) +ENDIF(NOT TARGET dist) + +IF(BUILD_SHARED_LIBS) + SET(HAVE_SHARED TRUE) +ELSE() + SET(ZIP_STATIC TRUE) +ENDIF() + +# Checks + +CHECK_FUNCTION_EXISTS(_chmod HAVE__CHMOD) +CHECK_FUNCTION_EXISTS(_close HAVE__CLOSE) +CHECK_FUNCTION_EXISTS(_dup HAVE__DUP) +CHECK_FUNCTION_EXISTS(_fdopen HAVE__FDOPEN) +CHECK_FUNCTION_EXISTS(_fileno HAVE__FILENO) +CHECK_FUNCTION_EXISTS(_open HAVE__OPEN) +CHECK_FUNCTION_EXISTS(_setmode HAVE__SETMODE) +CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF) +CHECK_FUNCTION_EXISTS(_strdup HAVE__STRDUP) +CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP) +CHECK_FUNCTION_EXISTS(_strtoi64 HAVE__STRTOI64) +CHECK_FUNCTION_EXISTS(_strtoui64 HAVE__STRTOUI64) +CHECK_FUNCTION_EXISTS(_unlink HAVE__UNLINK) +CHECK_FUNCTION_EXISTS(arc4random HAVE_ARC4RANDOM) +CHECK_FUNCTION_EXISTS(clonefile HAVE_CLONEFILE) +CHECK_FUNCTION_EXISTS(explicit_bzero HAVE_EXPLICIT_BZERO) +CHECK_FUNCTION_EXISTS(explicit_memset HAVE_EXPLICIT_MEMSET) +CHECK_FUNCTION_EXISTS(fileno HAVE_FILENO) +CHECK_FUNCTION_EXISTS(fseeko HAVE_FSEEKO) +CHECK_FUNCTION_EXISTS(ftello HAVE_FTELLO) +CHECK_FUNCTION_EXISTS(getprogname HAVE_GETPROGNAME) +CHECK_FUNCTION_EXISTS(localtime_r HAVE_LOCALTIME_R) +CHECK_FUNCTION_EXISTS(open HAVE_OPEN) +CHECK_FUNCTION_EXISTS(setmode HAVE_SETMODE) +CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF) +CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP) +CHECK_FUNCTION_EXISTS(strdup HAVE_STRDUP) +CHECK_FUNCTION_EXISTS(stricmp HAVE_STRICMP) +CHECK_FUNCTION_EXISTS(strtoll HAVE_STRTOLL) +CHECK_FUNCTION_EXISTS(strtoull HAVE_STRTOULL) + +CHECK_INCLUDE_FILES("sys/types.h;sys/stat.h;fts.h" HAVE_FTS_H) +CHECK_INCLUDE_FILES(stdbool.h HAVE_STDBOOL_H) +CHECK_INCLUDE_FILES(strings.h HAVE_STRINGS_H) +CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) + +CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H_LIBZIP) +CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H_LIBZIP) +CHECK_INCLUDE_FILES(sys/types.h HAVE_SYS_TYPES_H_LIBZIP) + +# TODO: fix test +# this test does not find __progname even when it exists +#CHECK_SYMBOL_EXISTS(__progname stdlib.h HAVE___PROGNAME) + +CHECK_TYPE_SIZE(__int8 __INT8_LIBZIP) +CHECK_TYPE_SIZE(int8_t INT8_T_LIBZIP) +CHECK_TYPE_SIZE(uint8_t UINT8_T_LIBZIP) +CHECK_TYPE_SIZE(__int16 __INT16_LIBZIP) +CHECK_TYPE_SIZE(int16_t INT16_T_LIBZIP) +CHECK_TYPE_SIZE(uint16_t UINT16_T_LIBZIP) +CHECK_TYPE_SIZE(__int32 __INT32_LIBZIP) +CHECK_TYPE_SIZE(int32_t INT32_T_LIBZIP) +CHECK_TYPE_SIZE(uint32_t UINT32_T_LIBZIP) +CHECK_TYPE_SIZE(__int64 __INT64_LIBZIP) +CHECK_TYPE_SIZE(int64_t INT64_T_LIBZIP) +CHECK_TYPE_SIZE(uint64_t UINT64_T_LIBZIP) +CHECK_TYPE_SIZE("short" SHORT_LIBZIP) +CHECK_TYPE_SIZE("int" INT_LIBZIP) +CHECK_TYPE_SIZE("long" LONG_LIBZIP) +CHECK_TYPE_SIZE("long long" LONG_LONG_LIBZIP) +CHECK_TYPE_SIZE("off_t" SIZEOF_OFF_T) +CHECK_TYPE_SIZE("size_t" SIZE_T_LIBZIP) +CHECK_TYPE_SIZE("ssize_t" SSIZE_T_LIBZIP) + +CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h> +#include <linux/fs.h> +int main(int argc, char *argv[]) { unsigned long x = FICLONERANGE; }" HAVE_FICLONERANGE) + +CHECK_C_SOURCE_COMPILES(" +int foo(char * _Nullable bar); +int main(int argc, char *argv[]) { }" HAVE_NULLABLE) + +TEST_BIG_ENDIAN(WORDS_BIGENDIAN) + +#FIND_PACKAGE(ZLIB 1.1.2 REQUIRED) +INCLUDE_DIRECTORIES(../zlib/zlib) +SET(CMAKE_REQUIRED_INCLUDES ../zlib/zlib) + +IF(ENABLE_BZIP2) + FIND_PACKAGE(BZip2) + IF(BZIP2_FOUND) + SET (HAVE_LIBBZ2 1) + + INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR}) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${BZIP2_LIBRARIES}) + ELSE() + MESSAGE(WARNING "-- bzip2 library not found; bzip2 support disabled") + ENDIF(BZIP2_FOUND) +ENDIF(ENABLE_BZIP2) + +IF(ENABLE_LZMA) + FIND_PACKAGE(LibLZMA) + IF(LIBLZMA_FOUND) + SET (HAVE_LIBLZMA 1) + + INCLUDE_DIRECTORIES(${LIBLZMA_INCLUDE_DIR}) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${LIBLZMA_LIBRARY}) + ELSE() + MESSAGE(WARNING "-- lzma library not found; lzma support disabled") + ENDIF(LIBLZMA_FOUND) +ENDIF(ENABLE_LZMA) + + +IF (COMMONCRYPTO_FOUND) + SET (HAVE_CRYPTO 1) + SET (HAVE_COMMONCRYPTO 1) +ELSEIF (WINDOWS_CRYPTO_FOUND) + SET (HAVE_CRYPTO 1) + SET (HAVE_WINDOWS_CRYPTO 1) +ELSEIF (GNUTLS_FOUND AND NETTLE_FOUND) + SET (HAVE_CRYPTO 1) + SET (HAVE_GNUTLS 1) + INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_DIR} ${NETTLE_INCLUDE_DIR}) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${GNUTLS_LIBRARY} ${NETTLE_LIBRARY}) +ELSEIF (OPENSSL_FOUND) + SET (HAVE_CRYPTO 1) + SET (HAVE_OPENSSL 1) + INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${OPENSSL_LIBRARIES}) +ELSEIF (MBEDTLS_LIBRARIES) + SET (HAVE_CRYPTO 1) + SET (HAVE_MBEDTLS 1) + INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR}) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${MBEDTLS_LIBRARIES}) +ENDIF() + +IF (NOT HAVE_CRYPTO) + MESSAGE(WARNING "-- neither Common Crypto, GnuTLS, mbed TLS, OpenSSL, nor Windows Cryptography found; AES support disabled") +ENDIF() + +IF(MSVC) +ADD_DEFINITIONS("-D_CRT_SECURE_NO_WARNINGS") +ADD_DEFINITIONS("-D_CRT_NONSTDC_NO_DEPRECATE") +ENDIF(MSVC) + +if(WIN32) + if(HAVE_WINDOWS_CRYPTO) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} bcrypt) + endif() + if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) + ADD_DEFINITIONS(-DMS_UWP) + else(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) + SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} advapi32) + endif(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) +endif(WIN32) + +ADD_DEFINITIONS("-DHAVE_CONFIG_H") + +# rpath handling: use rpath in installed binaries +IF(NOT CMAKE_SYSTEM_NAME MATCHES Linux) + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") + SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +ENDIF() + +# fixed size integral types + +IF(HAVE_INTTYPES_H_LIBZIP) + SET(LIBZIP_TYPES_INCLUDE "#define __STDC_FORMAT_MACROS 1 +#include <inttypes.h>") +ELSEIF(HAVE_STDINT_H_LIBZIP) + SET(LIBZIP_TYPES_INCLUDE "#include <stdint.h>") +ELSEIF(HAVE_SYS_TYPES_H_LIBZIP) + SET(LIBZIP_TYPES_INCLUDE "#include <sys/types.h>") +ENDIF() + +IF(HAVE_INT8_T_LIBZIP) + SET(ZIP_INT8_T int8_t) +ELSEIF(HAVE___INT8_LIBZIP) + SET(ZIP_INT8_T __int8) +ELSE() + SET(ZIP_INT8_T "signed char") +ENDIF() + +IF(HAVE_UINT8_T_LIBZIP) + SET(ZIP_UINT8_T uint8_t) +ELSEIF(HAVE___INT8_LIBZIP) + SET(ZIP_UINT8_T "unsigned __int8") +ELSE() + SET(ZIP_UINT8_T "unsigned char") +ENDIF() + +IF(HAVE_INT16_T_LIBZIP) + SET(ZIP_INT16_T int16_t) +ELSEIF(HAVE___INT16_LIBZIP) + SET(INT16_T_LIBZIP __int16) +ELSEIF(SHORT_LIBZIP EQUAL 2) + SET(INT16_T_LIBZIP short) +ENDIF() + +IF(HAVE_UINT16_T_LIBZIP) + SET(ZIP_UINT16_T uint16_t) +ELSEIF(HAVE___INT16_LIBZIP) + SET(UINT16_T_LIBZIP "unsigned __int16") +ELSEIF(SHORT_LIBZIP EQUAL 2) + SET(UINT16_T_LIBZIP "unsigned short") +ENDIF() + +IF(HAVE_INT32_T_LIBZIP) + SET(ZIP_INT32_T int32_t) +ELSEIF(HAVE___INT32_LIBZIP) + SET(ZIP_INT32_T __int32) +ELSEIF(INT_LIBZIP EQUAL 4) + SET(ZIP_INT32_T int) +ELSEIF(LONG_LIBZIP EQUAL 4) + SET(ZIP_INT32_T long) +ENDIF() + +IF(HAVE_UINT32_T_LIBZIP) +SET(ZIP_UINT32_T uint32_t) +ELSEIF(HAVE___INT32_LIBZIP) +SET(ZIP_UINT32_T "unsigned __int32") +ELSEIF(INT_LIBZIP EQUAL 4) +SET(ZIP_UINT32_T "unsigned int") +ELSEIF(LONG_LIBZIP EQUAL 4) +SET(ZIP_UINT32_T "unsigned long") +ENDIF() + +IF(HAVE_INT64_T_LIBZIP) + SET(ZIP_INT64_T int64_t) +ELSEIF(HAVE___INT64_LIBZIP) + SET(ZIP_INT64_T __int64) +ELSEIF(LONG_LIBZIP EQUAL 8) + SET(ZIP_INT64_T long) +ELSEIF(LONG_LONG_LIBZIP EQUAL 8) + SET(ZIP_INT64_T "long long") +ENDIF() + +IF(HAVE_UINT64_T_LIBZIP) + SET(ZIP_UINT64_T uint64_t) +ELSEIF(HAVE___INT64_LIBZIP) + SET(ZIP_UINT64_T "unsigned __int64") +ELSEIF(LONG_LIBZIP EQUAL 8) + SET(ZIP_UINT64_T "unsigned long") +ELSEIF(LONG_LONG_LIBZIP EQUAL 8) + SET(ZIP_UINT64_T "unsigned long long") +ENDIF() + +IF(HAVE_NULLABLE) + SET(ZIP_NULLABLE_DEFINES) +ELSE() + SET(ZIP_NULLABLE_DEFINES "#define _Nullable +#define _Nonnull") +ENDIF() + +# write out config file +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libzip/cmake-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/libzip/config.h) +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libzip/cmake-zipconf.h.in ${CMAKE_CURRENT_BINARY_DIR}/libzip/zipconf.h) + +# installation +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libzip/zipconf.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +INSTALL(FILES libzip/lib/zip.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +SET(CMAKE_C_VISIBILITY_PRESET hidden) + +ADD_LIBRARY(zip + libzip/lib/zip_add.c + libzip/lib/zip_add_dir.c + libzip/lib/zip_add_entry.c + libzip/lib/zip_algorithm_deflate.c + libzip/lib/zip_buffer.c + libzip/lib/zip_close.c + libzip/lib/zip_delete.c + libzip/lib/zip_dir_add.c + libzip/lib/zip_dirent.c + libzip/lib/zip_discard.c + libzip/lib/zip_entry.c + libzip/lib/zip_err_str.c + libzip/lib/zip_error.c + libzip/lib/zip_error_clear.c + libzip/lib/zip_error_get.c + libzip/lib/zip_error_get_sys_type.c + libzip/lib/zip_error_strerror.c + libzip/lib/zip_error_to_str.c + libzip/lib/zip_extra_field.c + libzip/lib/zip_extra_field_api.c + libzip/lib/zip_fclose.c + libzip/lib/zip_fdopen.c + libzip/lib/zip_file_add.c + libzip/lib/zip_file_error_clear.c + libzip/lib/zip_file_error_get.c + libzip/lib/zip_file_get_comment.c + libzip/lib/zip_file_get_external_attributes.c + libzip/lib/zip_file_get_offset.c + libzip/lib/zip_file_rename.c + libzip/lib/zip_file_replace.c + libzip/lib/zip_file_set_comment.c + libzip/lib/zip_file_set_encryption.c + libzip/lib/zip_file_set_external_attributes.c + libzip/lib/zip_file_set_mtime.c + libzip/lib/zip_file_strerror.c + libzip/lib/zip_filerange_crc.c + libzip/lib/zip_fopen.c + libzip/lib/zip_fopen_encrypted.c + libzip/lib/zip_fopen_index.c + libzip/lib/zip_fopen_index_encrypted.c + libzip/lib/zip_fread.c + libzip/lib/zip_fseek.c + libzip/lib/zip_ftell.c + libzip/lib/zip_get_archive_comment.c + libzip/lib/zip_get_archive_flag.c + libzip/lib/zip_get_encryption_implementation.c + libzip/lib/zip_get_file_comment.c + libzip/lib/zip_get_name.c + libzip/lib/zip_get_num_entries.c + libzip/lib/zip_get_num_files.c + libzip/lib/zip_hash.c + libzip/lib/zip_io_util.c + libzip/lib/zip_libzip_version.c + libzip/lib/zip_memdup.c + libzip/lib/zip_name_locate.c + libzip/lib/zip_new.c + libzip/lib/zip_open.c + libzip/lib/zip_progress.c + libzip/lib/zip_rename.c + libzip/lib/zip_replace.c + libzip/lib/zip_set_archive_comment.c + libzip/lib/zip_set_archive_flag.c + libzip/lib/zip_set_default_password.c + libzip/lib/zip_set_file_comment.c + libzip/lib/zip_set_file_compression.c + libzip/lib/zip_set_name.c + libzip/lib/zip_source_accept_empty.c + libzip/lib/zip_source_begin_write.c + libzip/lib/zip_source_begin_write_cloning.c + libzip/lib/zip_source_buffer.c + libzip/lib/zip_source_call.c + libzip/lib/zip_source_close.c + libzip/lib/zip_source_commit_write.c + libzip/lib/zip_source_compress.c + libzip/lib/zip_source_crc.c + libzip/lib/zip_source_error.c + libzip/lib/zip_source_filep.c + libzip/lib/zip_source_free.c + libzip/lib/zip_source_function.c + libzip/lib/zip_source_get_compression_flags.c + libzip/lib/zip_source_is_deleted.c + libzip/lib/zip_source_layered.c + libzip/lib/zip_source_open.c + libzip/lib/zip_source_pkware.c + libzip/lib/zip_source_read.c + libzip/lib/zip_source_remove.c + libzip/lib/zip_source_rollback_write.c + libzip/lib/zip_source_seek.c + libzip/lib/zip_source_seek_write.c + libzip/lib/zip_source_stat.c + libzip/lib/zip_source_supports.c + libzip/lib/zip_source_tell.c + libzip/lib/zip_source_tell_write.c + libzip/lib/zip_source_window.c + libzip/lib/zip_source_write.c + libzip/lib/zip_source_zip.c + libzip/lib/zip_source_zip_new.c + libzip/lib/zip_stat.c + libzip/lib/zip_stat_index.c + libzip/lib/zip_stat_init.c + libzip/lib/zip_strerror.c + libzip/lib/zip_string.c + libzip/lib/zip_unchange.c + libzip/lib/zip_unchange_all.c + libzip/lib/zip_unchange_archive.c + libzip/lib/zip_unchange_data.c + libzip/lib/zip_utf-8.c +) + +IF(WIN32) + target_sources(zip PRIVATE + libzip/lib/zip_source_win32handle.c + libzip/lib/zip_source_win32utf8.c + libzip/lib/zip_source_win32w.c + ) + IF(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) + ELSE() + target_sources(zip PRIVATE libzip/lib/zip_source_win32a.c) + ENDIF() +ELSE() + target_sources(zip PRIVATE + libzip/lib/zip_mkstempm.c + libzip/lib/zip_source_file.c + libzip/lib/zip_random_unix.c + ) +ENDIF() + +IF(HAVE_LIBBZ2) + target_sources(zip PRIVATE libzip/lib/zip_algorithm_bzip2.c) +ENDIF() + +IF(HAVE_LIBLZMA) + target_sources(zip PRIVATE libzip/lib/zip_algorithm_xz.c) +ENDIF() + +IF(HAVE_COMMONCRYPTO) + target_sources(zip PRIVATE libzip/lib/zip_crypto_commoncrypto.c) +ELSEIF(HAVE_WINDOWS_CRYPTO) + target_sources(zip PRIVATE libzip/lib/zip_crypto_win.c) +ELSEIF(HAVE_GNUTLS) + target_sources(zip PRIVATE libzip/lib/zip_crypto_gnutls.c) +ELSEIF(HAVE_OPENSSL) + target_sources(zip PRIVATE libzip/lib/zip_crypto_openssl.c) +ELSEIF(HAVE_MBEDTLS) + target_sources(zip PRIVATE libzip/lib/zip_crypto_mbedtls.c) +ENDIF() + +IF(HAVE_CRYPTO) + target_sources(zip PRIVATE + libzip/lib/zip_winzip_aes.c + libzip/lib/zip_source_winzip_aes_decode.c + libzip/lib/zip_source_winzip_aes_encode.c + ) +ENDIF() + +target_include_directories(zip +PUBLIC + libzip/lib + ${CMAKE_CURRENT_BINARY_DIR}/libzip +) + +# pkgconfig file +SET(prefix ${CMAKE_INSTALL_PREFIX}) +SET(exec_prefix \${prefix}) +SET(bindir \${exec_prefix}/${CMAKE_INSTALL_BINDIR}) +SET(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR}) +SET(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR}) +IF(CMAKE_SYSTEM_NAME MATCHES BSD) + SET(PKG_CONFIG_RPATH "-Wl,-R\${libdir}") +ENDIF(CMAKE_SYSTEM_NAME MATCHES BSD) +get_target_property(LIBS_PRIVATE zip LINK_LIBRARIES) +foreach(LIB ${LIBS_PRIVATE}) + if(LIB MATCHES "^/") + get_filename_component(LIB ${LIB} NAME_WE) + string(REGEX REPLACE "^lib" "" LIB ${LIB}) + endif() + set(LIBS "${LIBS} -l${LIB}") +endforeach() +CONFIGURE_FILE(libzip/libzip.pc.in libzip/libzip.pc @ONLY) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libzip.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +ADD_CUSTOM_TARGET(update_zip_err_str + COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/libzip/lib/make_zip_err_str.sh ${CMAKE_CURRENT_SOURCE_DIR}/libzip/lib/zip.h ${CMAKE_CURRENT_SOURCE_DIR}/libzip/lib/zip_err_str.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libzip/lib/zip.h ${CMAKE_CURRENT_SOURCE_DIR}/libzip/lib/make_zip_err_str.sh +) + +IF(SHARED_LIB_VERSIONNING) +SET_TARGET_PROPERTIES(zip PROPERTIES VERSION 5.0 SOVERSION 5) +ENDIF() + +TARGET_LINK_LIBRARIES(zip ${ZLIB_LIBRARIES} ${OPTIONAL_LIBRARY}) +INSTALL(TARGETS zip + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + diff --git a/externals/libzip/libzip b/externals/libzip/libzip new file mode 160000 +Subproject 89bd6d63bdea9da7627695f6c82e54f16d368b5 diff --git a/externals/zlib/CMakeLists.txt b/externals/zlib/CMakeLists.txt new file mode 100644 index 000000000..0ca32aae4 --- /dev/null +++ b/externals/zlib/CMakeLists.txt @@ -0,0 +1,81 @@ +project(zlib C) + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# Check to see if we have large file support +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# Check for fseeko +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# Check for unistd.h +check_include_file(unistd.h HAVE_UNISTD_H) +if(HAVE_UNISTD_H) + add_definitions(-DHAVE_UNISTD_H) +endif() + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) +endif() + +add_library(z STATIC + zlib/adler32.c + zlib/compress.c + zlib/crc32.c + zlib/crc32.h + zlib/deflate.c + zlib/deflate.h + zlib/gzclose.c + zlib/gzguts.h + zlib/gzlib.c + zlib/gzread.c + zlib/gzwrite.c + zlib/inffast.h + zlib/inffixed.h + zlib/inflate.c + zlib/inflate.h + zlib/infback.c + zlib/inftrees.c + zlib/inftrees.h + zlib/inffast.c + zlib/trees.c + zlib/trees.h + zlib/uncompr.c + zlib/zconf.h + zlib/zlib.h + zlib/zutil.c + zlib/zutil.h +) +add_library(ZLIB::ZLIB ALIAS z) + +target_include_directories(z +PUBLIC + zlib/ +) diff --git a/externals/zlib b/externals/zlib/zlib -Subproject cacf7f1d4e3d44d871b605da3b647f07d718623 +Subproject cacf7f1d4e3d44d871b605da3b647f07d718623 diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 902e668e3..fd2bbbd99 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h @@ -36,6 +36,13 @@ #include "common/common_funcs.h" #include "common/swap.h" +// Inlining +#ifdef _WIN32 +#define FORCE_INLINE __forceinline +#else +#define FORCE_INLINE inline __attribute__((always_inline)) +#endif + /* * Abstract bitfield class * @@ -168,11 +175,11 @@ public: constexpr BitField(BitField&&) noexcept = default; constexpr BitField& operator=(BitField&&) noexcept = default; - constexpr FORCE_INLINE operator T() const { + constexpr operator T() const { return Value(); } - constexpr FORCE_INLINE void Assign(const T& value) { + constexpr void Assign(const T& value) { storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value); } diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 04ecac959..c029dc7b3 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -1,10 +1,11 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include <algorithm> +#include <array> #include <string> #if !defined(ARCHITECTURE_x86_64) @@ -16,18 +17,15 @@ #define CONCAT2(x, y) DO_CONCAT2(x, y) #define DO_CONCAT2(x, y) x##y -// helper macro to properly align structure members. -// Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121", -// depending on the current source line to make sure variable names are unique. -#define INSERT_PADDING_BYTES(num_bytes) u8 CONCAT2(pad, __LINE__)[(num_bytes)] -#define INSERT_PADDING_WORDS(num_words) u32 CONCAT2(pad, __LINE__)[(num_words)] +/// Helper macros to insert unused bytes or words to properly align structs. These values will be +/// zero-initialized. +#define INSERT_PADDING_BYTES(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__){}; +#define INSERT_PADDING_WORDS(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__){}; -// Inlining -#ifdef _WIN32 -#define FORCE_INLINE __forceinline -#else -#define FORCE_INLINE inline __attribute__((always_inline)) -#endif +/// These are similar to the INSERT_PADDING_* macros, but are needed for padding unions. This is +/// because unions can only be initialized by one member. +#define INSERT_UNION_PADDING_BYTES(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__); +#define INSERT_UNION_PADDING_WORDS(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__); #ifndef _MSC_VER diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index ea5c92f61..b8bbdd1ef 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -32,11 +32,28 @@ enum class NCASectionFilesystemType : u8 { ROMFS = 0x3, }; +struct IVFCLevel { + u64_le offset; + u64_le size; + u32_le block_size; + u32_le reserved; +}; +static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size."); + +struct IVFCHeader { + u32_le magic; + u32_le magic_number; + INSERT_UNION_PADDING_BYTES(8); + std::array<IVFCLevel, 6> levels; + INSERT_UNION_PADDING_BYTES(64); +}; +static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); + struct NCASectionHeaderBlock { - INSERT_PADDING_BYTES(3); + INSERT_UNION_PADDING_BYTES(3); NCASectionFilesystemType filesystem_type; NCASectionCryptoType crypto_type; - INSERT_PADDING_BYTES(3); + INSERT_UNION_PADDING_BYTES(3); }; static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); @@ -44,7 +61,7 @@ struct NCASectionRaw { NCASectionHeaderBlock header; std::array<u8, 0x138> block_data; std::array<u8, 0x8> section_ctr; - INSERT_PADDING_BYTES(0xB8); + INSERT_UNION_PADDING_BYTES(0xB8); }; static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size."); @@ -52,19 +69,19 @@ struct PFS0Superblock { NCASectionHeaderBlock header_block; std::array<u8, 0x20> hash; u32_le size; - INSERT_PADDING_BYTES(4); + INSERT_UNION_PADDING_BYTES(4); u64_le hash_table_offset; u64_le hash_table_size; u64_le pfs0_header_offset; u64_le pfs0_size; - INSERT_PADDING_BYTES(0x1B0); + INSERT_UNION_PADDING_BYTES(0x1B0); }; static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size."); struct RomFSSuperblock { NCASectionHeaderBlock header_block; IVFCHeader ivfc; - INSERT_PADDING_BYTES(0x118); + INSERT_UNION_PADDING_BYTES(0x118); }; static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size."); @@ -72,24 +89,24 @@ struct BKTRHeader { u64_le offset; u64_le size; u32_le magic; - INSERT_PADDING_BYTES(0x4); + INSERT_UNION_PADDING_BYTES(0x4); u32_le number_entries; - INSERT_PADDING_BYTES(0x4); + INSERT_UNION_PADDING_BYTES(0x4); }; static_assert(sizeof(BKTRHeader) == 0x20, "BKTRHeader has incorrect size."); struct BKTRSuperblock { NCASectionHeaderBlock header_block; IVFCHeader ivfc; - INSERT_PADDING_BYTES(0x18); + INSERT_UNION_PADDING_BYTES(0x18); BKTRHeader relocation; BKTRHeader subsection; - INSERT_PADDING_BYTES(0xC0); + INSERT_UNION_PADDING_BYTES(0xC0); }; static_assert(sizeof(BKTRSuperblock) == 0x200, "BKTRSuperblock has incorrect size."); union NCASectionHeader { - NCASectionRaw raw; + NCASectionRaw raw{}; PFS0Superblock pfs0; RomFSSuperblock romfs; BKTRSuperblock bktr; diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 0f35639bc..1c89be8a4 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h @@ -13,25 +13,6 @@ namespace FileSys { -struct RomFSHeader; - -struct IVFCLevel { - u64_le offset; - u64_le size; - u32_le block_size; - u32_le reserved; -}; -static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size."); - -struct IVFCHeader { - u32_le magic; - u32_le magic_number; - INSERT_PADDING_BYTES(8); - std::array<IVFCLevel, 6> levels; - INSERT_PADDING_BYTES(64); -}; -static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); - enum class RomFSExtractionType { Full, // Includes data directory Truncated, // Traverses into data directory diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index fc8755c78..e2a7eaf7b 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -16,6 +16,7 @@ namespace FileSys { constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; namespace { + void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) { if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { if (meta.zero_1 != 0) { @@ -52,6 +53,13 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) { meta.user_id[1], meta.user_id[0]); } } + +bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { + return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || + (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User + desc.type == SaveDataType::SaveData && desc.title_id == 0 && desc.save_id == 0); +} + } // Anonymous namespace std::string SaveDataDescriptor::DebugInfo() const { @@ -96,6 +104,10 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, auto out = dir->GetDirectoryRelative(save_directory); + if (out == nullptr && ShouldSaveDataBeAutomaticallyCreated(space, meta)) { + return Create(space, meta); + } + // Return an error if the save data doesn't actually exist. if (out == nullptr) { // TODO(Subv): Find out correct error code. diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index fae54bcc7..7ce313190 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -160,7 +160,7 @@ struct DomainMessageHeader { // Used when responding to an IPC request, Server -> Client. struct { u32_le num_objects; - INSERT_PADDING_WORDS(3); + INSERT_UNION_PADDING_WORDS(3); }; // Used when performing an IPC request, Client -> Server. @@ -171,8 +171,10 @@ struct DomainMessageHeader { BitField<16, 16, u32> size; }; u32_le object_id; - INSERT_PADDING_WORDS(2); + INSERT_UNION_PADDING_WORDS(2); }; + + std::array<u32, 4> raw{}; }; }; static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect"); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index e6dcb9639..0e2dbf13e 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -22,9 +22,9 @@ namespace Kernel { -GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} { - is_reselection_pending = false; -} +GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {} + +GlobalScheduler::~GlobalScheduler() = default; void GlobalScheduler::AddThread(SharedPtr<Thread> thread) { thread_list.push_back(std::move(thread)); @@ -35,24 +35,11 @@ void GlobalScheduler::RemoveThread(const Thread* thread) { thread_list.end()); } -/* - * UnloadThread selects a core and forces it to unload its current thread's context - */ void GlobalScheduler::UnloadThread(s32 core) { Scheduler& sched = system.Scheduler(core); sched.UnloadThread(); } -/* - * SelectThread takes care of selecting the new scheduled thread. - * It does it in 3 steps: - * - First a thread is selected from the top of the priority queue. If no thread - * is obtained then we move to step two, else we are done. - * - Second we try to get a suggested thread that's not assigned to any core or - * that is not the top thread in that core. - * - Third is no suggested thread is found, we do a second pass and pick a running - * thread in another core and swap it with its current thread. - */ void GlobalScheduler::SelectThread(u32 core) { const auto update_thread = [](Thread* thread, Scheduler& sched) { if (thread != sched.selected_thread) { @@ -114,30 +101,19 @@ void GlobalScheduler::SelectThread(u32 core) { update_thread(current_thread, sched); } -/* - * YieldThread takes a thread and moves it to the back of the it's priority list - * This operation can be redundant and no scheduling is changed if marked as so. - */ bool GlobalScheduler::YieldThread(Thread* yielding_thread) { // Note: caller should use critical section, etc. const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); // Yield the thread - ASSERT_MSG(yielding_thread == scheduled_queue[core_id].front(priority), - "Thread yielding without being in front"); + const Thread* const winner = scheduled_queue[core_id].front(priority); + ASSERT_MSG(yielding_thread == winner, "Thread yielding without being in front"); scheduled_queue[core_id].yield(priority); - Thread* winner = scheduled_queue[core_id].front(priority); return AskForReselectionOrMarkRedundant(yielding_thread, winner); } -/* - * YieldThreadAndBalanceLoad takes a thread and moves it to the back of the it's priority list. - * Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or - * a better priority than the next thread in the core. - * This operation can be redundant and no scheduling is changed if marked as so. - */ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. @@ -189,12 +165,6 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { return AskForReselectionOrMarkRedundant(yielding_thread, winner); } -/* - * YieldThreadAndWaitForLoadBalancing takes a thread and moves it out of the scheduling queue - * and into the suggested queue. If no thread can be squeduled afterwards in that core, - * a suggested thread is obtained instead. - * This operation can be redundant and no scheduling is changed if marked as so. - */ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) { // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. @@ -280,7 +250,7 @@ void GlobalScheduler::PreemptThreads() { if (winner->IsRunning()) { UnloadThread(winner->GetProcessorID()); } - TransferToCore(winner->GetPriority(), core_id, winner); + TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner->GetPriority() <= current_thread->GetPriority() ? winner : current_thread; } @@ -313,7 +283,7 @@ void GlobalScheduler::PreemptThreads() { if (winner->IsRunning()) { UnloadThread(winner->GetProcessorID()); } - TransferToCore(winner->GetPriority(), core_id, winner); + TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner; } } @@ -331,12 +301,12 @@ void GlobalScheduler::Unsuggest(u32 priority, u32 core, Thread* thread) { } void GlobalScheduler::Schedule(u32 priority, u32 core, Thread* thread) { - ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); + ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority); } void GlobalScheduler::SchedulePrepend(u32 priority, u32 core, Thread* thread) { - ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); + ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority, false); } @@ -368,7 +338,8 @@ void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* } } -bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner) { +bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, + const Thread* winner) { if (current_thread == winner) { current_thread->IncrementYieldCount(); return true; @@ -386,8 +357,6 @@ void GlobalScheduler::Shutdown() { thread_list.clear(); } -GlobalScheduler::~GlobalScheduler() = default; - Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 core_id) : system(system), cpu_core(cpu_core), core_id(core_id) {} @@ -470,7 +439,7 @@ void Scheduler::SwitchContext() { // Load context of new thread if (new_thread) { - ASSERT_MSG(new_thread->GetProcessorID() == this->core_id, + ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), "Thread must be assigned to this core."); ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, "Thread must be ready to become running."); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index fcae28e0a..f2d6311b8 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -26,6 +26,7 @@ public: explicit GlobalScheduler(Core::System& system); ~GlobalScheduler(); + /// Adds a new thread to the scheduler void AddThread(SharedPtr<Thread> thread); @@ -37,47 +38,57 @@ public: return thread_list; } - // Add a thread to the suggested queue of a cpu core. Suggested threads may be - // picked if no thread is scheduled to run on the core. + /** + * Add a thread to the suggested queue of a cpu core. Suggested threads may be + * picked if no thread is scheduled to run on the core. + */ void Suggest(u32 priority, u32 core, Thread* thread); - // Remove a thread to the suggested queue of a cpu core. Suggested threads may be - // picked if no thread is scheduled to run on the core. + /** + * Remove a thread to the suggested queue of a cpu core. Suggested threads may be + * picked if no thread is scheduled to run on the core. + */ void Unsuggest(u32 priority, u32 core, Thread* thread); - // Add a thread to the scheduling queue of a cpu core. The thread is added at the - // back the queue in its priority level + /** + * Add a thread to the scheduling queue of a cpu core. The thread is added at the + * back the queue in its priority level. + */ void Schedule(u32 priority, u32 core, Thread* thread); - // Add a thread to the scheduling queue of a cpu core. The thread is added at the - // front the queue in its priority level + /** + * Add a thread to the scheduling queue of a cpu core. The thread is added at the + * front the queue in its priority level. + */ void SchedulePrepend(u32 priority, u32 core, Thread* thread); - // Reschedule an already scheduled thread based on a new priority + /// Reschedule an already scheduled thread based on a new priority void Reschedule(u32 priority, u32 core, Thread* thread); - // Unschedule a thread. + /// Unschedules a thread. void Unschedule(u32 priority, u32 core, Thread* thread); - // Transfers a thread into an specific core. If the destination_core is -1 - // it will be unscheduled from its source code and added into its suggested - // queue. + /** + * Transfers a thread into an specific core. If the destination_core is -1 + * it will be unscheduled from its source code and added into its suggested + * queue. + */ void TransferToCore(u32 priority, s32 destination_core, Thread* thread); - /* - * UnloadThread selects a core and forces it to unload its current thread's context - */ + /// Selects a core and forces it to unload its current thread's context void UnloadThread(s32 core); - /* - * SelectThread takes care of selecting the new scheduled thread. - * It does it in 3 steps: - * - First a thread is selected from the top of the priority queue. If no thread - * is obtained then we move to step two, else we are done. - * - Second we try to get a suggested thread that's not assigned to any core or - * that is not the top thread in that core. - * - Third is no suggested thread is found, we do a second pass and pick a running - * thread in another core and swap it with its current thread. + /** + * Takes care of selecting the new scheduled thread in three steps: + * + * 1. First a thread is selected from the top of the priority queue. If no thread + * is obtained then we move to step two, else we are done. + * + * 2. Second we try to get a suggested thread that's not assigned to any core or + * that is not the top thread in that core. + * + * 3. Third is no suggested thread is found, we do a second pass and pick a running + * thread in another core and swap it with its current thread. */ void SelectThread(u32 core); @@ -85,33 +96,37 @@ public: return !scheduled_queue[core_id].empty(); } - /* - * YieldThread takes a thread and moves it to the back of the it's priority list - * This operation can be redundant and no scheduling is changed if marked as so. + /** + * Takes a thread and moves it to the back of the it's priority list. + * + * @note This operation can be redundant and no scheduling is changed if marked as so. */ bool YieldThread(Thread* thread); - /* - * YieldThreadAndBalanceLoad takes a thread and moves it to the back of the it's priority list. + /** + * Takes a thread and moves it to the back of the it's priority list. * Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or * a better priority than the next thread in the core. - * This operation can be redundant and no scheduling is changed if marked as so. + * + * @note This operation can be redundant and no scheduling is changed if marked as so. */ bool YieldThreadAndBalanceLoad(Thread* thread); - /* - * YieldThreadAndWaitForLoadBalancing takes a thread and moves it out of the scheduling queue - * and into the suggested queue. If no thread can be squeduled afterwards in that core, + /** + * Takes a thread and moves it out of the scheduling queue. + * and into the suggested queue. If no thread can be scheduled afterwards in that core, * a suggested thread is obtained instead. - * This operation can be redundant and no scheduling is changed if marked as so. + * + * @note This operation can be redundant and no scheduling is changed if marked as so. */ bool YieldThreadAndWaitForLoadBalancing(Thread* thread); - /* - * PreemptThreads this operation rotates the scheduling queues of threads at - * a preemption priority and then does some core rebalancing. Preemption priorities - * can be found in the array 'preemption_priorities'. This operation happens - * every 10ms. + /** + * Rotates the scheduling queues of threads at a preemption priority and then does + * some core rebalancing. Preemption priorities can be found in the array + * 'preemption_priorities'. + * + * @note This operation happens every 10ms. */ void PreemptThreads(); @@ -130,15 +145,15 @@ public: void Shutdown(); private: - bool AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner); + bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner); static constexpr u32 min_regular_priority = 2; std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue; std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue; - std::atomic<bool> is_reselection_pending; + std::atomic<bool> is_reselection_pending{false}; - // `preemption_priorities` are the priority levels at which the global scheduler - // preempts threads every 10 ms. They are ordered from Core 0 to Core 3 + // The priority levels at which the global scheduler preempts threads every 10 ms. They are + // ordered from Core 0 to Core 3. std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; /// Lists all thread ids that aren't deleted/etc. @@ -181,10 +196,8 @@ public: private: friend class GlobalScheduler; - /** - * Switches the CPU's active thread context to that of the specified thread - * @param new_thread The thread to switch to - */ + + /// Switches the CPU's active thread context to that of the specified thread void SwitchContext(); /** diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 3a32d5b41..3d8a91d22 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1073,9 +1073,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {71, nullptr, "RequestToReboot"}, {80, nullptr, "ExitAndRequestToShowThanksMessage"}, {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, - {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, - {101, nullptr, "SetApplicationCopyrightImage"}, - {102, nullptr, "SetApplicationCopyrightVisibility"}, + {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, + {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, + {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, {110, nullptr, "QueryApplicationPlayStatistics"}, {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, @@ -1103,6 +1103,31 @@ void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestConte rb.Push(RESULT_SUCCESS); } +void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer( + Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void IApplicationFunctions::SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void IApplicationFunctions::SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_visible = rp.Pop<bool>(); + + LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index ccd053c13..2ae9402a8 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -252,6 +252,9 @@ private: void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx); + void InitializeApplicationCopyrightFrameBuffer(Kernel::HLERequestContext& ctx); + void SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx); + void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); bool launch_popped_application_specific = false; diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index a7db26725..eab0d42c9 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -20,9 +20,9 @@ namespace Service::AM::Applets { struct ShowError { u8 mode; bool jump; - INSERT_PADDING_BYTES(4); + INSERT_UNION_PADDING_BYTES(4); bool use_64bit_error_code; - INSERT_PADDING_BYTES(1); + INSERT_UNION_PADDING_BYTES(1); u64 error_code_64; u32 error_code_32; }; @@ -32,7 +32,7 @@ static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); struct ShowErrorRecord { u8 mode; bool jump; - INSERT_PADDING_BYTES(6); + INSERT_UNION_PADDING_BYTES(6); u64 error_code_64; u64 posix_time; }; @@ -41,7 +41,7 @@ static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect si struct SystemErrorArg { u8 mode; bool jump; - INSERT_PADDING_BYTES(6); + INSERT_UNION_PADDING_BYTES(6); u64 error_code_64; std::array<char, 8> language_code; std::array<char, 0x800> main_text; @@ -52,7 +52,7 @@ static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect si struct ApplicationErrorArg { u8 mode; bool jump; - INSERT_PADDING_BYTES(6); + INSERT_UNION_PADDING_BYTES(6); u32 error_code; std::array<char, 8> language_code; std::array<char, 0x800> main_text; @@ -65,6 +65,7 @@ union Error::ErrorArguments { ShowErrorRecord error_record; SystemErrorArg system_error; ApplicationErrorArg application_error; + std::array<u8, 0x1018> raw{}; }; namespace { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index ba1da4181..ecc130f6c 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -203,13 +203,13 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, - {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, + {123, &Hid::SetNpadJoyAssignmentModeSingle, "SetNpadJoyAssignmentModeSingle"}, {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"}, {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"}, {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, - {129, nullptr, "GetNpadHandheldActivationMode"}, + {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"}, {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, @@ -557,10 +557,126 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, applet_resource_user_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { + // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto npad_joy_device_type{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", + npad_id, applet_resource_user_id, npad_joy_device_type); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown_1{rp.Pop<u32>()}; + const auto unknown_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + unknown_1, unknown_2, applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.StartLRAssignmentMode(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.StopLRAssignmentMode(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto mode{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", + applet_resource_user_id, mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } +void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_1{rp.Pop<u32>()}; + const auto npad_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", + applet_resource_user_id, npad_1, npad_2); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + IPC::ResponseBuilder rb{ctx, 2}; + if (controller.SwapNpadAssignment(npad_1, npad_2)) { + rb.Push(RESULT_SUCCESS); + } else { + LOG_ERROR(Service_HID, "Npads are not connected!"); + rb.Push(ERR_NPAD_NOT_CONNECTED); + } +} + void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; @@ -635,47 +751,6 @@ void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration()); } -void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, - applet_resource_user_id); - - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto unknown_1{rp.Pop<u32>()}; - const auto unknown_2{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_WARNING(Service_HID, - "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", - unknown_1, unknown_2, applet_resource_user_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto mode{rp.Pop<u64>()}; - - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", - applet_resource_user_id, mode); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called"); @@ -769,49 +844,6 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.StartLRAssignmentMode(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.StopLRAssignmentMode(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); -} - -void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_1{rp.Pop<u32>()}; - const auto npad_2{rp.Pop<u32>()}; - const auto applet_resource_user_id{rp.Pop<u64>()}; - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", - applet_resource_user_id, npad_1, npad_2); - - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - IPC::ResponseBuilder rb{ctx, 2}; - if (controller.SwapNpadAssignment(npad_1, npad_2)) { - rb.Push(RESULT_SUCCESS); - } else { - LOG_ERROR(Service_HID, "Npads are not connected!"); - rb.Push(ERR_NPAD_NOT_CONNECTED); - } -} - class HidDbg final : public ServiceFramework<HidDbg> { public: explicit HidDbg() : ServiceFramework{"hid:dbg"} { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 01852e019..f08e036a3 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -106,14 +106,19 @@ private: void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); + void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); + void StartLrAssignmentMode(Kernel::HLERequestContext& ctx); + void StopLrAssignmentMode(Kernel::HLERequestContext& ctx); + void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); + void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); + void SwapNpadAssignment(Kernel::HLERequestContext& ctx); void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); void SendVibrationValue(Kernel::HLERequestContext& ctx); void SendVibrationValues(Kernel::HLERequestContext& ctx); void GetActualVibrationValue(Kernel::HLERequestContext& ctx); - void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); - void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); - void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); void PermitVibration(Kernel::HLERequestContext& ctx); @@ -123,9 +128,6 @@ private: void StopSixAxisSensor(Kernel::HLERequestContext& ctx); void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); - void StartLrAssignmentMode(Kernel::HLERequestContext& ctx); - void StopLrAssignmentMode(Kernel::HLERequestContext& ctx); - void SwapNpadAssignment(Kernel::HLERequestContext& ctx); std::shared_ptr<IAppletResource> applet_resource; Core::System& system; diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 199b30635..611cecc20 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -45,7 +45,7 @@ struct DisplayInfo { /// Whether or not the display has a limited number of layers. u8 has_limited_layers{1}; - INSERT_PADDING_BYTES(7){}; + INSERT_PADDING_BYTES(7); /// Indicates the total amount of layers supported by the display. /// @note This is only valid if has_limited_layers is set. diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index cb6eda1b8..c911c6ec4 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -36,6 +36,8 @@ add_library(video_core STATIC memory_manager.h morton.cpp morton.h + rasterizer_accelerated.cpp + rasterizer_accelerated.h rasterizer_cache.cpp rasterizer_cache.h rasterizer_interface.h diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 7ff44f06d..85d308e26 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -28,6 +28,13 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { } } +std::pair<u32, u32> DelimitLine(u32 src_1, u32 src_2, u32 dst_1, u32 dst_2, u32 src_line) { + const u32 line_a = src_2 - src_1; + const u32 line_b = dst_2 - dst_1; + const u32 excess = std::max<s32>(0, line_a - src_line + src_1); + return {line_b - (excess * line_b) / line_a, excess}; +} + void Fermi2D::HandleSurfaceCopy() { LOG_DEBUG(HW_GPU, "Requested a surface copy with operation {}", static_cast<u32>(regs.operation)); @@ -47,10 +54,27 @@ void Fermi2D::HandleSurfaceCopy() { src_blit_x2 = static_cast<u32>((regs.blit_src_x >> 32) + regs.blit_dst_width); src_blit_y2 = static_cast<u32>((regs.blit_src_y >> 32) + regs.blit_dst_height); } + u32 dst_blit_x2 = regs.blit_dst_x + regs.blit_dst_width; + u32 dst_blit_y2 = regs.blit_dst_y + regs.blit_dst_height; + const auto [new_dst_w, src_excess_x] = + DelimitLine(src_blit_x1, src_blit_x2, regs.blit_dst_x, dst_blit_x2, regs.src.width); + const auto [new_dst_h, src_excess_y] = + DelimitLine(src_blit_y1, src_blit_y2, regs.blit_dst_y, dst_blit_y2, regs.src.height); + dst_blit_x2 = new_dst_w + regs.blit_dst_x; + src_blit_x2 = src_blit_x2 - src_excess_x; + dst_blit_y2 = new_dst_h + regs.blit_dst_y; + src_blit_y2 = src_blit_y2 - src_excess_y; + const auto [new_src_w, dst_excess_x] = + DelimitLine(regs.blit_dst_x, dst_blit_x2, src_blit_x1, src_blit_x2, regs.dst.width); + const auto [new_src_h, dst_excess_y] = + DelimitLine(regs.blit_dst_y, dst_blit_y2, src_blit_y1, src_blit_y2, regs.dst.height); + src_blit_x2 = new_src_w + src_blit_x1; + dst_blit_x2 = dst_blit_x2 - dst_excess_x; + src_blit_y2 = new_src_h + src_blit_y1; + dst_blit_y2 = dst_blit_y2 - dst_excess_y; const Common::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2}; - const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, - regs.blit_dst_x + regs.blit_dst_width, - regs.blit_dst_y + regs.blit_dst_height}; + const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, dst_blit_x2, + dst_blit_y2}; Config copy_config; copy_config.operation = regs.operation; copy_config.filter = regs.blit_control.filter; diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 0901cf2fa..dba342c70 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -99,19 +99,19 @@ public: union { struct { - INSERT_PADDING_WORDS(0x80); + INSERT_UNION_PADDING_WORDS(0x80); Surface dst; - INSERT_PADDING_WORDS(2); + INSERT_UNION_PADDING_WORDS(2); Surface src; - INSERT_PADDING_WORDS(0x15); + INSERT_UNION_PADDING_WORDS(0x15); Operation operation; - INSERT_PADDING_WORDS(0x177); + INSERT_UNION_PADDING_WORDS(0x177); union { u32 raw; @@ -119,7 +119,7 @@ public: BitField<4, 1, Filter> filter; } blit_control; - INSERT_PADDING_WORDS(0x8); + INSERT_UNION_PADDING_WORDS(0x8); u32 blit_dst_x; u32 blit_dst_y; @@ -130,7 +130,7 @@ public: u64 blit_src_x; u64 blit_src_y; - INSERT_PADDING_WORDS(0x21); + INSERT_UNION_PADDING_WORDS(0x21); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h index b185c98c7..5259d92bd 100644 --- a/src/video_core/engines/kepler_compute.h +++ b/src/video_core/engines/kepler_compute.h @@ -51,7 +51,7 @@ public: union { struct { - INSERT_PADDING_WORDS(0x60); + INSERT_UNION_PADDING_WORDS(0x60); Upload::Registers upload; @@ -63,7 +63,7 @@ public: u32 data_upload; - INSERT_PADDING_WORDS(0x3F); + INSERT_UNION_PADDING_WORDS(0x3F); struct { u32 address; @@ -72,11 +72,11 @@ public: } } launch_desc_loc; - INSERT_PADDING_WORDS(0x1); + INSERT_UNION_PADDING_WORDS(0x1); u32 launch; - INSERT_PADDING_WORDS(0x4A7); + INSERT_UNION_PADDING_WORDS(0x4A7); struct { u32 address_high; @@ -88,7 +88,7 @@ public: } } tsc; - INSERT_PADDING_WORDS(0x3); + INSERT_UNION_PADDING_WORDS(0x3); struct { u32 address_high; @@ -100,7 +100,7 @@ public: } } tic; - INSERT_PADDING_WORDS(0x22); + INSERT_UNION_PADDING_WORDS(0x22); struct { u32 address_high; @@ -111,11 +111,11 @@ public: } } code_loc; - INSERT_PADDING_WORDS(0x3FE); + INSERT_UNION_PADDING_WORDS(0x3FE); u32 tex_cb_index; - INSERT_PADDING_WORDS(0x374); + INSERT_UNION_PADDING_WORDS(0x374); }; std::array<u32, NUM_REGS> reg_array; }; @@ -179,7 +179,7 @@ public: }; INSERT_PADDING_WORDS(0x11); - } launch_description; + } launch_description{}; struct { u32 write_offset = 0; diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index e0e25c321..396fb6e86 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h @@ -45,7 +45,7 @@ public: union { struct { - INSERT_PADDING_WORDS(0x60); + INSERT_UNION_PADDING_WORDS(0x60); Upload::Registers upload; @@ -57,7 +57,7 @@ public: u32 data; - INSERT_PADDING_WORDS(0x11); + INSERT_UNION_PADDING_WORDS(0x11); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 8cc842684..1aa7c274f 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -496,7 +496,7 @@ public: Equation equation_a; Factor factor_source_a; Factor factor_dest_a; - INSERT_PADDING_WORDS(1); + INSERT_UNION_PADDING_WORDS(1); }; struct RenderTargetConfig { @@ -517,7 +517,7 @@ public: }; u32 layer_stride; u32 base_layer; - INSERT_PADDING_WORDS(7); + INSERT_UNION_PADDING_WORDS(7); GPUVAddr Address() const { return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | @@ -542,7 +542,7 @@ public: f32 translate_x; f32 translate_y; f32 translate_z; - INSERT_PADDING_WORDS(2); + INSERT_UNION_PADDING_WORDS(2); Common::Rectangle<s32> GetRect() const { return { @@ -606,7 +606,7 @@ public: union { struct { - INSERT_PADDING_WORDS(0x45); + INSERT_UNION_PADDING_WORDS(0x45); struct { u32 upload_address; @@ -615,7 +615,7 @@ public: u32 bind; } macros; - INSERT_PADDING_WORDS(0x17); + INSERT_UNION_PADDING_WORDS(0x17); Upload::Registers upload; struct { @@ -626,7 +626,7 @@ public: u32 data_upload; - INSERT_PADDING_WORDS(0x44); + INSERT_UNION_PADDING_WORDS(0x44); struct { union { @@ -636,11 +636,11 @@ public: }; } sync_info; - INSERT_PADDING_WORDS(0x11E); + INSERT_UNION_PADDING_WORDS(0x11E); u32 tfb_enabled; - INSERT_PADDING_WORDS(0x2E); + INSERT_UNION_PADDING_WORDS(0x2E); std::array<RenderTargetConfig, NumRenderTargets> rt; @@ -648,49 +648,49 @@ public: std::array<ViewPort, NumViewports> viewports; - INSERT_PADDING_WORDS(0x1D); + INSERT_UNION_PADDING_WORDS(0x1D); struct { u32 first; u32 count; } vertex_buffer; - INSERT_PADDING_WORDS(1); + INSERT_UNION_PADDING_WORDS(1); float clear_color[4]; float clear_depth; - INSERT_PADDING_WORDS(0x3); + INSERT_UNION_PADDING_WORDS(0x3); s32 clear_stencil; - INSERT_PADDING_WORDS(0x7); + INSERT_UNION_PADDING_WORDS(0x7); u32 polygon_offset_point_enable; u32 polygon_offset_line_enable; u32 polygon_offset_fill_enable; - INSERT_PADDING_WORDS(0xD); + INSERT_UNION_PADDING_WORDS(0xD); std::array<ScissorTest, NumViewports> scissor_test; - INSERT_PADDING_WORDS(0x15); + INSERT_UNION_PADDING_WORDS(0x15); s32 stencil_back_func_ref; u32 stencil_back_mask; u32 stencil_back_func_mask; - INSERT_PADDING_WORDS(0xC); + INSERT_UNION_PADDING_WORDS(0xC); u32 color_mask_common; - INSERT_PADDING_WORDS(0x6); + INSERT_UNION_PADDING_WORDS(0x6); u32 rt_separate_frag_data; f32 depth_bounds[2]; - INSERT_PADDING_WORDS(0xA); + INSERT_UNION_PADDING_WORDS(0xA); struct { u32 address_high; @@ -710,7 +710,7 @@ public: } } zeta; - INSERT_PADDING_WORDS(0x41); + INSERT_UNION_PADDING_WORDS(0x41); union { BitField<0, 4, u32> stencil; @@ -719,11 +719,11 @@ public: BitField<12, 4, u32> viewport; } clear_flags; - INSERT_PADDING_WORDS(0x19); + INSERT_UNION_PADDING_WORDS(0x19); std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; - INSERT_PADDING_WORDS(0xF); + INSERT_UNION_PADDING_WORDS(0xF); struct { union { @@ -746,16 +746,16 @@ public: } } rt_control; - INSERT_PADDING_WORDS(0x2); + INSERT_UNION_PADDING_WORDS(0x2); u32 zeta_width; u32 zeta_height; - INSERT_PADDING_WORDS(0x27); + INSERT_UNION_PADDING_WORDS(0x27); u32 depth_test_enable; - INSERT_PADDING_WORDS(0x5); + INSERT_UNION_PADDING_WORDS(0x5); u32 independent_blend_enable; @@ -763,7 +763,7 @@ public: u32 alpha_test_enabled; - INSERT_PADDING_WORDS(0x6); + INSERT_UNION_PADDING_WORDS(0x6); u32 d3d_cull_mode; @@ -777,7 +777,7 @@ public: float b; float a; } blend_color; - INSERT_PADDING_WORDS(0x4); + INSERT_UNION_PADDING_WORDS(0x4); struct { u32 separate_alpha; @@ -786,7 +786,7 @@ public: Blend::Factor factor_dest_rgb; Blend::Equation equation_a; Blend::Factor factor_source_a; - INSERT_PADDING_WORDS(1); + INSERT_UNION_PADDING_WORDS(1); Blend::Factor factor_dest_a; u32 enable_common; @@ -802,7 +802,7 @@ public: u32 stencil_front_func_mask; u32 stencil_front_mask; - INSERT_PADDING_WORDS(0x2); + INSERT_UNION_PADDING_WORDS(0x2); u32 frag_color_clamp; @@ -811,12 +811,12 @@ public: BitField<4, 1, u32> triangle_rast_flip; } screen_y_control; - INSERT_PADDING_WORDS(0x21); + INSERT_UNION_PADDING_WORDS(0x21); u32 vb_element_base; u32 vb_base_instance; - INSERT_PADDING_WORDS(0x35); + INSERT_UNION_PADDING_WORDS(0x35); union { BitField<0, 1, u32> c0; @@ -829,11 +829,11 @@ public: BitField<7, 1, u32> c7; } clip_distance_enabled; - INSERT_PADDING_WORDS(0x1); + INSERT_UNION_PADDING_WORDS(0x1); float point_size; - INSERT_PADDING_WORDS(0x7); + INSERT_UNION_PADDING_WORDS(0x7); u32 zeta_enable; @@ -842,7 +842,7 @@ public: BitField<4, 1, u32> alpha_to_one; } multisample_control; - INSERT_PADDING_WORDS(0x4); + INSERT_UNION_PADDING_WORDS(0x4); struct { u32 address_high; @@ -866,11 +866,11 @@ public: } } tsc; - INSERT_PADDING_WORDS(0x1); + INSERT_UNION_PADDING_WORDS(0x1); float polygon_offset_factor; - INSERT_PADDING_WORDS(0x1); + INSERT_UNION_PADDING_WORDS(0x1); struct { u32 tic_address_high; @@ -883,7 +883,7 @@ public: } } tic; - INSERT_PADDING_WORDS(0x5); + INSERT_UNION_PADDING_WORDS(0x5); u32 stencil_two_side_enable; StencilOp stencil_back_op_fail; @@ -891,13 +891,13 @@ public: StencilOp stencil_back_op_zpass; ComparisonOp stencil_back_func_func; - INSERT_PADDING_WORDS(0x4); + INSERT_UNION_PADDING_WORDS(0x4); u32 framebuffer_srgb; float polygon_offset_units; - INSERT_PADDING_WORDS(0x11); + INSERT_UNION_PADDING_WORDS(0x11); union { BitField<2, 1, u32> coord_origin; @@ -913,7 +913,7 @@ public: (static_cast<GPUVAddr>(code_address_high) << 32) | code_address_low); } } code_address; - INSERT_PADDING_WORDS(1); + INSERT_UNION_PADDING_WORDS(1); struct { u32 vertex_end_gl; @@ -925,14 +925,14 @@ public: }; } draw; - INSERT_PADDING_WORDS(0xA); + INSERT_UNION_PADDING_WORDS(0xA); struct { u32 enabled; u32 index; } primitive_restart; - INSERT_PADDING_WORDS(0x5F); + INSERT_UNION_PADDING_WORDS(0x5F); struct { u32 start_addr_high; @@ -973,9 +973,9 @@ public: } } index_array; - INSERT_PADDING_WORDS(0x7); + INSERT_UNION_PADDING_WORDS(0x7); - INSERT_PADDING_WORDS(0x1F); + INSERT_UNION_PADDING_WORDS(0x1F); float polygon_offset_clamp; @@ -989,17 +989,17 @@ public: } } instanced_arrays; - INSERT_PADDING_WORDS(0x6); + INSERT_UNION_PADDING_WORDS(0x6); Cull cull; u32 pixel_center_integer; - INSERT_PADDING_WORDS(0x1); + INSERT_UNION_PADDING_WORDS(0x1); u32 viewport_transform_enabled; - INSERT_PADDING_WORDS(0x3); + INSERT_UNION_PADDING_WORDS(0x3); union { BitField<0, 1, u32> depth_range_0_1; @@ -1007,13 +1007,13 @@ public: BitField<4, 1, u32> depth_clamp_far; } view_volume_clip_control; - INSERT_PADDING_WORDS(0x21); + INSERT_UNION_PADDING_WORDS(0x21); struct { u32 enable; LogicOperation operation; } logic_op; - INSERT_PADDING_WORDS(0x1); + INSERT_UNION_PADDING_WORDS(0x1); union { u32 raw; @@ -1026,9 +1026,9 @@ public: BitField<6, 4, u32> RT; BitField<10, 11, u32> layer; } clear_buffers; - INSERT_PADDING_WORDS(0xB); + INSERT_UNION_PADDING_WORDS(0xB); std::array<ColorMask, NumRenderTargets> color_mask; - INSERT_PADDING_WORDS(0x38); + INSERT_UNION_PADDING_WORDS(0x38); struct { u32 query_address_high; @@ -1050,7 +1050,7 @@ public: } } query; - INSERT_PADDING_WORDS(0x3C); + INSERT_UNION_PADDING_WORDS(0x3C); struct { union { @@ -1090,10 +1090,10 @@ public: BitField<4, 4, ShaderProgram> program; }; u32 offset; - INSERT_PADDING_WORDS(14); + INSERT_UNION_PADDING_WORDS(14); } shader_config[MaxShaderProgram]; - INSERT_PADDING_WORDS(0x60); + INSERT_UNION_PADDING_WORDS(0x60); u32 firmware[0x20]; @@ -1110,7 +1110,7 @@ public: } } const_buffer; - INSERT_PADDING_WORDS(0x10); + INSERT_UNION_PADDING_WORDS(0x10); struct { union { @@ -1118,14 +1118,14 @@ public: BitField<0, 1, u32> valid; BitField<4, 5, u32> index; }; - INSERT_PADDING_WORDS(7); + INSERT_UNION_PADDING_WORDS(7); } cb_bind[MaxShaderStage]; - INSERT_PADDING_WORDS(0x56); + INSERT_UNION_PADDING_WORDS(0x56); u32 tex_cb_index; - INSERT_PADDING_WORDS(0x395); + INSERT_UNION_PADDING_WORDS(0x395); struct { /// Compressed address of a buffer that holds information about bound SSBOs. @@ -1137,14 +1137,14 @@ public: } } ssbo_info; - INSERT_PADDING_WORDS(0x11); + INSERT_UNION_PADDING_WORDS(0x11); struct { u32 address[MaxShaderStage]; u32 size[MaxShaderStage]; } tex_info_buffers; - INSERT_PADDING_WORDS(0xCC); + INSERT_UNION_PADDING_WORDS(0xCC); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 93808a9bb..4f40d1d1f 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h @@ -94,7 +94,7 @@ public: union { struct { - INSERT_PADDING_WORDS(0xC0); + INSERT_UNION_PADDING_WORDS(0xC0); struct { union { @@ -112,7 +112,7 @@ public: }; } exec; - INSERT_PADDING_WORDS(0x3F); + INSERT_UNION_PADDING_WORDS(0x3F); struct { u32 address_high; @@ -139,7 +139,7 @@ public: u32 x_count; u32 y_count; - INSERT_PADDING_WORDS(0xB8); + INSERT_UNION_PADDING_WORDS(0xB8); u32 const0; u32 const1; @@ -162,11 +162,11 @@ public: Parameters dst_params; - INSERT_PADDING_WORDS(1); + INSERT_UNION_PADDING_WORDS(1); Parameters src_params; - INSERT_PADDING_WORDS(0x13); + INSERT_UNION_PADDING_WORDS(0x13); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index d3d05a866..8f6bc76eb 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -1238,6 +1238,32 @@ union Instruction { } tld4; union { + BitField<35, 1, u64> ndv_flag; + BitField<49, 1, u64> nodep_flag; + BitField<50, 1, u64> dc_flag; + BitField<33, 2, u64> info; + BitField<37, 2, u64> component; + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::NDV: + return ndv_flag != 0; + case TextureMiscMode::NODEP: + return nodep_flag != 0; + case TextureMiscMode::DC: + return dc_flag != 0; + case TextureMiscMode::AOFFI: + return info == 1; + case TextureMiscMode::PTP: + return info == 2; + default: + break; + } + return false; + } + } tld4_b; + + union { BitField<49, 1, u64> nodep_flag; BitField<50, 1, u64> dc_flag; BitField<51, 1, u64> aoffi_flag; @@ -1590,7 +1616,8 @@ public: TEXS, // Texture Fetch with scalar/non-vec4 source/destinations TLD, // Texture Load TLDS, // Texture Load with scalar/non-vec4 source/destinations - TLD4, // Texture Load 4 + TLD4, // Texture Gather 4 + TLD4_B, // Texture Gather 4 Bindless TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations TMML_B, // Texture Mip Map Level TMML, // Texture Mip Map Level @@ -1881,6 +1908,7 @@ private: INST("11011100--11----", Id::TLD, Type::Texture, "TLD"), INST("1101-01---------", Id::TLDS, Type::Texture, "TLDS"), INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"), + INST("1101111011111---", Id::TLD4_B, Type::Texture, "TLD4_B"), INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"), INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), INST("1101111101011---", Id::TMML, Type::Texture, "TMML"), diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h index e86a7f04a..bc80661d8 100644 --- a/src/video_core/engines/shader_header.h +++ b/src/video_core/engines/shader_header.h @@ -38,37 +38,37 @@ struct Header { BitField<26, 1, u32> does_load_or_store; BitField<27, 1, u32> does_fp64; BitField<28, 4, u32> stream_out_mask; - } common0; + } common0{}; union { BitField<0, 24, u32> shader_local_memory_low_size; BitField<24, 8, u32> per_patch_attribute_count; - } common1; + } common1{}; union { BitField<0, 24, u32> shader_local_memory_high_size; BitField<24, 8, u32> threads_per_input_primitive; - } common2; + } common2{}; union { BitField<0, 24, u32> shader_local_memory_crs_size; BitField<24, 4, OutputTopology> output_topology; BitField<28, 4, u32> reserved; - } common3; + } common3{}; union { BitField<0, 12, u32> max_output_vertices; BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders. BitField<24, 4, u32> reserved; BitField<12, 8, u32> store_req_end; // NOTE: not used by geometry shaders. - } common4; + } common4{}; union { struct { - INSERT_PADDING_BYTES(3); // ImapSystemValuesA - INSERT_PADDING_BYTES(1); // ImapSystemValuesB - INSERT_PADDING_BYTES(16); // ImapGenericVector[32] - INSERT_PADDING_BYTES(2); // ImapColor + INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA + INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB + INSERT_UNION_PADDING_BYTES(16); // ImapGenericVector[32] + INSERT_UNION_PADDING_BYTES(2); // ImapColor union { BitField<0, 8, u16> clip_distances; BitField<8, 1, u16> point_sprite_s; @@ -79,20 +79,20 @@ struct Header { BitField<14, 1, u16> instance_id; BitField<15, 1, u16> vertex_id; }; - INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10] - INSERT_PADDING_BYTES(1); // ImapReserved - INSERT_PADDING_BYTES(3); // OmapSystemValuesA - INSERT_PADDING_BYTES(1); // OmapSystemValuesB - INSERT_PADDING_BYTES(16); // OmapGenericVector[32] - INSERT_PADDING_BYTES(2); // OmapColor - INSERT_PADDING_BYTES(2); // OmapSystemValuesC - INSERT_PADDING_BYTES(5); // OmapFixedFncTexture[10] - INSERT_PADDING_BYTES(1); // OmapReserved + INSERT_UNION_PADDING_BYTES(5); // ImapFixedFncTexture[10] + INSERT_UNION_PADDING_BYTES(1); // ImapReserved + INSERT_UNION_PADDING_BYTES(3); // OmapSystemValuesA + INSERT_UNION_PADDING_BYTES(1); // OmapSystemValuesB + INSERT_UNION_PADDING_BYTES(16); // OmapGenericVector[32] + INSERT_UNION_PADDING_BYTES(2); // OmapColor + INSERT_UNION_PADDING_BYTES(2); // OmapSystemValuesC + INSERT_UNION_PADDING_BYTES(5); // OmapFixedFncTexture[10] + INSERT_UNION_PADDING_BYTES(1); // OmapReserved } vtg; struct { - INSERT_PADDING_BYTES(3); // ImapSystemValuesA - INSERT_PADDING_BYTES(1); // ImapSystemValuesB + INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA + INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB union { BitField<0, 2, AttributeUse> x; BitField<2, 2, AttributeUse> y; @@ -100,10 +100,10 @@ struct Header { BitField<6, 2, AttributeUse> z; u8 raw; } imap_generic_vector[32]; - INSERT_PADDING_BYTES(2); // ImapColor - INSERT_PADDING_BYTES(2); // ImapSystemValuesC - INSERT_PADDING_BYTES(10); // ImapFixedFncTexture[10] - INSERT_PADDING_BYTES(2); // ImapReserved + INSERT_UNION_PADDING_BYTES(2); // ImapColor + INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC + INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10] + INSERT_UNION_PADDING_BYTES(2); // ImapReserved struct { u32 target; union { @@ -139,6 +139,8 @@ struct Header { return result; } } ps; + + std::array<u32, 0xF> raw{}; }; u64 GetLocalMemorySize() const { diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index dbca19f35..ecc338ae9 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -207,7 +207,7 @@ public: union { struct { - INSERT_PADDING_WORDS(0x4); + INSERT_UNION_PADDING_WORDS(0x4); struct { u32 address_high; u32 address_low; @@ -220,12 +220,12 @@ public: u32 semaphore_sequence; u32 semaphore_trigger; - INSERT_PADDING_WORDS(0xC); + INSERT_UNION_PADDING_WORDS(0xC); // The puser and the puller share the reference counter, the pusher only has read // access u32 reference_count; - INSERT_PADDING_WORDS(0x5); + INSERT_UNION_PADDING_WORDS(0x5); u32 semaphore_acquire; u32 semaphore_release; @@ -234,7 +234,7 @@ public: BitField<4, 4, u32> operation; BitField<8, 8, u32> id; } fence_action; - INSERT_PADDING_WORDS(0xE2); + INSERT_UNION_PADDING_WORDS(0xE2); // Puller state u32 acquire_mode; diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp new file mode 100644 index 000000000..b230dcc18 --- /dev/null +++ b/src/video_core/rasterizer_accelerated.cpp @@ -0,0 +1,63 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <mutex> + +#include <boost/icl/interval_map.hpp> + +#include "common/assert.h" +#include "common/common_types.h" +#include "core/memory.h" +#include "video_core/rasterizer_accelerated.h" + +namespace VideoCore { + +namespace { + +template <typename Map, typename Interval> +constexpr auto RangeFromInterval(Map& map, const Interval& interval) { + return boost::make_iterator_range(map.equal_range(interval)); +} + +} // Anonymous namespace + +RasterizerAccelerated::RasterizerAccelerated() = default; + +RasterizerAccelerated::~RasterizerAccelerated() = default; + +void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { + std::lock_guard lock{pages_mutex}; + const u64 page_start{addr >> Memory::PAGE_BITS}; + const u64 page_end{(addr + size + Memory::PAGE_SIZE - 1) >> Memory::PAGE_BITS}; + + // Interval maps will erase segments if count reaches 0, so if delta is negative we have to + // subtract after iterating + const auto pages_interval = CachedPageMap::interval_type::right_open(page_start, page_end); + if (delta > 0) { + cached_pages.add({pages_interval, delta}); + } + + for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) { + const auto interval = pair.first & pages_interval; + const int count = pair.second; + + const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; + const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; + const u64 interval_size = interval_end_addr - interval_start_addr; + + if (delta > 0 && count == delta) { + Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true); + } else if (delta < 0 && count == -delta) { + Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false); + } else { + ASSERT(count >= 0); + } + } + + if (delta < 0) { + cached_pages.add({pages_interval, delta}); + } +} + +} // namespace VideoCore diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h new file mode 100644 index 000000000..8f7e3547e --- /dev/null +++ b/src/video_core/rasterizer_accelerated.h @@ -0,0 +1,31 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <mutex> + +#include <boost/icl/interval_map.hpp> + +#include "common/common_types.h" +#include "video_core/rasterizer_interface.h" + +namespace VideoCore { + +/// Implements the shared part in GPU accelerated rasterizers in RasterizerInterface. +class RasterizerAccelerated : public RasterizerInterface { +public: + explicit RasterizerAccelerated(); + ~RasterizerAccelerated() override; + + void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; + +private: + using CachedPageMap = boost::icl::interval_map<u64, int>; + CachedPageMap cached_pages; + + std::mutex pages_mutex; +}; + +} // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 35fc094a8..d1e147db8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -68,8 +68,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind ScreenInfo& info) : texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device}, system{system}, screen_info{info}, buffer_cache{*this, system, STREAM_BUFFER_SIZE} { - OpenGLState::ApplyDefaultState(); - shader_program_manager = std::make_unique<GLShader::ProgramManager>(); state.draw.shader_program = 0; state.Apply(); @@ -342,42 +340,6 @@ std::size_t RasterizerOpenGL::CalculateIndexBufferSize() const { static_cast<std::size_t>(regs.index_array.FormatSizeInBytes()); } -template <typename Map, typename Interval> -static constexpr auto RangeFromInterval(Map& map, const Interval& interval) { - return boost::make_iterator_range(map.equal_range(interval)); -} - -void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { - std::lock_guard lock{pages_mutex}; - const u64 page_start{addr >> Memory::PAGE_BITS}; - const u64 page_end{(addr + size + Memory::PAGE_SIZE - 1) >> Memory::PAGE_BITS}; - - // Interval maps will erase segments if count reaches 0, so if delta is negative we have to - // subtract after iterating - const auto pages_interval = CachedPageMap::interval_type::right_open(page_start, page_end); - if (delta > 0) - cached_pages.add({pages_interval, delta}); - - for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) { - const auto interval = pair.first & pages_interval; - const int count = pair.second; - - const VAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS; - const VAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS; - const u64 interval_size = interval_end_addr - interval_start_addr; - - if (delta > 0 && count == delta) - Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true); - else if (delta < 0 && count == -delta) - Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false); - else - ASSERT(count >= 0); - } - - if (delta < 0) - cached_pages.add({pages_interval, delta}); -} - void RasterizerOpenGL::LoadDiskResources(const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback) { shader_cache.LoadDiskCache(stop_loading, callback); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index c24a02d71..bd6fe5c3a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -9,17 +9,16 @@ #include <cstddef> #include <map> #include <memory> -#include <mutex> #include <optional> #include <tuple> #include <utility> -#include <boost/icl/interval_map.hpp> #include <glad/glad.h> #include "common/common_types.h" #include "video_core/engines/const_buffer_info.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/rasterizer_accelerated.h" #include "video_core/rasterizer_cache.h" #include "video_core/rasterizer_interface.h" #include "video_core/renderer_opengl/gl_buffer_cache.h" @@ -52,7 +51,7 @@ namespace OpenGL { struct ScreenInfo; struct DrawParameters; -class RasterizerOpenGL : public VideoCore::RasterizerInterface { +class RasterizerOpenGL : public VideoCore::RasterizerAccelerated { public: explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, ScreenInfo& info); @@ -73,7 +72,6 @@ public: const Tegra::Engines::Fermi2D::Config& copy_config) override; bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, u32 pixel_stride) override; - void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; void LoadDiskResources(const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback) override; @@ -228,11 +226,6 @@ private: AccelDraw accelerate_draw = AccelDraw::Disabled; OGLFramebuffer clear_framebuffer; - - using CachedPageMap = boost::icl::interval_map<u64, int>; - CachedPageMap cached_pages; - - std::mutex pages_mutex; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index bf86b5a0b..f25148362 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <iterator> #include <glad/glad.h> #include "common/assert.h" @@ -69,147 +70,29 @@ void Enable(GLenum cap, GLuint index, bool enable) { } void Enable(GLenum cap, bool& current_value, bool new_value) { - if (UpdateValue(current_value, new_value)) + if (UpdateValue(current_value, new_value)) { Enable(cap, new_value); + } } void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) { - if (UpdateValue(current_value, new_value)) + if (UpdateValue(current_value, new_value)) { Enable(cap, index, new_value); -} - -} // namespace - -OpenGLState::OpenGLState() { - // These all match default OpenGL values - framebuffer_srgb.enabled = false; - - multisample_control.alpha_to_coverage = false; - multisample_control.alpha_to_one = false; - - cull.enabled = false; - cull.mode = GL_BACK; - cull.front_face = GL_CCW; - - depth.test_enabled = false; - depth.test_func = GL_LESS; - depth.write_mask = GL_TRUE; - - primitive_restart.enabled = false; - primitive_restart.index = 0; - - for (auto& item : color_mask) { - item.red_enabled = GL_TRUE; - item.green_enabled = GL_TRUE; - item.blue_enabled = GL_TRUE; - item.alpha_enabled = GL_TRUE; } +} - const auto ResetStencil = [](auto& config) { - config.test_func = GL_ALWAYS; - config.test_ref = 0; - config.test_mask = 0xFFFFFFFF; - config.write_mask = 0xFFFFFFFF; - config.action_depth_fail = GL_KEEP; - config.action_depth_pass = GL_KEEP; - config.action_stencil_fail = GL_KEEP; - }; - stencil.test_enabled = false; - ResetStencil(stencil.front); - ResetStencil(stencil.back); - - for (auto& item : viewports) { - item.x = 0; - item.y = 0; - item.width = 0; - item.height = 0; - item.depth_range_near = 0.0f; - item.depth_range_far = 1.0f; - item.scissor.enabled = false; - item.scissor.x = 0; - item.scissor.y = 0; - item.scissor.width = 0; - item.scissor.height = 0; - } - - for (auto& item : blend) { - item.enabled = true; - item.rgb_equation = GL_FUNC_ADD; - item.a_equation = GL_FUNC_ADD; - item.src_rgb_func = GL_ONE; - item.dst_rgb_func = GL_ZERO; - item.src_a_func = GL_ONE; - item.dst_a_func = GL_ZERO; - } - - independant_blend.enabled = false; - - blend_color.red = 0.0f; - blend_color.green = 0.0f; - blend_color.blue = 0.0f; - blend_color.alpha = 0.0f; - - logic_op.enabled = false; - logic_op.operation = GL_COPY; - - draw.read_framebuffer = 0; - draw.draw_framebuffer = 0; - draw.vertex_array = 0; - draw.shader_program = 0; - draw.program_pipeline = 0; - - clip_distance = {}; - - point.size = 1; - - fragment_color_clamp.enabled = false; - - depth_clamp.far_plane = false; - depth_clamp.near_plane = false; - - polygon_offset.fill_enable = false; - polygon_offset.line_enable = false; - polygon_offset.point_enable = false; - polygon_offset.factor = 0.0f; - polygon_offset.units = 0.0f; - polygon_offset.clamp = 0.0f; +} // Anonymous namespace - alpha_test.enabled = false; - alpha_test.func = GL_ALWAYS; - alpha_test.ref = 0.0f; -} +OpenGLState::OpenGLState() = default; void OpenGLState::SetDefaultViewports() { - for (auto& item : viewports) { - item.x = 0; - item.y = 0; - item.width = 0; - item.height = 0; - item.depth_range_near = 0.0f; - item.depth_range_far = 1.0f; - item.scissor.enabled = false; - item.scissor.x = 0; - item.scissor.y = 0; - item.scissor.width = 0; - item.scissor.height = 0; - } + viewports.fill(Viewport{}); depth_clamp.far_plane = false; depth_clamp.near_plane = false; } -void OpenGLState::ApplyDefaultState() { - glEnable(GL_BLEND); - glDisable(GL_FRAMEBUFFER_SRGB); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_PRIMITIVE_RESTART); - glDisable(GL_STENCIL_TEST); - glDisable(GL_COLOR_LOGIC_OP); - glDisable(GL_SCISSOR_TEST); -} - -void OpenGLState::ApplyFramebufferState() const { +void OpenGLState::ApplyFramebufferState() { if (UpdateValue(cur_state.draw.read_framebuffer, draw.read_framebuffer)) { glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); } @@ -218,52 +101,52 @@ void OpenGLState::ApplyFramebufferState() const { } } -void OpenGLState::ApplyVertexArrayState() const { +void OpenGLState::ApplyVertexArrayState() { if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) { glBindVertexArray(draw.vertex_array); } } -void OpenGLState::ApplyShaderProgram() const { +void OpenGLState::ApplyShaderProgram() { if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) { glUseProgram(draw.shader_program); } } -void OpenGLState::ApplyProgramPipeline() const { +void OpenGLState::ApplyProgramPipeline() { if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) { glBindProgramPipeline(draw.program_pipeline); } } -void OpenGLState::ApplyClipDistances() const { +void OpenGLState::ApplyClipDistances() { for (std::size_t i = 0; i < clip_distance.size(); ++i) { Enable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i), cur_state.clip_distance[i], clip_distance[i]); } } -void OpenGLState::ApplyPointSize() const { +void OpenGLState::ApplyPointSize() { if (UpdateValue(cur_state.point.size, point.size)) { glPointSize(point.size); } } -void OpenGLState::ApplyFragmentColorClamp() const { +void OpenGLState::ApplyFragmentColorClamp() { if (UpdateValue(cur_state.fragment_color_clamp.enabled, fragment_color_clamp.enabled)) { glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); } } -void OpenGLState::ApplyMultisample() const { +void OpenGLState::ApplyMultisample() { Enable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur_state.multisample_control.alpha_to_coverage, multisample_control.alpha_to_coverage); Enable(GL_SAMPLE_ALPHA_TO_ONE, cur_state.multisample_control.alpha_to_one, multisample_control.alpha_to_one); } -void OpenGLState::ApplyDepthClamp() const { +void OpenGLState::ApplyDepthClamp() { if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane && depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { return; @@ -276,7 +159,7 @@ void OpenGLState::ApplyDepthClamp() const { Enable(GL_DEPTH_CLAMP, depth_clamp.far_plane || depth_clamp.near_plane); } -void OpenGLState::ApplySRgb() const { +void OpenGLState::ApplySRgb() { if (cur_state.framebuffer_srgb.enabled == framebuffer_srgb.enabled) return; cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled; @@ -287,7 +170,7 @@ void OpenGLState::ApplySRgb() const { } } -void OpenGLState::ApplyCulling() const { +void OpenGLState::ApplyCulling() { Enable(GL_CULL_FACE, cur_state.cull.enabled, cull.enabled); if (UpdateValue(cur_state.cull.mode, cull.mode)) { @@ -299,7 +182,12 @@ void OpenGLState::ApplyCulling() const { } } -void OpenGLState::ApplyColorMask() const { +void OpenGLState::ApplyColorMask() { + if (!dirty.color_mask) { + return; + } + dirty.color_mask = false; + for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) { const auto& updated = color_mask[i]; auto& current = cur_state.color_mask[i]; @@ -314,7 +202,7 @@ void OpenGLState::ApplyColorMask() const { } } -void OpenGLState::ApplyDepth() const { +void OpenGLState::ApplyDepth() { Enable(GL_DEPTH_TEST, cur_state.depth.test_enabled, depth.test_enabled); if (cur_state.depth.test_func != depth.test_func) { @@ -328,7 +216,7 @@ void OpenGLState::ApplyDepth() const { } } -void OpenGLState::ApplyPrimitiveRestart() const { +void OpenGLState::ApplyPrimitiveRestart() { Enable(GL_PRIMITIVE_RESTART, cur_state.primitive_restart.enabled, primitive_restart.enabled); if (cur_state.primitive_restart.index != primitive_restart.index) { @@ -337,7 +225,12 @@ void OpenGLState::ApplyPrimitiveRestart() const { } } -void OpenGLState::ApplyStencilTest() const { +void OpenGLState::ApplyStencilTest() { + if (!dirty.stencil_state) { + return; + } + dirty.stencil_state = false; + Enable(GL_STENCIL_TEST, cur_state.stencil.test_enabled, stencil.test_enabled); const auto ConfigStencil = [](GLenum face, const auto& config, auto& current) { @@ -366,7 +259,7 @@ void OpenGLState::ApplyStencilTest() const { ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back); } -void OpenGLState::ApplyViewport() const { +void OpenGLState::ApplyViewport() { for (GLuint i = 0; i < static_cast<GLuint>(Maxwell::NumViewports); ++i) { const auto& updated = viewports[i]; auto& current = cur_state.viewports[i]; @@ -403,7 +296,7 @@ void OpenGLState::ApplyViewport() const { } } -void OpenGLState::ApplyGlobalBlending() const { +void OpenGLState::ApplyGlobalBlending() { const Blend& updated = blend[0]; Blend& current = cur_state.blend[0]; @@ -427,7 +320,7 @@ void OpenGLState::ApplyGlobalBlending() const { } } -void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { +void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) { const Blend& updated = blend[target]; Blend& current = cur_state.blend[target]; @@ -451,7 +344,12 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { } } -void OpenGLState::ApplyBlending() const { +void OpenGLState::ApplyBlending() { + if (!dirty.blend_state) { + return; + } + dirty.blend_state = false; + if (independant_blend.enabled) { const bool force = independant_blend.enabled != cur_state.independant_blend.enabled; for (std::size_t target = 0; target < Maxwell::NumRenderTargets; ++target) { @@ -470,7 +368,7 @@ void OpenGLState::ApplyBlending() const { } } -void OpenGLState::ApplyLogicOp() const { +void OpenGLState::ApplyLogicOp() { Enable(GL_COLOR_LOGIC_OP, cur_state.logic_op.enabled, logic_op.enabled); if (UpdateValue(cur_state.logic_op.operation, logic_op.operation)) { @@ -478,7 +376,12 @@ void OpenGLState::ApplyLogicOp() const { } } -void OpenGLState::ApplyPolygonOffset() const { +void OpenGLState::ApplyPolygonOffset() { + if (!dirty.polygon_offset) { + return; + } + dirty.polygon_offset = false; + Enable(GL_POLYGON_OFFSET_FILL, cur_state.polygon_offset.fill_enable, polygon_offset.fill_enable); Enable(GL_POLYGON_OFFSET_LINE, cur_state.polygon_offset.line_enable, @@ -499,7 +402,7 @@ void OpenGLState::ApplyPolygonOffset() const { } } -void OpenGLState::ApplyAlphaTest() const { +void OpenGLState::ApplyAlphaTest() { Enable(GL_ALPHA_TEST, cur_state.alpha_test.enabled, alpha_test.enabled); if (UpdateTie(std::tie(cur_state.alpha_test.func, cur_state.alpha_test.ref), std::tie(alpha_test.func, alpha_test.ref))) { @@ -507,19 +410,19 @@ void OpenGLState::ApplyAlphaTest() const { } } -void OpenGLState::ApplyTextures() const { +void OpenGLState::ApplyTextures() { if (const auto update = UpdateArray(cur_state.textures, textures)) { glBindTextures(update->first, update->second, textures.data() + update->first); } } -void OpenGLState::ApplySamplers() const { +void OpenGLState::ApplySamplers() { if (const auto update = UpdateArray(cur_state.samplers, samplers)) { glBindSamplers(update->first, update->second, samplers.data() + update->first); } } -void OpenGLState::ApplyImages() const { +void OpenGLState::ApplyImages() { if (const auto update = UpdateArray(cur_state.images, images)) { glBindImageTextures(update->first, update->second, images.data() + update->first); } @@ -535,32 +438,20 @@ void OpenGLState::Apply() { ApplyPointSize(); ApplyFragmentColorClamp(); ApplyMultisample(); - if (dirty.color_mask) { - ApplyColorMask(); - dirty.color_mask = false; - } + ApplyColorMask(); ApplyDepthClamp(); ApplyViewport(); - if (dirty.stencil_state) { - ApplyStencilTest(); - dirty.stencil_state = false; - } + ApplyStencilTest(); ApplySRgb(); ApplyCulling(); ApplyDepth(); ApplyPrimitiveRestart(); - if (dirty.blend_state) { - ApplyBlending(); - dirty.blend_state = false; - } + ApplyBlending(); ApplyLogicOp(); ApplyTextures(); ApplySamplers(); ApplyImages(); - if (dirty.polygon_offset) { - ApplyPolygonOffset(); - dirty.polygon_offset = false; - } + ApplyPolygonOffset(); ApplyAlphaTest(); } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index c358d3b38..cca25206b 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -5,168 +5,146 @@ #pragma once #include <array> +#include <type_traits> #include <glad/glad.h> #include "video_core/engines/maxwell_3d.h" namespace OpenGL { -namespace TextureUnits { - -struct TextureUnit { - GLint id; - constexpr GLenum Enum() const { - return static_cast<GLenum>(GL_TEXTURE0 + id); - } -}; - -constexpr TextureUnit MaxwellTexture(int unit) { - return TextureUnit{unit}; -} - -constexpr TextureUnit LightingLUT{3}; -constexpr TextureUnit FogLUT{4}; -constexpr TextureUnit ProcTexNoiseLUT{5}; -constexpr TextureUnit ProcTexColorMap{6}; -constexpr TextureUnit ProcTexAlphaMap{7}; -constexpr TextureUnit ProcTexLUT{8}; -constexpr TextureUnit ProcTexDiffLUT{9}; - -} // namespace TextureUnits - class OpenGLState { public: struct { - bool enabled; // GL_FRAMEBUFFER_SRGB + bool enabled = false; // GL_FRAMEBUFFER_SRGB } framebuffer_srgb; struct { - bool alpha_to_coverage; // GL_ALPHA_TO_COVERAGE - bool alpha_to_one; // GL_ALPHA_TO_ONE + bool alpha_to_coverage = false; // GL_ALPHA_TO_COVERAGE + bool alpha_to_one = false; // GL_ALPHA_TO_ONE } multisample_control; struct { - bool enabled; // GL_CLAMP_FRAGMENT_COLOR_ARB + bool enabled = false; // GL_CLAMP_FRAGMENT_COLOR_ARB } fragment_color_clamp; struct { - bool far_plane; - bool near_plane; + bool far_plane = false; + bool near_plane = false; } depth_clamp; // GL_DEPTH_CLAMP struct { - bool enabled; // GL_CULL_FACE - GLenum mode; // GL_CULL_FACE_MODE - GLenum front_face; // GL_FRONT_FACE + bool enabled = false; // GL_CULL_FACE + GLenum mode = GL_BACK; // GL_CULL_FACE_MODE + GLenum front_face = GL_CCW; // GL_FRONT_FACE } cull; struct { - bool test_enabled; // GL_DEPTH_TEST - GLenum test_func; // GL_DEPTH_FUNC - GLboolean write_mask; // GL_DEPTH_WRITEMASK + bool test_enabled = false; // GL_DEPTH_TEST + GLboolean write_mask = GL_TRUE; // GL_DEPTH_WRITEMASK + GLenum test_func = GL_LESS; // GL_DEPTH_FUNC } depth; struct { - bool enabled; - GLuint index; + bool enabled = false; + GLuint index = 0; } primitive_restart; // GL_PRIMITIVE_RESTART struct ColorMask { - GLboolean red_enabled; - GLboolean green_enabled; - GLboolean blue_enabled; - GLboolean alpha_enabled; + GLboolean red_enabled = GL_TRUE; + GLboolean green_enabled = GL_TRUE; + GLboolean blue_enabled = GL_TRUE; + GLboolean alpha_enabled = GL_TRUE; }; std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> color_mask; // GL_COLOR_WRITEMASK struct { - bool test_enabled; // GL_STENCIL_TEST + bool test_enabled = false; // GL_STENCIL_TEST struct { - GLenum test_func; // GL_STENCIL_FUNC - GLint test_ref; // GL_STENCIL_REF - GLuint test_mask; // GL_STENCIL_VALUE_MASK - GLuint write_mask; // GL_STENCIL_WRITEMASK - GLenum action_stencil_fail; // GL_STENCIL_FAIL - GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL - GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS + GLenum test_func = GL_ALWAYS; // GL_STENCIL_FUNC + GLint test_ref = 0; // GL_STENCIL_REF + GLuint test_mask = 0xFFFFFFFF; // GL_STENCIL_VALUE_MASK + GLuint write_mask = 0xFFFFFFFF; // GL_STENCIL_WRITEMASK + GLenum action_stencil_fail = GL_KEEP; // GL_STENCIL_FAIL + GLenum action_depth_fail = GL_KEEP; // GL_STENCIL_PASS_DEPTH_FAIL + GLenum action_depth_pass = GL_KEEP; // GL_STENCIL_PASS_DEPTH_PASS } front, back; } stencil; struct Blend { - bool enabled; // GL_BLEND - GLenum rgb_equation; // GL_BLEND_EQUATION_RGB - GLenum a_equation; // GL_BLEND_EQUATION_ALPHA - GLenum src_rgb_func; // GL_BLEND_SRC_RGB - GLenum dst_rgb_func; // GL_BLEND_DST_RGB - GLenum src_a_func; // GL_BLEND_SRC_ALPHA - GLenum dst_a_func; // GL_BLEND_DST_ALPHA + bool enabled = false; // GL_BLEND + GLenum rgb_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_RGB + GLenum a_equation = GL_FUNC_ADD; // GL_BLEND_EQUATION_ALPHA + GLenum src_rgb_func = GL_ONE; // GL_BLEND_SRC_RGB + GLenum dst_rgb_func = GL_ZERO; // GL_BLEND_DST_RGB + GLenum src_a_func = GL_ONE; // GL_BLEND_SRC_ALPHA + GLenum dst_a_func = GL_ZERO; // GL_BLEND_DST_ALPHA }; std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend; struct { - bool enabled; + bool enabled = false; } independant_blend; struct { - GLclampf red; - GLclampf green; - GLclampf blue; - GLclampf alpha; + GLclampf red = 0.0f; + GLclampf green = 0.0f; + GLclampf blue = 0.0f; + GLclampf alpha = 0.0f; } blend_color; // GL_BLEND_COLOR struct { - bool enabled; // GL_LOGIC_OP_MODE - GLenum operation; + bool enabled = false; // GL_LOGIC_OP_MODE + GLenum operation = GL_COPY; } logic_op; - std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures{}; - std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers{}; - std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images{}; + std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures = {}; + std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers = {}; + std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumImages> images = {}; struct { - GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING - GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING - GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING - GLuint shader_program; // GL_CURRENT_PROGRAM - GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING + GLuint read_framebuffer = 0; // GL_READ_FRAMEBUFFER_BINDING + GLuint draw_framebuffer = 0; // GL_DRAW_FRAMEBUFFER_BINDING + GLuint vertex_array = 0; // GL_VERTEX_ARRAY_BINDING + GLuint shader_program = 0; // GL_CURRENT_PROGRAM + GLuint program_pipeline = 0; // GL_PROGRAM_PIPELINE_BINDING } draw; - struct viewport { - GLint x; - GLint y; - GLint width; - GLint height; - GLfloat depth_range_near; // GL_DEPTH_RANGE - GLfloat depth_range_far; // GL_DEPTH_RANGE + struct Viewport { + GLint x = 0; + GLint y = 0; + GLint width = 0; + GLint height = 0; + GLfloat depth_range_near = 0.0f; // GL_DEPTH_RANGE + GLfloat depth_range_far = 1.0f; // GL_DEPTH_RANGE struct { - bool enabled; // GL_SCISSOR_TEST - GLint x; - GLint y; - GLsizei width; - GLsizei height; + bool enabled = false; // GL_SCISSOR_TEST + GLint x = 0; + GLint y = 0; + GLsizei width = 0; + GLsizei height = 0; } scissor; }; - std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; + std::array<Viewport, Tegra::Engines::Maxwell3D::Regs::NumViewports> viewports; struct { - float size; // GL_POINT_SIZE + float size = 1.0f; // GL_POINT_SIZE } point; struct { - bool point_enable; - bool line_enable; - bool fill_enable; - GLfloat units; - GLfloat factor; - GLfloat clamp; + bool point_enable = false; + bool line_enable = false; + bool fill_enable = false; + GLfloat units = 0.0f; + GLfloat factor = 0.0f; + GLfloat clamp = 0.0f; } polygon_offset; struct { - bool enabled; // GL_ALPHA_TEST - GLenum func; // GL_ALPHA_TEST_FUNC - GLfloat ref; // GL_ALPHA_TEST_REF + bool enabled = false; // GL_ALPHA_TEST + GLenum func = GL_ALWAYS; // GL_ALPHA_TEST_FUNC + GLfloat ref = 0.0f; // GL_ALPHA_TEST_REF } alpha_test; - std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE + std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE OpenGLState(); @@ -179,34 +157,31 @@ public: /// Apply this state as the current OpenGL state void Apply(); - void ApplyFramebufferState() const; - void ApplyVertexArrayState() const; - void ApplyShaderProgram() const; - void ApplyProgramPipeline() const; - void ApplyClipDistances() const; - void ApplyPointSize() const; - void ApplyFragmentColorClamp() const; - void ApplyMultisample() const; - void ApplySRgb() const; - void ApplyCulling() const; - void ApplyColorMask() const; - void ApplyDepth() const; - void ApplyPrimitiveRestart() const; - void ApplyStencilTest() const; - void ApplyViewport() const; - void ApplyTargetBlending(std::size_t target, bool force) const; - void ApplyGlobalBlending() const; - void ApplyBlending() const; - void ApplyLogicOp() const; - void ApplyTextures() const; - void ApplySamplers() const; - void ApplyImages() const; - void ApplyDepthClamp() const; - void ApplyPolygonOffset() const; - void ApplyAlphaTest() const; - - /// Set the initial OpenGL state - static void ApplyDefaultState(); + void ApplyFramebufferState(); + void ApplyVertexArrayState(); + void ApplyShaderProgram(); + void ApplyProgramPipeline(); + void ApplyClipDistances(); + void ApplyPointSize(); + void ApplyFragmentColorClamp(); + void ApplyMultisample(); + void ApplySRgb(); + void ApplyCulling(); + void ApplyColorMask(); + void ApplyDepth(); + void ApplyPrimitiveRestart(); + void ApplyStencilTest(); + void ApplyViewport(); + void ApplyTargetBlending(std::size_t target, bool force); + void ApplyGlobalBlending(); + void ApplyBlending(); + void ApplyLogicOp(); + void ApplyTextures(); + void ApplySamplers(); + void ApplyImages(); + void ApplyDepthClamp(); + void ApplyPolygonOffset(); + void ApplyAlphaTest(); /// Resets any references to the given resource OpenGLState& UnbindTexture(GLuint handle); @@ -253,5 +228,6 @@ private: bool color_mask; } dirty{}; }; +static_assert(std::is_trivially_copyable_v<OpenGLState>); } // namespace OpenGL diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index 8d3d962c7..ca690b58b 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp @@ -96,6 +96,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { } break; } + case OpCode::Id::TLD4_B: { + is_bindless = true; + [[fallthrough]]; + } case OpCode::Id::TLD4: { ASSERT(instr.tld4.array == 0); UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(TextureMiscMode::NDV), @@ -108,11 +112,14 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { } const auto texture_type = instr.tld4.texture_type.Value(); - const bool depth_compare = instr.tld4.UsesMiscMode(TextureMiscMode::DC); + const bool depth_compare = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::DC) + : instr.tld4.UsesMiscMode(TextureMiscMode::DC); const bool is_array = instr.tld4.array != 0; - const bool is_aoffi = instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI); + const bool is_aoffi = is_bindless ? instr.tld4_b.UsesMiscMode(TextureMiscMode::AOFFI) + : instr.tld4.UsesMiscMode(TextureMiscMode::AOFFI); WriteTexInstructionFloat( - bb, instr, GetTld4Code(instr, texture_type, depth_compare, is_array, is_aoffi)); + bb, instr, + GetTld4Code(instr, texture_type, depth_compare, is_array, is_aoffi, is_bindless)); break; } case OpCode::Id::TLD4S: { @@ -586,7 +593,7 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type, } Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare, - bool is_array, bool is_aoffi) { + bool is_array, bool is_aoffi, bool is_bindless) { const std::size_t coord_count = GetCoordCount(texture_type); // If enabled arrays index is always stored in the gpr8 field @@ -600,6 +607,12 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de } u64 parameter_register = instr.gpr20.Value(); + + const auto& sampler = + is_bindless + ? GetBindlessSampler(parameter_register++, {{texture_type, is_array, depth_compare}}) + : GetSampler(instr.sampler, {{texture_type, is_array, depth_compare}}); + std::vector<Node> aoffi; if (is_aoffi) { aoffi = GetAoffiCoordinates(GetRegister(parameter_register++), coord_count, true); @@ -610,12 +623,14 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de dc = GetRegister(parameter_register++); } - const auto& sampler = GetSampler(instr.sampler, {{texture_type, is_array, depth_compare}}); + const Node component = is_bindless ? Immediate(static_cast<u32>(instr.tld4_b.component)) + : Immediate(static_cast<u32>(instr.tld4.component)); Node4 values; for (u32 element = 0; element < values.size(); ++element) { auto coords_copy = coords; - MetaTexture meta{sampler, GetRegister(array_register), dc, aoffi, {}, {}, {}, element}; + MetaTexture meta{sampler, GetRegister(array_register), dc, aoffi, {}, {}, component, + element}; values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); } diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 5243644e8..26c8fde22 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -341,7 +341,7 @@ private: bool is_array); Node4 GetTld4Code(Tegra::Shader::Instruction instr, Tegra::Shader::TextureType texture_type, - bool depth_compare, bool is_array, bool is_aoffi); + bool depth_compare, bool is_array, bool is_aoffi, bool is_bindless); Node4 GetTldCode(Tegra::Shader::Instruction instr); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d6bb18d24..160613ee1 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1839,6 +1839,10 @@ void GMainWindow::OnLoadAmiibo() { return; } + LoadAmiibo(filename); +} + +void GMainWindow::LoadAmiibo(const QString& filename) { Core::System& system{Core::System::GetInstance()}; Service::SM::ServiceManager& sm = system.ServiceManager(); auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); @@ -2189,10 +2193,19 @@ static bool IsSingleFileDropEvent(QDropEvent* event) { } void GMainWindow::dropEvent(QDropEvent* event) { - if (IsSingleFileDropEvent(event) && ConfirmChangeGame()) { - const QMimeData* mimeData = event->mimeData(); - QString filename = mimeData->urls().at(0).toLocalFile(); - BootGame(filename); + if (!IsSingleFileDropEvent(event)) { + return; + } + + const QMimeData* mime_data = event->mimeData(); + const QString filename = mime_data->urls().at(0).toLocalFile(); + + if (emulation_running && QFileInfo(filename).suffix() == QStringLiteral("bin")) { + LoadAmiibo(filename); + } else { + if (ConfirmChangeGame()) { + BootGame(filename); + } } } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index fd4b9ccf5..7f46bea2b 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -142,6 +142,7 @@ private: void ShowTelemetryCallout(); void SetDiscordEnabled(bool state); + void LoadAmiibo(const QString& filename); void SelectAndSetCurrentUser(); |