Compare commits

..

1 Commits

Author SHA1 Message Date
9ffb91e8f4 Android #94 2023-10-08 00:57:47 +00:00
210 changed files with 1335 additions and 15724 deletions

View File

@ -5,6 +5,6 @@
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
ARTIFACTS_DIR="$PWD/artifacts"
ARTIFACTS_DIR="artifacts"
mkdir -p "${ARTIFACTS_DIR}/"

View File

@ -11,7 +11,7 @@ ccache -s
mkdir build || true && cd build
cmake .. \
-DBoost_USE_STATIC_LIBS=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-march=x86-64-v2" \
-DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ \
-DCMAKE_C_COMPILER=/usr/lib/ccache/gcc \
@ -31,19 +31,6 @@ ccache -s
ctest -VV -C Release
# Separate debug symbols from specified executables
for EXE in yuzu; do
EXE_PATH="bin/$EXE"
# Copy debug symbols out
objcopy --only-keep-debug $EXE_PATH $EXE_PATH.debug
# Add debug link and strip debug symbols
objcopy -g --add-gnu-debuglink=$EXE_PATH.debug $EXE_PATH $EXE_PATH.out
# Overwrite original with stripped copy
mv $EXE_PATH.out $EXE_PATH
done
# Strip debug symbols from all executables
find bin/ -type f -not -regex '.*.debug' -exec strip -g {} ';'
DESTDIR="$PWD/AppDir" ninja install
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester

View File

@ -59,9 +59,4 @@ if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ];
cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage"
fi
# Copy debug symbols to artifacts
cd build/bin
tar $COMPRESSION_FLAGS "${ARTIFACTS_DIR}/${REV_NAME}-debug.tar.xz" *.debug
cd -
. .ci/scripts/common/post-upload.sh

View File

@ -3,4 +3,4 @@
[codespell]
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink
ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink

View File

@ -11,6 +11,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modul
include(DownloadExternals)
include(CMakeDependentOption)
include(CTest)
include(FetchContent)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
@ -98,8 +99,47 @@ if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
DESTINATION "${vvl_lib_path}")
endif()
# On Android, fetch and compile libcxx before doing anything else
if (ANDROID)
set(CMAKE_SKIP_INSTALL_RULES ON)
set(LLVM_VERSION "15.0.6")
# Note: even though libcxx and libcxxabi have separate releases on the project page,
# the separated releases cannot be compiled. Only in-tree builds work. Therefore we
# must fetch the source release for the entire llvm tree.
FetchContent_Declare(llvm
URL "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz"
URL_HASH SHA256=9d53ad04dc60cb7b30e810faf64c5ab8157dadef46c8766f67f286238256ff92
TLS_VERIFY TRUE
)
FetchContent_MakeAvailable(llvm)
# libcxx has support for most of the range library, but it's gated behind a flag:
add_compile_definitions(_LIBCPP_ENABLE_EXPERIMENTAL)
# Disable standard header inclusion
set(ANDROID_STL "none")
# libcxxabi
set(LIBCXXABI_INCLUDE_TESTS OFF)
set(LIBCXXABI_ENABLE_SHARED FALSE)
set(LIBCXXABI_ENABLE_STATIC TRUE)
set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXX_TARGET_INCLUDE_DIRECTORY}" CACHE STRING "" FORCE)
add_subdirectory("${llvm_SOURCE_DIR}/libcxxabi" "${llvm_BINARY_DIR}/libcxxabi")
link_libraries(cxxabi_static)
# libcxx
set(LIBCXX_ABI_NAMESPACE "__ndk1" CACHE STRING "" FORCE)
set(LIBCXX_CXX_ABI "libcxxabi")
set(LIBCXX_INCLUDE_TESTS OFF)
set(LIBCXX_INCLUDE_BENCHMARKS OFF)
set(LIBCXX_INCLUDE_DOCS OFF)
set(LIBCXX_ENABLE_SHARED FALSE)
set(LIBCXX_ENABLE_STATIC TRUE)
set(LIBCXX_ENABLE_ASSERTIONS FALSE)
add_subdirectory("${llvm_SOURCE_DIR}/libcxx" "${llvm_BINARY_DIR}/libcxx")
set_target_properties(cxx-headers PROPERTIES INTERFACE_COMPILE_OPTIONS "-isystem${CMAKE_BINARY_DIR}/${LIBCXX_INSTALL_INCLUDE_DIR}")
link_libraries(cxx_static cxx-headers)
endif()
if (YUZU_USE_BUNDLED_VCPKG)
@ -289,7 +329,7 @@ find_package(Boost 1.79.0 REQUIRED context)
find_package(enet 1.3 MODULE)
find_package(fmt 9 REQUIRED)
find_package(inih 52 MODULE COMPONENTS INIReader)
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
find_package(LLVM 17 MODULE COMPONENTS Demangle)
find_package(lz4 REQUIRED)
find_package(nlohmann_json 3.8 REQUIRED)
find_package(Opus 1.3 MODULE)
@ -360,9 +400,6 @@ function(set_yuzu_qt_components)
if (ENABLE_QT_TRANSLATION)
list(APPEND YUZU_QT_COMPONENTS2 LinguistTools)
endif()
if (USE_DISCORD_PRESENCE)
list(APPEND YUZU_QT_COMPONENTS2 Network)
endif()
set(YUZU_QT_COMPONENTS ${YUZU_QT_COMPONENTS2} PARENT_SCOPE)
endfunction(set_yuzu_qt_components)

View File

@ -1,6 +1,5 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [11827](https://github.com/yuzu-emu/yuzu//pull/11827) | [`689f346e9`](https://github.com/yuzu-emu/yuzu//pull/11827/files) | nvnflinger: fix reporting and freeing of preallocated buffers | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -120,10 +120,6 @@ QWidget#connectedControllers {
background: transparent;
}
QWidget#closeButtons {
background: transparent;
}
QWidget#playersSupported,
QWidget#controllersSupported,
QWidget#controllerSupported1,

View File

@ -1380,10 +1380,6 @@ QWidget#connectedControllers {
background: transparent;
}
QWidget#closeButtons {
background: transparent;
}
QWidget#playersSupported,
QWidget#controllersSupported,
QWidget#controllerSupported1,

View File

@ -2305,10 +2305,6 @@ QWidget#connectedControllers {
background: transparent;
}
QWidget#closeButtons {
background: transparent;
}
QWidget#playersSupported,
QWidget#controllersSupported,
QWidget#controllerSupported1,

View File

@ -168,7 +168,7 @@ if (NOT TARGET LLVM::Demangle)
add_library(LLVM::Demangle ALIAS demangle)
endif()
add_library(stb stb/stb_dxt.cpp stb/stb_image.cpp stb/stb_image_resize.cpp)
add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)

View File

@ -27,7 +27,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID)
set(CAN_BUILD_NX_TZDB false)
endif()
set(NX_TZDB_VERSION "221202")
set(NX_TZDB_VERSION "220816")
set(NX_TZDB_ARCHIVE "${CMAKE_CURRENT_BINARY_DIR}/${NX_TZDB_VERSION}.zip")
set(NX_TZDB_ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx_tzdb")

File diff suppressed because it is too large Load Diff

View File

@ -1,772 +0,0 @@
// SPDX-FileCopyrightText: stb http://nothings.org/stb
// SPDX-License-Identifier: MIT
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
#define STB_IMAGE_IMPLEMENTATION
before you include this file in *one* C or C++ file to create the implementation.
// i.e. it should look like this:
#include ...
#include ...
#include ...
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
QUICK NOTES:
Primarily of interest to game developers and other people who can
avoid problematic images and only need the trivial interface
JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
PNG 1/2/4/8/16-bit-per-channel
TGA (not sure what subset, if a subset)
BMP non-1bpp, non-RLE
PSD (composited view only, no extra channels, 8/16 bit-per-channel)
GIF (*comp always reports as 4-channel)
HDR (radiance rgbE format)
PIC (Softimage PIC)
PNM (PPM and PGM binary only)
Animated GIF still needs a proper API, but here's one way to do it:
http://gist.github.com/urraka/685d9a6340b26b830d49
- decode from memory or through FILE (define STBI_NO_STDIO to remove code)
- decode from arbitrary I/O callbacks
- SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
Full documentation under "DOCUMENTATION" below.
LICENSE
See end of file for license information.
RECENT REVISION HISTORY:
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
2.26 (2020-07-13) many minor fixes
2.25 (2020-02-02) fix warnings
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
2.23 (2019-08-11) fix clang static analysis warning
2.22 (2019-03-04) gif fixes, fix warnings
2.21 (2019-02-25) fix typo in comment
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
RGB-format JPEG; remove white matting in PSD;
allocate large structures on the stack;
correct channel count for PNG & BMP
2.10 (2016-01-22) avoid warning introduced in 2.09
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
See end of file for full revision history.
============================ Contributors =========================
Image formats Extensions, features
Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
github:urraka (animated gif) Junggon Kim (PNM comments)
Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit PNG)
Jeremy Sawicki (handle all ImageNet JPGs)
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
Arseny Kapoulkine Simon Breuss (16-bit PNM)
John-Mark Allen
Carmelo J Fdez-Aguera
Bug & warning fixes
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
Phil Jordan Dave Moore Roy Eltham
Hayaki Saito Nathan Reed Won Chun
Luke Graham Johan Duparc Nick Verigakis the Horde3D community
Thomas Ruf Ronny Chevalier github:rlyeh
Janez Zemva John Bartholomew Michal Cichon github:romigrou
Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
Cass Everitt Ryamond Barbiero github:grim210
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
Brad Weinberger Matvey Cherevko github:mosra
Luca Sas Alexander Veselov Zack Middleton [reserved]
Ryan C. Gordon [reserved] [reserved]
DO NOT ADD YOUR NAME HERE
Jacko Dirks
To add your name to the credits, pick a random blank space in the middle and fill it.
80% of merge conflicts on stb PRs are due to people adding their name at the end
of the credits.
*/
#ifndef STBI_INCLUDE_STB_IMAGE_H
#define STBI_INCLUDE_STB_IMAGE_H
// DOCUMENTATION
//
// Limitations:
// - no 12-bit-per-channel JPEG
// - no JPEGs with arithmetic coding
// - GIF always returns *comp=4
//
// Basic usage (see HDR discussion below for HDR usage):
// int x,y,n;
// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// // ... process data if not NULL ...
// // ... x = width, y = height, n = # 8-bit components per pixel ...
// // ... replace '0' with '1'..'4' to force that many components per pixel
// // ... but 'n' will always be the number that it would have been if you said 0
// stbi_image_free(data);
//
// Standard parameters:
// int *x -- outputs image width in pixels
// int *y -- outputs image height in pixels
// int *channels_in_file -- outputs # of image components in image file
// int desired_channels -- if non-zero, # of image components requested in result
//
// The return value from an image loader is an 'unsigned char *' which points
// to the pixel data, or NULL on an allocation failure or if the image is
// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
// with each pixel consisting of N interleaved 8-bit components; the first
// pixel pointed to is top-left-most in the image. There is no padding between
// image scanlines or between pixels, regardless of format. The number of
// components N is 'desired_channels' if desired_channels is non-zero, or
// *channels_in_file otherwise. If desired_channels is non-zero,
// *channels_in_file has the number of components that _would_ have been
// output otherwise. E.g. if you set desired_channels to 4, you will always
// get RGBA output, but you can check *channels_in_file to see if it's trivially
// opaque because e.g. there were only 3 channels in the source image.
//
// An output image with N components has the following components interleaved
// in this order in each pixel:
//
// N=#comp components
// 1 grey
// 2 grey, alpha
// 3 red, green, blue
// 4 red, green, blue, alpha
//
// If image loading fails for any reason, the return value will be NULL,
// and *x, *y, *channels_in_file will be unchanged. The function
// stbi_failure_reason() can be queried for an extremely brief, end-user
// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
// more user-friendly ones.
//
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
//
// To query the width, height and component count of an image without having to
// decode the full file, you can use the stbi_info family of functions:
//
// int x,y,n,ok;
// ok = stbi_info(filename, &x, &y, &n);
// // returns ok=1 and sets x, y, n if image is a supported format,
// // 0 otherwise.
//
// Note that stb_image pervasively uses ints in its public API for sizes,
// including sizes of memory buffers. This is now part of the API and thus
// hard to change without causing breakage. As a result, the various image
// loaders all have certain limits on image size; these differ somewhat
// by format but generally boil down to either just under 2GB or just under
// 1GB. When the decoded image would be larger than this, stb_image decoding
// will fail.
//
// Additionally, stb_image will reject image files that have any of their
// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
// the only way to have an image with such dimensions load correctly
// is for it to have a rather extreme aspect ratio. Either way, the
// assumption here is that such larger images are likely to be malformed
// or malicious. If you do need to load an image with individual dimensions
// larger than that, and it still fits in the overall size limit, you can
// #define STBI_MAX_DIMENSIONS on your own to be something larger.
//
// ===========================================================================
//
// UNICODE:
//
// If compiling for Windows and you wish to use Unicode filenames, compile
// with
// #define STBI_WINDOWS_UTF8
// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
// Windows wchar_t filenames to utf8.
//
// ===========================================================================
//
// Philosophy
//
// stb libraries are designed with the following priorities:
//
// 1. easy to use
// 2. easy to maintain
// 3. good performance
//
// Sometimes I let "good performance" creep up in priority over "easy to maintain",
// and for best performance I may provide less-easy-to-use APIs that give higher
// performance, in addition to the easy-to-use ones. Nevertheless, it's important
// to keep in mind that from the standpoint of you, a client of this library,
// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
//
// Some secondary priorities arise directly from the first two, some of which
// provide more explicit reasons why performance can't be emphasized.
//
// - Portable ("ease of use")
// - Small source code footprint ("easy to maintain")
// - No dependencies ("ease of use")
//
// ===========================================================================
//
// I/O callbacks
//
// I/O callbacks allow you to read from arbitrary sources, like packaged
// files or some other source. Data read from callbacks are processed
// through a small internal buffer (currently 128 bytes) to try to reduce
// overhead.
//
// The three functions you must define are "read" (reads some bytes of data),
// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
//
// ===========================================================================
//
// SIMD support
//
// The JPEG decoder will try to automatically use SIMD kernels on x86 when
// supported by the compiler. For ARM Neon support, you must explicitly
// request it.
//
// (The old do-it-yourself SIMD API is no longer supported in the current
// code.)
//
// On x86, SSE2 will automatically be used when available based on a run-time
// test; if not, the generic C versions are used as a fall-back. On ARM targets,
// the typical path is to have separate builds for NEON and non-NEON devices
// (at least this is true for iOS and Android). Therefore, the NEON support is
// toggled by a build flag: define STBI_NEON to get NEON loops.
//
// If for some reason you do not want to use any of SIMD code, or if
// you have issues compiling it, you can disable it entirely by
// defining STBI_NO_SIMD.
//
// ===========================================================================
//
// HDR image support (disable by defining STBI_NO_HDR)
//
// stb_image supports loading HDR images in general, and currently the Radiance
// .HDR file format specifically. You can still load any file through the existing
// interface; if you attempt to load an HDR file, it will be automatically remapped
// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
// both of these constants can be reconfigured through this interface:
//
// stbi_hdr_to_ldr_gamma(2.2f);
// stbi_hdr_to_ldr_scale(1.0f);
//
// (note, do not use _inverse_ constants; stbi_image will invert them
// appropriately).
//
// Additionally, there is a new, parallel interface for loading files as
// (linear) floats to preserve the full dynamic range:
//
// float *data = stbi_loadf(filename, &x, &y, &n, 0);
//
// If you load LDR images through this interface, those images will
// be promoted to floating point values, run through the inverse of
// constants corresponding to the above:
//
// stbi_ldr_to_hdr_scale(1.0f);
// stbi_ldr_to_hdr_gamma(2.2f);
//
// Finally, given a filename (or an open file or memory block--see header
// file for details) containing image data, you can query for the "most
// appropriate" interface to use (that is, whether the image is HDR or
// not), using:
//
// stbi_is_hdr(char *filename);
//
// ===========================================================================
//
// iPhone PNG support:
//
// We optionally support converting iPhone-formatted PNGs (which store
// premultiplied BGRA) back to RGB, even though they're internally encoded
// differently. To enable this conversion, call
// stbi_convert_iphone_png_to_rgb(1).
//
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
// pixel to remove any premultiplied alpha *only* if the image file explicitly
// says there's premultiplied data (currently only happens in iPhone images,
// and only if iPhone convert-to-rgb processing is on).
//
// ===========================================================================
//
// ADDITIONAL CONFIGURATION
//
// - You can suppress implementation of any of the decoders to reduce
// your code footprint by #defining one or more of the following
// symbols before creating the implementation.
//
// STBI_NO_JPEG
// STBI_NO_PNG
// STBI_NO_BMP
// STBI_NO_PSD
// STBI_NO_TGA
// STBI_NO_GIF
// STBI_NO_HDR
// STBI_NO_PIC
// STBI_NO_PNM (.ppm and .pgm)
//
// - You can request *only* certain decoders and suppress all other ones
// (this will be more forward-compatible, as addition of new decoders
// doesn't require you to disable them explicitly):
//
// STBI_ONLY_JPEG
// STBI_ONLY_PNG
// STBI_ONLY_BMP
// STBI_ONLY_PSD
// STBI_ONLY_TGA
// STBI_ONLY_GIF
// STBI_ONLY_HDR
// STBI_ONLY_PIC
// STBI_ONLY_PNM (.ppm and .pgm)
//
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
//
// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
// than that size (in either width or height) without further processing.
// This is to let programs in the wild set an upper bound to prevent
// denial-of-service attacks on untrusted data, as one could generate a
// valid image of gigantic dimensions and force stb_image to allocate a
// huge block of memory and spend disproportionate time decoding it. By
// default this is set to (1 << 24), which is 16777216, but that's still
// very big.
#ifndef STBI_NO_STDIO
#include <stdio.h>
#endif // STBI_NO_STDIO
#define STBI_VERSION 1
enum
{
STBI_default = 0, // only used for desired_channels
STBI_grey = 1,
STBI_grey_alpha = 2,
STBI_rgb = 3,
STBI_rgb_alpha = 4
};
#include <stdlib.h>
typedef unsigned char stbi_uc;
typedef unsigned short stbi_us;
#ifdef __cplusplus
extern "C" {
#endif
#ifndef STBIDEF
#ifdef STB_IMAGE_STATIC
#define STBIDEF static
#else
#define STBIDEF extern
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// PRIMARY API - works on images of any type
//
//
// load image by filename, open file, or memory buffer
//
typedef struct
{
int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
int (*eof) (void *user); // returns nonzero if we are at end of file/data
} stbi_io_callbacks;
////////////////////////////////////
//
// 8-bits-per-channel interface
//
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
// for stbi_load_from_file, file pointer is left pointing immediately after image
#endif
#ifndef STBI_NO_GIF
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
#endif
#ifdef STBI_WINDOWS_UTF8
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif
////////////////////////////////////
//
// 16-bits-per-channel interface
//
STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
////////////////////////////////////
//
// float-per-channel interface
//
#ifndef STBI_NO_LINEAR
STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
#endif
#ifndef STBI_NO_HDR
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
STBIDEF void stbi_hdr_to_ldr_scale(float scale);
#endif // STBI_NO_HDR
#ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
STBIDEF void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_LINEAR
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
#ifndef STBI_NO_STDIO
STBIDEF int stbi_is_hdr (char const *filename);
STBIDEF int stbi_is_hdr_from_file(FILE *f);
#endif // STBI_NO_STDIO
// get a VERY brief reason for failure
// on most compilers (and ALL modern mainstream compilers) this is threadsafe
STBIDEF const char *stbi_failure_reason (void);
// free the loaded image -- this is just free()
STBIDEF void stbi_image_free (void *retval_from_stbi_load);
// get image dimensions & components without fully decoding
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
#ifndef STBI_NO_STDIO
STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit (char const *filename);
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
#endif
// for image formats that explicitly notate that they have premultiplied alpha,
// we just return the colors as stored in the file. set this flag to force
// unpremultiplication. results are undefined if the unpremultiply overflow.
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
// indicate whether we should process iphone images back to canonical format,
// or just pass them through "as-is"
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
// flip the image vertically, so the first pixel in the output array is the bottom left
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
// as above, but only applies to images loaded on the thread that calls the function
// this function is only available if your compiler supports thread-local variables;
// calling it will fail to link if your compiler doesn't
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
// ZLIB client - used by PNG, available for other purposes
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
#ifdef __cplusplus
}
#endif
//
//
//// end header file /////////////////////////////////////////////////////
#endif // STBI_INCLUDE_STB_IMAGE_H
/*
revision history:
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
1-bit BMP
*_is_16_bit api
avoid warnings
2.16 (2017-07-23) all functions have 16-bit variants;
STBI_NO_STDIO works again;
compilation fixes;
fix rounding in unpremultiply;
optimize vertical flip;
disable raw_len validation;
documentation fixes
2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
warning fixes; disable run-time SSE detection on gcc;
uniform handling of optional "return" values;
thread-safe initialization of zlib tables
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) allocate large structures on the stack
remove white matting for transparent PSD
fix reported channel count for PNG & BMP
re-enable SSE2 in non-gcc 64-bit
support RGB-formatted JPEG
read 16-bit PNGs (only as 8-bit)
2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
2.09 (2016-01-16) allow comments in PNM files
16-bit-per-pixel TGA (not bit-per-component)
info() for TGA could break due to .hdr handling
info() for BMP to shares code instead of sloppy parse
can use STBI_REALLOC_SIZED if allocator doesn't support realloc
code cleanup
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) fix compiler warnings
partial animated GIF support
limited 16-bpc PSD support
#ifdef unused functions
bug with < 92 byte PIC,PNM,HDR,TGA
2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
2.03 (2015-04-12) extra corruption checking (mmozeiko)
stbi_set_flip_vertically_on_load (nguillemot)
fix NEON support; fix mingw support
2.02 (2015-01-19) fix incorrect assert, fix warning
2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
progressive JPEG (stb)
PGM/PPM support (Ken Miller)
STBI_MALLOC,STBI_REALLOC,STBI_FREE
GIF bugfix -- seemingly never worked
STBI_NO_*, STBI_ONLY_*
1.48 (2014-12-14) fix incorrectly-named assert()
1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
optimize PNG (ryg)
fix bug in interlaced PNG with user-specified channel count (stb)
1.46 (2014-08-26)
fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
1.45 (2014-08-16)
fix MSVC-ARM internal compiler error by wrapping malloc
1.44 (2014-08-07)
various warning fixes from Ronny Chevalier
1.43 (2014-07-15)
fix MSVC-only compiler problem in code changed in 1.42
1.42 (2014-07-09)
don't define _CRT_SECURE_NO_WARNINGS (affects user code)
fixes to stbi__cleanup_jpeg path
added STBI_ASSERT to avoid requiring assert.h
1.41 (2014-06-25)
fix search&replace from 1.36 that messed up comments/error messages
1.40 (2014-06-22)
fix gcc struct-initialization warning
1.39 (2014-06-15)
fix to TGA optimization when req_comp != number of components in TGA;
fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
add support for BMP version 5 (more ignored fields)
1.38 (2014-06-06)
suppress MSVC warnings on integer casts truncating values
fix accidental rename of 'skip' field of I/O
1.37 (2014-06-04)
remove duplicate typedef
1.36 (2014-06-03)
convert to header file single-file library
if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
1.35 (2014-05-27)
various warnings
fix broken STBI_SIMD path
fix bug where stbi_load_from_file no longer left file pointer in correct place
fix broken non-easy path for 32-bit BMP (possibly never used)
TGA optimization by Arseny Kapoulkine
1.34 (unknown)
use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
1.33 (2011-07-14)
make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
1.32 (2011-07-13)
support for "info" function for all supported filetypes (SpartanJ)
1.31 (2011-06-20)
a few more leak fixes, bug in PNG handling (SpartanJ)
1.30 (2011-06-11)
added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
removed deprecated format-specific test/load functions
removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
fix inefficiency in decoding 32-bit BMP (David Woo)
1.29 (2010-08-16)
various warning fixes from Aurelien Pocheville
1.28 (2010-08-01)
fix bug in GIF palette transparency (SpartanJ)
1.27 (2010-08-01)
cast-to-stbi_uc to fix warnings
1.26 (2010-07-24)
fix bug in file buffering for PNG reported by SpartanJ
1.25 (2010-07-17)
refix trans_data warning (Won Chun)
1.24 (2010-07-12)
perf improvements reading from files on platforms with lock-heavy fgetc()
minor perf improvements for jpeg
deprecated type-specific functions so we'll get feedback if they're needed
attempt to fix trans_data warning (Won Chun)
1.23 fixed bug in iPhone support
1.22 (2010-07-10)
removed image *writing* support
stbi_info support from Jetro Lauha
GIF support from Jean-Marc Lienher
iPhone PNG-extensions from James Brown
warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
1.21 fix use of 'stbi_uc' in header (reported by jon blow)
1.20 added support for Softimage PIC, by Tom Seddon
1.19 bug in interlaced PNG corruption check (found by ryg)
1.18 (2008-08-02)
fix a threading bug (local mutable static)
1.17 support interlaced PNG
1.16 major bugfix - stbi__convert_format converted one too many pixels
1.15 initialize some fields for thread safety
1.14 fix threadsafe conversion bug
header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
1.13 threadsafe
1.12 const qualifiers in the API
1.11 Support installable IDCT, colorspace conversion routines
1.10 Fixes for 64-bit (don't use "unsigned long")
optimized upsampling by Fabian "ryg" Giesen
1.09 Fix format-conversion for PSD code (bad global variables!)
1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
1.07 attempt to fix C++ warning/errors again
1.06 attempt to fix C++ warning/errors again
1.05 fix TGA loading to return correct *comp and use good luminance calc
1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
1.02 support for (subset of) HDR files, float interface for preferred access to them
1.01 fix bug: possible bug in handling right-side up bmps... not sure
fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
1.00 interface to zlib that skips zlib header
0.99 correct handling of alpha in palette
0.98 TGA loader by lonesock; dynamically add loaders (untested)
0.97 jpeg errors on too large a file; also catch another malloc failure
0.96 fix detection of invalid v value - particleman@mollyrocket forum
0.95 during header scan, seek to markers in case of padding
0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
0.93 handle jpegtran output; verbose errors
0.92 read 4,8,16,24,32-bit BMP files of several formats
0.91 output 24-bit Windows 3.0 BMP files
0.90 fix a few more warnings; bump version number to approach 1.0
0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
0.60 fix compiling as c++
0.59 fix warnings: merge Dave Moore's -Wall fixes
0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
0.56 fix bug: zlib uncompressed mode len vs. nlen
0.55 fix bug: restart_interval not initialized to 0
0.54 allow NULL for 'int *comp'
0.53 fix bug in png 3->4; speedup png decoding
0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
0.51 obey req_comp requests, 1-component jpegs return as 1-component,
on 'test' only check type, not whether we support this variant
0.50 (2006-11-19)
first released version
*/
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,426 +0,0 @@
// SPDX-FileCopyrightText: Jorge L Rodriguez
// SPDX-License-Identifier: MIT
/* stb_image_resize - v0.97 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb
Written with emphasis on usability, portability, and efficiency. (No
SIMD or threads, so it be easily outperformed by libs that use those.)
Only scaling and translation is supported, no rotations or shears.
Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
COMPILING & LINKING
In one C/C++ file that #includes this file, do this:
#define STB_IMAGE_RESIZE_IMPLEMENTATION
before the #include. That will create the implementation in that file.
QUICKSTART
stbir_resize_uint8( input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0, num_channels)
stbir_resize_float(...)
stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0)
stbir_resize_uint8_srgb_edgemode(
input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
// WRAP/REFLECT/ZERO
FULL API
See the "header file" section of the source for API documentation.
ADDITIONAL DOCUMENTATION
SRGB & FLOATING POINT REPRESENTATION
The sRGB functions presume IEEE floating point. If you do not have
IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
a slower implementation.
MEMORY ALLOCATION
The resize functions here perform a single memory allocation using
malloc. To control the memory allocation, before the #include that
triggers the implementation, do:
#define STBIR_MALLOC(size,context) ...
#define STBIR_FREE(ptr,context) ...
Each resize function makes exactly one call to malloc/free, so to use
temp memory, store the temp memory in the context and return that.
ASSERT
Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
OPTIMIZATION
Define STBIR_SATURATE_INT to compute clamp values in-range using
integer operations instead of float operations. This may be faster
on some platforms.
DEFAULT FILTERS
For functions which don't provide explicit control over what filters
to use, you can change the compile-time defaults with
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
See stbir_filter in the header-file section for the list of filters.
NEW FILTERS
A number of 1D filter kernels are used. For a list of
supported filters see the stbir_filter enum. To add a new filter,
write a filter function and add it to stbir__filter_info_table.
PROGRESS
For interactive use with slow resize operations, you can install
a progress-report callback:
#define STBIR_PROGRESS_REPORT(val) some_func(val)
The parameter val is a float which goes from 0 to 1 as progress is made.
For example:
static void my_progress_report(float progress);
#define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
static void my_progress_report(float progress)
{
printf("Progress: %f%%\n", progress*100);
}
MAX CHANNELS
If your image has more than 64 channels, define STBIR_MAX_CHANNELS
to the max you'll have.
ALPHA CHANNEL
Most of the resizing functions provide the ability to control how
the alpha channel of an image is processed. The important things
to know about this:
1. The best mathematically-behaved version of alpha to use is
called "premultiplied alpha", in which the other color channels
have had the alpha value multiplied in. If you use premultiplied
alpha, linear filtering (such as image resampling done by this
library, or performed in texture units on GPUs) does the "right
thing". While premultiplied alpha is standard in the movie CGI
industry, it is still uncommon in the videogame/real-time world.
If you linearly filter non-premultiplied alpha, strange effects
occur. (For example, the 50/50 average of 99% transparent bright green
and 1% transparent black produces 50% transparent dark green when
non-premultiplied, whereas premultiplied it produces 50%
transparent near-black. The former introduces green energy
that doesn't exist in the source image.)
2. Artists should not edit premultiplied-alpha images; artists
want non-premultiplied alpha images. Thus, art tools generally output
non-premultiplied alpha images.
3. You will get best results in most cases by converting images
to premultiplied alpha before processing them mathematically.
4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
resizer does not do anything special for the alpha channel;
it is resampled identically to other channels. This produces
the correct results for premultiplied-alpha images, but produces
less-than-ideal results for non-premultiplied-alpha images.
5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
then the resizer weights the contribution of input pixels
based on their alpha values, or, equivalently, it multiplies
the alpha value into the color channels, resamples, then divides
by the resultant alpha value. Input pixels which have alpha=0 do
not contribute at all to output pixels unless _all_ of the input
pixels affecting that output pixel have alpha=0, in which case
the result for that pixel is the same as it would be without
STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
input images in integer formats. For input images in float format,
input pixels with alpha=0 have no effect, and output pixels
which have alpha=0 will be 0 in all channels. (For float images,
you can manually achieve the same result by adding a tiny epsilon
value to the alpha channel of every image, and then subtracting
or clamping it at the end.)
6. You can suppress the behavior described in #5 and make
all-0-alpha pixels have 0 in all channels by #defining
STBIR_NO_ALPHA_EPSILON.
7. You can separately control whether the alpha channel is
interpreted as linear or affected by the colorspace. By default
it is linear; you almost never want to apply the colorspace.
(For example, graphics hardware does not apply sRGB conversion
to the alpha channel.)
CONTRIBUTORS
Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix
Nathan Reed: warning fixes
REVISIONS
0.97 (2020-02-02) fixed warning
0.96 (2019-03-04) fixed warnings
0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings
0.93 (2017-03-03) fixed bug with certain combinations of heights
0.92 (2017-01-02) fix integer overflow on large (>2GB) images
0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
0.90 (2014-09-17) first released version
LICENSE
See end of file for license information.
TODO
Don't decode all of the image data when only processing a partial tile
Don't use full-width decode buffers when only processing a partial tile
When processing wide images, break processing into tiles so data fits in L1 cache
Installable filters?
Resize that respects alpha test coverage
(Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
*/
#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
#ifdef _MSC_VER
typedef unsigned char stbir_uint8;
typedef unsigned short stbir_uint16;
typedef unsigned int stbir_uint32;
#else
#include <stdint.h>
typedef uint8_t stbir_uint8;
typedef uint16_t stbir_uint16;
typedef uint32_t stbir_uint32;
#endif
#ifndef STBIRDEF
#ifdef STB_IMAGE_RESIZE_STATIC
#define STBIRDEF static
#else
#ifdef __cplusplus
#define STBIRDEF extern "C"
#else
#define STBIRDEF extern
#endif
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// Easy-to-use API:
//
// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
// * input_w is input image width (x-axis), input_h is input image height (y-axis)
// * stride is the offset between successive rows of image data in memory, in bytes. you can
// specify 0 to mean packed continuously in memory
// * alpha channel is treated identically to other channels.
// * colorspace is linear or sRGB as specified by function name
// * returned result is 1 for success or 0 in case of an error.
// #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
// * Memory required grows approximately linearly with input and output size, but with
// discontinuities at input_w == output_w and input_h == output_h.
// * These functions use a "default" resampling filter defined at compile time. To change the filter,
// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels);
STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels);
// The following functions interpret image data as gamma-corrected sRGB.
// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
// or otherwise provide the index of the alpha channel. Flags value
// of 0 will probably do the right thing if you're not sure what
// the flags mean.
#define STBIR_ALPHA_CHANNEL_NONE -1
// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
// use alpha-weighted resampling (effectively premultiplying, resampling,
// then unpremultiplying).
#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
// The specified alpha channel should be handled as gamma-corrected value even
// when doing sRGB operations.
#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags);
typedef enum
{
STBIR_EDGE_CLAMP = 1,
STBIR_EDGE_REFLECT = 2,
STBIR_EDGE_WRAP = 3,
STBIR_EDGE_ZERO = 4,
} stbir_edge;
// This function adds the ability to specify how requests to sample off the edge of the image are handled.
STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode);
//////////////////////////////////////////////////////////////////////////////
//
// Medium-complexity API
//
// This extends the easy-to-use API as follows:
//
// * Alpha-channel can be processed separately
// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
// * Filter can be selected explicitly
// * uint16 image type
// * sRGB colorspace available for all types
// * context parameter for passing to STBIR_MALLOC
typedef enum
{
STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
} stbir_filter;
typedef enum
{
STBIR_COLORSPACE_LINEAR,
STBIR_COLORSPACE_SRGB,
STBIR_MAX_COLORSPACES,
} stbir_colorspace;
// The following functions are all identical except for the type of the image data
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
//////////////////////////////////////////////////////////////////////////////
//
// Full-complexity API
//
// This extends the medium API as follows:
//
// * uint32 image type
// * not typesafe
// * separate filter types for each axis
// * separate edge modes for each axis
// * can specify scale explicitly for subpixel correctness
// * can specify image source tile using texture coordinates
typedef enum
{
STBIR_TYPE_UINT8 ,
STBIR_TYPE_UINT16,
STBIR_TYPE_UINT32,
STBIR_TYPE_FLOAT ,
STBIR_MAX_TYPES
} stbir_datatype;
STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context);
STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float x_scale, float y_scale,
float x_offset, float y_offset);
STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float s0, float t0, float s1, float t1);
// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
//
//
//// end header file /////////////////////////////////////////////////////
#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View File

@ -27,7 +27,7 @@ android {
namespace = "org.yuzu.yuzu_emu"
compileSdkVersion = "android-34"
ndkVersion = "26.1.10909125"
ndkVersion = "25.2.9519653"
buildFeatures {
viewBinding = true
@ -203,23 +203,23 @@ ktlint {
}
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.core:core-ktx:1.10.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.recyclerview:recyclerview:1.3.1")
implementation("androidx.recyclerview:recyclerview:1.3.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.fragment:fragment-ktx:1.6.1")
implementation("androidx.fragment:fragment-ktx:1.6.0")
implementation("androidx.documentfile:documentfile:1.0.1")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
implementation("androidx.preference:preference:1.2.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
implementation("io.coil-kt:coil:2.2.2")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation("androidx.window:window:1.2.0-beta03")
implementation("org.ini4j:ini4j:0.5.4")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
implementation("info.debatty:java-string-similarity:2.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
}

View File

@ -28,6 +28,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:appCategory="game"
android:localeConfig="@xml/locales_config"
android:banner="@drawable/tv_banner"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/data_extraction_rules"
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
android:enableOnBackInvokedCallback="true">

View File

@ -15,9 +15,13 @@ import androidx.annotation.Keep
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.YuzuApplication.Companion.appContext
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.utils.DocumentsTree.Companion.isNativePath
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.FileUtil.exists
import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize
import org.yuzu.yuzu_emu.utils.FileUtil.isDirectory
import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
@ -71,7 +75,7 @@ object NativeLibrary {
return if (isNativePath(path!!)) {
YuzuApplication.documentsTree!!.openContentUri(path, openmode)
} else {
FileUtil.openContentUri(path, openmode)
openContentUri(appContext, path, openmode)
}
}
@ -81,7 +85,7 @@ object NativeLibrary {
return if (isNativePath(path!!)) {
YuzuApplication.documentsTree!!.getFileSize(path)
} else {
FileUtil.getFileSize(path)
getFileSize(appContext, path)
}
}
@ -91,7 +95,7 @@ object NativeLibrary {
return if (isNativePath(path!!)) {
YuzuApplication.documentsTree!!.exists(path)
} else {
FileUtil.exists(path)
exists(appContext, path)
}
}
@ -101,7 +105,7 @@ object NativeLibrary {
return if (isNativePath(path!!)) {
YuzuApplication.documentsTree!!.isDirectory(path)
} else {
FileUtil.isDirectory(path)
isDirectory(appContext, path)
}
}

View File

@ -47,7 +47,7 @@ class YuzuApplication : Application() {
application = this
documentsTree = DocumentsTree()
DirectoryInitialization.start()
GpuDriverHelper.initializeDriverParameters()
GpuDriverHelper.initializeDriverParameters(applicationContext)
NativeLibrary.logDeviceInfo()
createNotificationChannels()

View File

@ -1,117 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
class DriverAdapter(private val driverViewModel: DriverViewModel) :
ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
val binding =
CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return DriverViewHolder(binding)
}
override fun getItemCount(): Int = currentList.size
override fun onBindViewHolder(holder: DriverViewHolder, position: Int) =
holder.bind(currentList[position])
private fun onSelectDriver(position: Int) {
driverViewModel.setSelectedDriverIndex(position)
notifyItemChanged(driverViewModel.previouslySelectedDriver)
notifyItemChanged(driverViewModel.selectedDriver)
}
private fun onDeleteDriver(driverData: Pair<String, GpuDriverMetadata>, position: Int) {
if (driverViewModel.selectedDriver > position) {
driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1)
}
if (GpuDriverHelper.customDriverData == driverData.second) {
driverViewModel.setSelectedDriverIndex(0)
}
driverViewModel.driversToDelete.add(driverData.first)
driverViewModel.removeDriver(driverData)
notifyItemRemoved(position)
notifyItemChanged(driverViewModel.selectedDriver)
}
inner class DriverViewHolder(val binding: CardDriverOptionBinding) :
RecyclerView.ViewHolder(binding.root) {
private lateinit var driverData: Pair<String, GpuDriverMetadata>
fun bind(driverData: Pair<String, GpuDriverMetadata>) {
this.driverData = driverData
val driver = driverData.second
binding.apply {
radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition
root.setOnClickListener {
onSelectDriver(bindingAdapterPosition)
}
buttonDelete.setOnClickListener {
onDeleteDriver(driverData, bindingAdapterPosition)
}
// Delay marquee by 3s
title.postDelayed(
{
title.isSelected = true
title.ellipsize = TextUtils.TruncateAt.MARQUEE
version.isSelected = true
version.ellipsize = TextUtils.TruncateAt.MARQUEE
description.isSelected = true
description.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
if (driver.name == null) {
title.setText(R.string.system_gpu_driver)
description.text = ""
version.text = ""
version.visibility = View.GONE
description.visibility = View.GONE
buttonDelete.visibility = View.GONE
} else {
title.text = driver.name
version.text = driver.version
description.text = driver.description
version.visibility = View.VISIBLE
description.visibility = View.VISIBLE
buttonDelete.visibility = View.VISIBLE
}
}
}
}
private class DiffCallback : DiffUtil.ItemCallback<Pair<String, GpuDriverMetadata>>() {
override fun areItemsTheSame(
oldItem: Pair<String, GpuDriverMetadata>,
newItem: Pair<String, GpuDriverMetadata>
): Boolean {
return oldItem.first == newItem.first
}
override fun areContentsTheSame(
oldItem: Pair<String, GpuDriverMetadata>,
newItem: Pair<String, GpuDriverMetadata>
): Boolean {
return oldItem.second == newItem.second
}
}
}

View File

@ -1,186 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.DriverAdapter
import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import java.io.File
import java.io.IOException
class DriverManagerFragment : Fragment() {
private var _binding: FragmentDriverManagerBinding? = null
private val binding get() = _binding!!
private val homeViewModel: HomeViewModel by activityViewModels()
private val driverViewModel: DriverViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentDriverManagerBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true)
homeViewModel.setStatusBarShadeVisibility(visible = false)
if (!driverViewModel.isInteractionAllowed) {
DriversLoadingDialogFragment().show(
childFragmentManager,
DriversLoadingDialogFragment.TAG
)
}
binding.toolbarDrivers.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}
binding.buttonInstall.setOnClickListener {
getDriver.launch(arrayOf("application/zip"))
}
binding.listDrivers.apply {
layoutManager = GridLayoutManager(
requireContext(),
resources.getInteger(R.integer.grid_columns)
)
adapter = DriverAdapter(driverViewModel)
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
driverViewModel.driverList.collectLatest {
(binding.listDrivers.adapter as DriverAdapter).submitList(it)
}
}
launch {
driverViewModel.newDriverInstalled.collect {
if (_binding != null && it) {
(binding.listDrivers.adapter as DriverAdapter).apply {
notifyItemChanged(driverViewModel.previouslySelectedDriver)
notifyItemChanged(driverViewModel.selectedDriver)
driverViewModel.setNewDriverInstalled(false)
}
}
}
}
}
setInsets()
}
// Start installing requested driver
override fun onStop() {
super.onStop()
driverViewModel.onCloseDriverManager()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
) { _: View, windowInsets: WindowInsetsCompat ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.toolbarDrivers.layoutParams as ViewGroup.MarginLayoutParams
mlpAppBar.leftMargin = leftInsets
mlpAppBar.rightMargin = rightInsets
binding.toolbarDrivers.layoutParams = mlpAppBar
val mlplistDrivers = binding.listDrivers.layoutParams as ViewGroup.MarginLayoutParams
mlplistDrivers.leftMargin = leftInsets
mlplistDrivers.rightMargin = rightInsets
binding.listDrivers.layoutParams = mlplistDrivers
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
val mlpFab =
binding.buttonInstall.layoutParams as ViewGroup.MarginLayoutParams
mlpFab.leftMargin = leftInsets + fabSpacing
mlpFab.rightMargin = rightInsets + fabSpacing
mlpFab.bottomMargin = barInsets.bottom + fabSpacing
binding.buttonInstall.layoutParams = mlpFab
binding.listDrivers.updatePadding(
bottom = barInsets.bottom +
resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab)
)
windowInsets
}
private val getDriver =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
requireActivity(),
R.string.installing_driver,
false
) {
val driverPath =
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}"
val driverFile = File(driverPath)
// Ignore file exceptions when a user selects an invalid zip
try {
if (!GpuDriverHelper.copyDriverToInternalStorage(result)) {
throw IOException("Driver failed validation!")
}
} catch (_: IOException) {
if (driverFile.exists()) {
driverFile.delete()
}
return@newInstance getString(R.string.select_gpu_driver_error)
}
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
val driverInList =
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
if (driverInList != null) {
return@newInstance getString(R.string.driver_already_installed)
} else {
driverViewModel.addDriver(Pair(driverPath, driverData))
driverViewModel.setNewDriverInstalled(true)
}
return@newInstance Any()
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
}
}

View File

@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.DriverViewModel
class DriversLoadingDialogFragment : DialogFragment() {
private val driverViewModel: DriverViewModel by activityViewModels()
private lateinit var binding: DialogProgressBarBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
binding = DialogProgressBarBinding.inflate(layoutInflater)
binding.progressBar.isIndeterminate = true
isCancelable = false
return MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.loading)
.setView(binding.root)
.create()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = binding.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.areDriversLoading.collect { checkForDismiss() }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isDriverReady.collect { checkForDismiss() }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isDeletingDrivers.collect { checkForDismiss() }
}
}
}
}
private fun checkForDismiss() {
if (driverViewModel.isInteractionAllowed) {
dismiss()
}
}
companion object {
const val TAG = "DriversLoadingDialogFragment"
}
}

View File

@ -39,7 +39,6 @@ import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections
@ -51,7 +50,6 @@ import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.overlay.InputOverlay
@ -72,7 +70,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private lateinit var game: Game
private val emulationViewModel: EmulationViewModel by activityViewModels()
private val driverViewModel: DriverViewModel by activityViewModels()
private var isInFoldableLayout = false
@ -302,21 +299,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isDriverReady.collect {
if (it && !emulationState.isRunning) {
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start()
}
updateScreenLayout()
emulationState.run(emulationActivity!!.isActivityRecreated)
}
}
}
}
}
}
@ -350,6 +332,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
override fun onResume() {
super.onResume()
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start()
}
updateScreenLayout()
emulationState.run(emulationActivity!!.isActivityRecreated)
}
override fun onPause() {
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
emulationState.pause()

View File

@ -5,6 +5,7 @@ package org.yuzu.yuzu_emu.fragments
import android.Manifest
import android.content.ActivityNotFoundException
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
@ -27,6 +28,7 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.BuildConfig
import org.yuzu.yuzu_emu.HomeNavigationDirections
@ -35,7 +37,6 @@ import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
@ -49,7 +50,6 @@ class HomeSettingsFragment : Fragment() {
private lateinit var mainActivity: MainActivity
private val homeViewModel: HomeViewModel by activityViewModels()
private val driverViewModel: DriverViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -107,17 +107,13 @@ class HomeSettingsFragment : Fragment() {
)
add(
HomeSetting(
R.string.gpu_driver_manager,
R.string.install_gpu_driver,
R.string.install_gpu_driver_description,
R.drawable.ic_build,
{
binding.root.findNavController()
.navigate(R.id.action_homeSettingsFragment_to_driverManagerFragment)
},
R.drawable.ic_exit,
{ driverInstaller() },
{ GpuDriverHelper.supportsCustomDriverLoading() },
R.string.custom_driver_not_supported,
R.string.custom_driver_not_supported_description,
driverViewModel.selectedDriverMetadata
R.string.custom_driver_not_supported_description
)
)
add(
@ -296,6 +292,31 @@ class HomeSettingsFragment : Fragment() {
}
}
private fun driverInstaller() {
// Get the driver name for the dialog message.
var driverName = GpuDriverHelper.customDriverName
if (driverName == null) {
driverName = getString(R.string.system_gpu_driver)
}
MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.select_gpu_driver_title))
.setMessage(driverName)
.setNegativeButton(android.R.string.cancel, null)
.setNeutralButton(R.string.select_gpu_driver_default) { _: DialogInterface?, _: Int ->
GpuDriverHelper.installDefaultDriver(requireContext())
Toast.makeText(
requireContext(),
R.string.select_gpu_driver_use_default,
Toast.LENGTH_SHORT
).show()
}
.setPositiveButton(R.string.select_gpu_driver_install) { _: DialogInterface?, _: Int ->
mainActivity.getDriver.launch(arrayOf("application/zip"))
}
.show()
}
private fun shareLog() {
val file = DocumentFile.fromSingleUri(
mainActivity,

View File

@ -10,8 +10,8 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
@ -78,10 +78,6 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
requireActivity().supportFragmentManager,
MessageDialogFragment.TAG
)
else -> {
// Do nothing
}
}
taskViewModel.clear()
}
@ -119,7 +115,7 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
private const val CANCELLABLE = "Cancellable"
fun newInstance(
activity: FragmentActivity,
activity: AppCompatActivity,
titleId: Int,
cancellable: Boolean = false,
task: () -> Any

View File

@ -1,158 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import java.io.BufferedOutputStream
import java.io.File
class DriverViewModel : ViewModel() {
private val _areDriversLoading = MutableStateFlow(false)
val areDriversLoading: StateFlow<Boolean> get() = _areDriversLoading
private val _isDriverReady = MutableStateFlow(true)
val isDriverReady: StateFlow<Boolean> get() = _isDriverReady
private val _isDeletingDrivers = MutableStateFlow(false)
val isDeletingDrivers: StateFlow<Boolean> get() = _isDeletingDrivers
private val _driverList = MutableStateFlow(mutableListOf<Pair<String, GpuDriverMetadata>>())
val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList
var previouslySelectedDriver = 0
var selectedDriver = -1
private val _selectedDriverMetadata =
MutableStateFlow(
GpuDriverHelper.customDriverData.name
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
)
val selectedDriverMetadata: StateFlow<String> get() = _selectedDriverMetadata
private val _newDriverInstalled = MutableStateFlow(false)
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
val driversToDelete = mutableListOf<String>()
val isInteractionAllowed
get() = !areDriversLoading.value && isDriverReady.value && !isDeletingDrivers.value
init {
_areDriversLoading.value = true
viewModelScope.launch {
withContext(Dispatchers.IO) {
val drivers = GpuDriverHelper.getDrivers()
val currentDriverMetadata = GpuDriverHelper.customDriverData
for (i in drivers.indices) {
if (drivers[i].second == currentDriverMetadata) {
setSelectedDriverIndex(i)
break
}
}
// If a user had installed a driver before the manager was implemented, this zips
// the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can
// be indexed and exported as expected.
if (selectedDriver == -1) {
val driverToSave =
File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip")
driverToSave.createNewFile()
FileUtil.zipFromInternalStorage(
File(GpuDriverHelper.driverInstallationPath!!),
GpuDriverHelper.driverInstallationPath!!,
BufferedOutputStream(driverToSave.outputStream())
)
drivers.add(Pair(driverToSave.path, currentDriverMetadata))
setSelectedDriverIndex(drivers.size - 1)
}
_driverList.value = drivers
_areDriversLoading.value = false
}
}
}
fun setSelectedDriverIndex(value: Int) {
if (selectedDriver != -1) {
previouslySelectedDriver = selectedDriver
}
selectedDriver = value
}
fun setNewDriverInstalled(value: Boolean) {
_newDriverInstalled.value = value
}
fun addDriver(driverData: Pair<String, GpuDriverMetadata>) {
val driverIndex = _driverList.value.indexOfFirst { it == driverData }
if (driverIndex == -1) {
setSelectedDriverIndex(_driverList.value.size)
_driverList.value.add(driverData)
_selectedDriverMetadata.value = driverData.second.name
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
} else {
setSelectedDriverIndex(driverIndex)
}
}
fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) {
_driverList.value.remove(driverData)
}
fun onCloseDriverManager() {
_isDeletingDrivers.value = true
viewModelScope.launch {
withContext(Dispatchers.IO) {
driversToDelete.forEach {
val driver = File(it)
if (driver.exists()) {
driver.delete()
}
}
driversToDelete.clear()
_isDeletingDrivers.value = false
}
}
if (GpuDriverHelper.customDriverData == driverList.value[selectedDriver].second) {
return
}
_isDriverReady.value = false
viewModelScope.launch {
withContext(Dispatchers.IO) {
if (selectedDriver == 0) {
GpuDriverHelper.installDefaultDriver()
setDriverReady()
return@withContext
}
val driverToInstall = File(driverList.value[selectedDriver].first)
if (driverToInstall.exists()) {
GpuDriverHelper.installCustomDriver(driverToInstall)
} else {
GpuDriverHelper.installDefaultDriver()
}
setDriverReady()
}
}
}
private fun setDriverReady() {
_isDriverReady.value = true
_selectedDriverMetadata.value = GpuDriverHelper.customDriverData.name
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
}
}

View File

@ -29,10 +29,12 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.navigation.NavigationBarView
import kotlinx.coroutines.CoroutineScope
import java.io.File
import java.io.FilenameFilter
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -41,6 +43,7 @@ import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
@ -340,10 +343,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
applicationContext,
result,
dstPath,
"prod.keys"
) != null
)
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
@ -442,10 +446,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
if (FileUtil.copyUriToInternalStorage(
applicationContext,
result,
dstPath,
"key_retail.bin"
) != null
)
) {
if (NativeLibrary.reloadKeys()) {
Toast.makeText(
@ -464,6 +469,59 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
val getDriver =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
val takeFlags =
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
contentResolver.takePersistableUriPermission(
result,
takeFlags
)
val progressBinding = DialogProgressBarBinding.inflate(layoutInflater)
progressBinding.progressBar.isIndeterminate = true
val installationDialog = MaterialAlertDialogBuilder(this)
.setTitle(R.string.installing_driver)
.setView(progressBinding.root)
.show()
lifecycleScope.launch {
withContext(Dispatchers.IO) {
// Ignore file exceptions when a user selects an invalid zip
try {
GpuDriverHelper.installCustomDriver(applicationContext, result)
} catch (_: IOException) {
}
withContext(Dispatchers.Main) {
installationDialog.dismiss()
val driverName = GpuDriverHelper.customDriverName
if (driverName != null) {
Toast.makeText(
applicationContext,
getString(
R.string.select_gpu_driver_install_success,
driverName
),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
applicationContext,
R.string.select_gpu_driver_error,
Toast.LENGTH_LONG
).show()
}
}
}
}
}
val installGameUpdate = registerForActivityResult(
ActivityResultContracts.OpenMultipleDocuments()
) { documents: List<Uri> ->

View File

@ -7,6 +7,7 @@ import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import java.io.File
import java.util.*
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
class DocumentsTree {
@ -21,7 +22,7 @@ class DocumentsTree {
fun openContentUri(filepath: String, openMode: String?): Int {
val node = resolvePath(filepath) ?: return -1
return FileUtil.openContentUri(node.uri.toString(), openMode)
return FileUtil.openContentUri(YuzuApplication.appContext, node.uri.toString(), openMode)
}
fun getFileSize(filepath: String): Long {
@ -29,7 +30,7 @@ class DocumentsTree {
return if (node == null || node.isDirectory) {
0
} else {
FileUtil.getFileSize(node.uri.toString())
FileUtil.getFileSize(YuzuApplication.appContext, node.uri.toString())
}
}
@ -66,7 +67,7 @@ class DocumentsTree {
* @param parent parent node of this level
*/
private fun structTree(parent: DocumentsNode) {
val documents = FileUtil.listFiles(parent.uri!!)
val documents = FileUtil.listFiles(YuzuApplication.appContext, parent.uri!!)
for (document in documents) {
val node = DocumentsNode(document)
node.parent = parent

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.utils
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.DocumentsContract
@ -10,6 +11,7 @@ import androidx.documentfile.provider.DocumentFile
import kotlinx.coroutines.flow.StateFlow
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.URLDecoder
@ -19,8 +21,6 @@ import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
import org.yuzu.yuzu_emu.model.TaskState
import java.io.BufferedOutputStream
import java.lang.NullPointerException
import java.nio.charset.StandardCharsets
import java.util.zip.ZipOutputStream
object FileUtil {
@ -29,8 +29,6 @@ object FileUtil {
const val APPLICATION_OCTET_STREAM = "application/octet-stream"
const val TEXT_PLAIN = "text/plain"
private val context get() = YuzuApplication.appContext
/**
* Create a file from directory with filename.
* @param context Application context
@ -38,11 +36,11 @@ object FileUtil {
* @param filename file display name.
* @return boolean
*/
fun createFile(directory: String?, filename: String): DocumentFile? {
fun createFile(context: Context?, directory: String?, filename: String): DocumentFile? {
var decodedFilename = filename
try {
val directoryUri = Uri.parse(directory)
val parent = DocumentFile.fromTreeUri(context, directoryUri) ?: return null
val parent = DocumentFile.fromTreeUri(context!!, directoryUri) ?: return null
decodedFilename = URLDecoder.decode(decodedFilename, DECODE_METHOD)
var mimeType = APPLICATION_OCTET_STREAM
if (decodedFilename.endsWith(".txt")) {
@ -58,15 +56,16 @@ object FileUtil {
/**
* Create a directory from directory with filename.
* @param context Application context
* @param directory parent path for directory.
* @param directoryName directory display name.
* @return boolean
*/
fun createDir(directory: String?, directoryName: String?): DocumentFile? {
fun createDir(context: Context?, directory: String?, directoryName: String?): DocumentFile? {
var decodedDirectoryName = directoryName
try {
val directoryUri = Uri.parse(directory)
val parent = DocumentFile.fromTreeUri(context, directoryUri) ?: return null
val parent = DocumentFile.fromTreeUri(context!!, directoryUri) ?: return null
decodedDirectoryName = URLDecoder.decode(decodedDirectoryName, DECODE_METHOD)
val isExist = parent.findFile(decodedDirectoryName)
return isExist ?: parent.createDirectory(decodedDirectoryName)
@ -78,12 +77,13 @@ object FileUtil {
/**
* Open content uri and return file descriptor to JNI.
* @param context Application context
* @param path Native content uri path
* @param openMode will be one of "r", "r", "rw", "wa", "rwa"
* @return file descriptor
*/
@JvmStatic
fun openContentUri(path: String, openMode: String?): Int {
fun openContentUri(context: Context, path: String, openMode: String?): Int {
try {
val uri = Uri.parse(path)
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, openMode!!)
@ -103,10 +103,11 @@ object FileUtil {
/**
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
* This function will be faster than DoucmentFile.listFiles
* @param context Application context
* @param uri Directory uri.
* @return CheapDocument lists.
*/
fun listFiles(uri: Uri): Array<MinimalDocumentFile> {
fun listFiles(context: Context, uri: Uri): Array<MinimalDocumentFile> {
val resolver = context.contentResolver
val columns = arrayOf(
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
@ -144,7 +145,7 @@ object FileUtil {
* @param path Native content uri path
* @return bool
*/
fun exists(path: String?): Boolean {
fun exists(context: Context, path: String?): Boolean {
var c: Cursor? = null
try {
val mUri = Uri.parse(path)
@ -164,7 +165,7 @@ object FileUtil {
* @param path content uri path
* @return bool
*/
fun isDirectory(path: String): Boolean {
fun isDirectory(context: Context, path: String): Boolean {
val resolver = context.contentResolver
val columns = arrayOf(
DocumentsContract.Document.COLUMN_MIME_TYPE
@ -209,10 +210,10 @@ object FileUtil {
return filename
}
fun getFilesName(path: String): Array<String> {
fun getFilesName(context: Context, path: String): Array<String> {
val uri = Uri.parse(path)
val files: MutableList<String> = ArrayList()
for (file in listFiles(uri)) {
for (file in listFiles(context, uri)) {
files.add(file.filename)
}
return files.toTypedArray()
@ -224,7 +225,7 @@ object FileUtil {
* @return long file size
*/
@JvmStatic
fun getFileSize(path: String): Long {
fun getFileSize(context: Context, path: String): Long {
val resolver = context.contentResolver
val columns = arrayOf(
DocumentsContract.Document.COLUMN_SIZE
@ -244,38 +245,44 @@ object FileUtil {
return size
}
/**
* Creates an input stream with a given [Uri] and copies its data to the given path. This will
* overwrite any pre-existing files.
*
* @param sourceUri The [Uri] to copy data from
* @param destinationParentPath Destination directory
* @param destinationFilename Optionally renames the file once copied
*/
fun copyUriToInternalStorage(
sourceUri: Uri,
context: Context,
sourceUri: Uri?,
destinationParentPath: String,
destinationFilename: String = ""
): File? =
destinationFilename: String
): Boolean {
var input: InputStream? = null
var output: FileOutputStream? = null
try {
val fileName =
if (destinationFilename == "") getFilename(sourceUri) else "/$destinationFilename"
val inputStream = context.contentResolver.openInputStream(sourceUri)!!
val destinationFile = File("$destinationParentPath$fileName")
if (destinationFile.exists()) {
destinationFile.delete()
input = context.contentResolver.openInputStream(sourceUri!!)
output = FileOutputStream("$destinationParentPath/$destinationFilename")
val buffer = ByteArray(1024)
var len: Int
while (input!!.read(buffer).also { len = it } != -1) {
output.write(buffer, 0, len)
}
destinationFile.outputStream().use { fos ->
inputStream.use { it.copyTo(fos) }
output.flush()
return true
} catch (e: Exception) {
Log.error("[FileUtil]: Cannot copy file, error: " + e.message)
} finally {
if (input != null) {
try {
input.close()
} catch (e: IOException) {
Log.error("[FileUtil]: Cannot close input file, error: " + e.message)
}
}
if (output != null) {
try {
output.close()
} catch (e: IOException) {
Log.error("[FileUtil]: Cannot close output file, error: " + e.message)
}
}
destinationFile
} catch (e: IOException) {
null
} catch (e: NullPointerException) {
null
}
return false
}
/**
* Extracts the given zip file into the given directory.
@ -361,12 +368,4 @@ object FileUtil {
return fileName.substring(fileName.lastIndexOf(".") + 1)
.lowercase()
}
@Throws(IOException::class)
fun getStringFromFile(file: File): String =
String(file.readBytes(), StandardCharsets.UTF_8)
@Throws(IOException::class)
fun getStringFromInputStream(stream: InputStream): String =
String(stream.readBytes(), StandardCharsets.UTF_8)
}

View File

@ -30,7 +30,7 @@ object GameHelper {
// Ensure keys are loaded so that ROM metadata can be decrypted.
NativeLibrary.reloadKeys()
addGamesRecursive(games, FileUtil.listFiles(gamesUri), 3)
addGamesRecursive(games, FileUtil.listFiles(context, gamesUri), 3)
// Cache list of games found on disk
val serializedGames = mutableSetOf<String>()
@ -58,7 +58,7 @@ object GameHelper {
if (it.isDirectory) {
addGamesRecursive(
games,
FileUtil.listFiles(it.uri),
FileUtil.listFiles(YuzuApplication.appContext, it.uri),
depth - 1
)
} else {

View File

@ -3,33 +3,64 @@
package org.yuzu.yuzu_emu.utils
import android.content.Context
import android.net.Uri
import android.os.Build
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.zip.ZipInputStream
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication
import java.util.zip.ZipException
import java.util.zip.ZipFile
import org.yuzu.yuzu_emu.utils.FileUtil.copyUriToInternalStorage
object GpuDriverHelper {
private const val META_JSON_FILENAME = "meta.json"
private const val DRIVER_INTERNAL_FILENAME = "gpu_driver.zip"
private var fileRedirectionPath: String? = null
var driverInstallationPath: String? = null
private var driverInstallationPath: String? = null
private var hookLibPath: String? = null
val driverStoragePath get() = DirectoryInitialization.userDirectory!! + "/gpu_drivers/"
@Throws(IOException::class)
private fun unzip(zipFilePath: String, destDir: String) {
val dir = File(destDir)
fun initializeDriverParameters() {
// Create output directory if it doesn't exist
if (!dir.exists()) dir.mkdirs()
// Unpack the files.
val inputStream = FileInputStream(zipFilePath)
val zis = ZipInputStream(BufferedInputStream(inputStream))
val buffer = ByteArray(1024)
var ze = zis.nextEntry
while (ze != null) {
val newFile = File(destDir, ze.name)
val canonicalPath = newFile.canonicalPath
if (!canonicalPath.startsWith(destDir + ze.name)) {
throw SecurityException("Zip file attempted path traversal! " + ze.name)
}
newFile.parentFile!!.mkdirs()
val fos = FileOutputStream(newFile)
var len: Int
while (zis.read(buffer).also { len = it } > 0) {
fos.write(buffer, 0, len)
}
fos.close()
zis.closeEntry()
ze = zis.nextEntry
}
zis.closeEntry()
}
fun initializeDriverParameters(context: Context) {
try {
// Initialize the file redirection directory.
fileRedirectionPath = YuzuApplication.appContext
.getExternalFilesDir(null)!!.canonicalPath + "/gpu/vk_file_redirect/"
fileRedirectionPath =
context.getExternalFilesDir(null)!!.canonicalPath + "/gpu/vk_file_redirect/"
// Initialize the driver installation directory.
driverInstallationPath = YuzuApplication.appContext
.filesDir.canonicalPath + "/gpu_driver/"
driverInstallationPath = context.filesDir.canonicalPath + "/gpu_driver/"
} catch (e: IOException) {
throw RuntimeException(e)
}
@ -38,169 +69,68 @@ object GpuDriverHelper {
initializeDirectories()
// Initialize hook libraries directory.
hookLibPath = YuzuApplication.appContext.applicationInfo.nativeLibraryDir + "/"
hookLibPath = context.applicationInfo.nativeLibraryDir + "/"
// Initialize GPU driver.
NativeLibrary.initializeGpuDriver(
hookLibPath,
driverInstallationPath,
customDriverData.libraryName,
customDriverLibraryName,
fileRedirectionPath
)
}
fun getDrivers(): MutableList<Pair<String, GpuDriverMetadata>> {
val driverZips = File(driverStoragePath).listFiles()
val drivers: MutableList<Pair<String, GpuDriverMetadata>> =
driverZips
?.mapNotNull {
val metadata = getMetadataFromZip(it)
metadata.name?.let { _ -> Pair(it.path, metadata) }
}
?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name }
?.distinct()
?.toMutableList() ?: mutableListOf()
// TODO: Get system driver information
drivers.add(0, Pair("", GpuDriverMetadata()))
return drivers
}
fun installDefaultDriver() {
fun installDefaultDriver(context: Context) {
// Removing the installed driver will result in the backend using the default system driver.
File(driverInstallationPath!!).deleteRecursively()
initializeDriverParameters()
val driverInstallationDir = File(driverInstallationPath!!)
deleteRecursive(driverInstallationDir)
initializeDriverParameters(context)
}
fun copyDriverToInternalStorage(driverUri: Uri): Boolean {
// Ensure we have directories.
initializeDirectories()
// Copy the zip file URI to user data
val copiedFile =
FileUtil.copyUriToInternalStorage(driverUri, driverStoragePath) ?: return false
// Validate driver
val metadata = getMetadataFromZip(copiedFile)
if (metadata.name == null) {
copiedFile.delete()
return false
}
if (metadata.minApi > Build.VERSION.SDK_INT) {
copiedFile.delete()
return false
}
return true
}
/**
* Copies driver zip into user data directory so that it can be exported along with
* other user data and also unzipped into the installation directory
*/
fun installCustomDriver(driverUri: Uri): Boolean {
fun installCustomDriver(context: Context, driverPathUri: Uri?) {
// Revert to system default in the event the specified driver is bad.
installDefaultDriver()
installDefaultDriver(context)
// Ensure we have directories.
initializeDirectories()
// Copy the zip file URI to user data
val copiedFile =
FileUtil.copyUriToInternalStorage(driverUri, driverStoragePath) ?: return false
// Validate driver
val metadata = getMetadataFromZip(copiedFile)
if (metadata.name == null) {
copiedFile.delete()
return false
}
if (metadata.minApi > Build.VERSION.SDK_INT) {
copiedFile.delete()
return false
}
// Copy the zip file URI into our private storage.
copyUriToInternalStorage(
context,
driverPathUri,
driverInstallationPath!!,
DRIVER_INTERNAL_FILENAME
)
// Unzip the driver.
try {
FileUtil.unzipToInternalStorage(
BufferedInputStream(copiedFile.inputStream()),
File(driverInstallationPath!!)
)
unzip(driverInstallationPath + DRIVER_INTERNAL_FILENAME, driverInstallationPath!!)
} catch (e: SecurityException) {
return false
return
}
// Initialize the driver parameters.
initializeDriverParameters()
return true
}
/**
* Unzips driver into installation directory
*/
fun installCustomDriver(driver: File): Boolean {
// Revert to system default in the event the specified driver is bad.
installDefaultDriver()
// Ensure we have directories.
initializeDirectories()
// Validate driver
val metadata = getMetadataFromZip(driver)
if (metadata.name == null) {
driver.delete()
return false
}
// Unzip the driver to the private installation directory
try {
FileUtil.unzipToInternalStorage(
BufferedInputStream(driver.inputStream()),
File(driverInstallationPath!!)
)
} catch (e: SecurityException) {
return false
}
// Initialize the driver parameters.
initializeDriverParameters()
return true
}
/**
* Takes in a zip file and reads the meta.json file for presentation to the UI
*
* @param driver Zip containing driver and meta.json file
* @return A non-null [GpuDriverMetadata] instance that may have null members
*/
fun getMetadataFromZip(driver: File): GpuDriverMetadata {
try {
ZipFile(driver).use { zf ->
val entries = zf.entries()
while (entries.hasMoreElements()) {
val entry = entries.nextElement()
if (!entry.isDirectory && entry.name.lowercase().contains(".json")) {
zf.getInputStream(entry).use {
return GpuDriverMetadata(it, entry.size)
}
}
}
}
} catch (_: ZipException) {
}
return GpuDriverMetadata()
initializeDriverParameters(context)
}
external fun supportsCustomDriverLoading(): Boolean
// Parse the custom driver metadata to retrieve the name.
val customDriverData: GpuDriverMetadata
get() = GpuDriverMetadata(File(driverInstallationPath + META_JSON_FILENAME))
val customDriverName: String?
get() {
val metadata = GpuDriverMetadata(driverInstallationPath + META_JSON_FILENAME)
return metadata.name
}
fun initializeDirectories() {
// Parse the custom driver metadata to retrieve the library name.
private val customDriverLibraryName: String?
get() {
// Parse the custom driver metadata to retrieve the library name.
val metadata = GpuDriverMetadata(driverInstallationPath + META_JSON_FILENAME)
return metadata.libraryName
}
private fun initializeDirectories() {
// Ensure the file redirection directory exists.
val fileRedirectionDir = File(fileRedirectionPath!!)
if (!fileRedirectionDir.exists()) {
@ -211,10 +141,14 @@ object GpuDriverHelper {
if (!driverInstallationDir.exists()) {
driverInstallationDir.mkdirs()
}
// Ensure the driver storage directory exists
val driverStorageDirectory = File(driverStoragePath)
if (!driverStorageDirectory.exists()) {
driverStorageDirectory.mkdirs()
}
private fun deleteRecursive(fileOrDirectory: File) {
if (fileOrDirectory.isDirectory) {
for (child in fileOrDirectory.listFiles()!!) {
deleteRecursive(child)
}
}
fileOrDirectory.delete()
}
}

View File

@ -4,116 +4,44 @@
package org.yuzu.yuzu_emu.utils
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import org.json.JSONException
import org.json.JSONObject
import java.io.File
import java.io.InputStream
class GpuDriverMetadata {
/**
* Tries to get driver metadata information from a meta.json [File]
*
* @param metadataFile meta.json file provided with a GPU driver
*/
constructor(metadataFile: File) {
if (metadataFile.length() > MAX_META_SIZE_BYTES) {
return
}
try {
val json = JSONObject(FileUtil.getStringFromFile(metadataFile))
name = json.getString("name")
description = json.getString("description")
author = json.getString("author")
vendor = json.getString("vendor")
version = json.getString("driverVersion")
minApi = json.getInt("minApi")
libraryName = json.getString("libraryName")
} catch (e: JSONException) {
// JSON is malformed, ignore and treat as unsupported metadata.
} catch (e: IOException) {
// File is inaccessible, ignore and treat as unsupported metadata.
}
}
/**
* Tries to get driver metadata information from an input stream that's intended to be
* from a zip file
*
* @param metadataStream ZipEntry input stream
* @param size Size of the file in bytes
*/
constructor(metadataStream: InputStream, size: Long) {
if (size > MAX_META_SIZE_BYTES) {
return
}
try {
val json = JSONObject(FileUtil.getStringFromInputStream(metadataStream))
name = json.getString("name")
description = json.getString("description")
author = json.getString("author")
vendor = json.getString("vendor")
version = json.getString("driverVersion")
minApi = json.getInt("minApi")
libraryName = json.getString("libraryName")
} catch (e: JSONException) {
// JSON is malformed, ignore and treat as unsupported metadata.
} catch (e: IOException) {
// File is inaccessible, ignore and treat as unsupported metadata.
}
}
/**
* Creates an empty metadata instance
*/
constructor()
override fun equals(other: Any?): Boolean {
if (other !is GpuDriverMetadata) {
return false
}
return other.name == name &&
other.description == description &&
other.author == author &&
other.vendor == vendor &&
other.version == version &&
other.minApi == minApi &&
other.libraryName == libraryName
}
override fun hashCode(): Int {
var result = name?.hashCode() ?: 0
result = 31 * result + (description?.hashCode() ?: 0)
result = 31 * result + (author?.hashCode() ?: 0)
result = 31 * result + (vendor?.hashCode() ?: 0)
result = 31 * result + (version?.hashCode() ?: 0)
result = 31 * result + minApi
result = 31 * result + (libraryName?.hashCode() ?: 0)
return result
}
override fun toString(): String =
"""
Name - $name
Description - $description
Author - $author
Vendor - $vendor
Version - $version
Min API - $minApi
Library Name - $libraryName
""".trimMargin().trimIndent()
class GpuDriverMetadata(metadataFilePath: String) {
var name: String? = null
var description: String? = null
var author: String? = null
var vendor: String? = null
var version: String? = null
var driverVersion: String? = null
var minApi = 0
var libraryName: String? = null
init {
try {
val json = JSONObject(getStringFromFile(metadataFilePath))
name = json.getString("name")
description = json.getString("description")
author = json.getString("author")
vendor = json.getString("vendor")
driverVersion = json.getString("driverVersion")
minApi = json.getInt("minApi")
libraryName = json.getString("libraryName")
} catch (e: JSONException) {
// JSON is malformed, ignore and treat as unsupported metadata.
} catch (e: IOException) {
// File is inaccessible, ignore and treat as unsupported metadata.
}
}
companion object {
private const val MAX_META_SIZE_BYTES = 500000
@Throws(IOException::class)
private fun getStringFromFile(filePath: String): String {
val path = Paths.get(filePath)
val bytes = Files.readAllBytes(path)
return String(bytes, StandardCharsets.UTF_8)
}
}
}

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z" />
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
</vector>

View File

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/materialCardViewOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:padding="16dp">
<RadioButton
android:id="@+id/radio_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:clickable="false"
android:checked="false" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_gravity="center_vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="@string/select_gpu_driver_default" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/version"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" />
</LinearLayout>
<Button
android:id="@+id/button_delete"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/delete"
android:tooltipText="@string/delete"
app:icon="@drawable/ic_delete"
app:iconTint="?attr/colorControlNormal" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_licenses"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_drivers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:liftOnScrollTargetViewId="@id/list_drivers">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_drivers"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_back"
app:title="@string/gpu_driver_manager" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_drivers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/button_install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:text="@string/install"
app:icon="@drawable/ic_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -22,9 +22,6 @@
<action
android:id="@+id/action_homeSettingsFragment_to_installableFragment"
app:destination="@id/installableFragment" />
<action
android:id="@+id/action_homeSettingsFragment_to_driverManagerFragment"
app:destination="@id/driverManagerFragment" />
</fragment>
<fragment
@ -98,9 +95,5 @@
android:id="@+id/installableFragment"
android:name="org.yuzu.yuzu_emu.fragments.InstallableFragment"
android:label="InstallableFragment" />
<fragment
android:id="@+id/driverManagerFragment"
android:name="org.yuzu.yuzu_emu.fragments.DriverManagerFragment"
android:label="DriverManagerFragment" />
</navigation>

View File

@ -168,7 +168,9 @@
<string name="select_gpu_driver_title">Möchtest du deinen aktuellen GPU-Treiber ersetzen?</string>
<string name="select_gpu_driver_install">Installieren</string>
<string name="select_gpu_driver_default">Standard</string>
<string name="select_gpu_driver_install_success">%s wurde installiert</string>
<string name="select_gpu_driver_use_default">Standard GPU-Treiber wird verwendet</string>
<string name="select_gpu_driver_error">Ungültiger Treiber ausgewählt, Standard-Treiber wird verwendet!</string>
<string name="system_gpu_driver">System GPU-Treiber</string>
<string name="installing_driver">Treiber wird installiert...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">¿Quiere reemplazar el driver de GPU actual?</string>
<string name="select_gpu_driver_install">Instalar</string>
<string name="select_gpu_driver_default">Predeterminado</string>
<string name="select_gpu_driver_install_success">Instalado %s</string>
<string name="select_gpu_driver_use_default">Usando el driver de GPU por defecto </string>
<string name="select_gpu_driver_error">¡Driver no válido, utilizando el predeterminado del sistema!</string>
<string name="system_gpu_driver">Driver GPU del sistema</string>
<string name="installing_driver">Instalando driver...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Souhaitez vous remplacer votre pilote actuel ?</string>
<string name="select_gpu_driver_install">Installer</string>
<string name="select_gpu_driver_default">Défaut</string>
<string name="select_gpu_driver_install_success">%s Installé</string>
<string name="select_gpu_driver_use_default">Utilisation du pilote de GPU par défaut</string>
<string name="select_gpu_driver_error">Pilote non valide sélectionné, utilisation du paramètre par défaut du système !</string>
<string name="system_gpu_driver">Pilote du GPU du système</string>
<string name="installing_driver">Installation du pilote...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Vuoi sostituire il driver della tua GPU attuale?</string>
<string name="select_gpu_driver_install">Installa</string>
<string name="select_gpu_driver_default">Predefinito</string>
<string name="select_gpu_driver_install_success">Installato%s</string>
<string name="select_gpu_driver_use_default">Utilizza il driver predefinito della GPU.</string>
<string name="select_gpu_driver_error">Il driver selezionato è invalido, è in utilizzo quello predefinito di sistema!</string>
<string name="system_gpu_driver">Driver GPU del sistema</string>
<string name="installing_driver">Installando i driver...</string>

View File

@ -170,7 +170,9 @@
<string name="select_gpu_driver_title">現在のGPUドライバーを置き換えますか</string>
<string name="select_gpu_driver_install">インストール</string>
<string name="select_gpu_driver_default">デフォルト</string>
<string name="select_gpu_driver_install_success">%s をインストールしました</string>
<string name="select_gpu_driver_use_default">デフォルトのGPUドライバーを使用します</string>
<string name="select_gpu_driver_error">選択されたドライバが無効なため、システムのデフォルトを使用します!</string>
<string name="system_gpu_driver">システムのGPUドライバ</string>
<string name="installing_driver">インストール中…</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">현재 사용 중인 GPU 드라이버를 교체하겠습니까?</string>
<string name="select_gpu_driver_install">설치</string>
<string name="select_gpu_driver_default">기본값</string>
<string name="select_gpu_driver_install_success">설치된 %s</string>
<string name="select_gpu_driver_use_default">기본 GPU 드라이버 사용</string>
<string name="select_gpu_driver_error">시스템 기본값을 사용하여 잘못된 드라이버를 선택했습니다!</string>
<string name="system_gpu_driver">시스템 GPU 드라이버</string>
<string name="installing_driver">드라이버 설치 중...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Ønsker du å bytte ut din nåværende GPU-driver?</string>
<string name="select_gpu_driver_install">Installer</string>
<string name="select_gpu_driver_default">Standard</string>
<string name="select_gpu_driver_install_success">Installert %s</string>
<string name="select_gpu_driver_use_default">Bruk av standard GPU-driver</string>
<string name="select_gpu_driver_error">Ugyldig driver valgt, bruker systemstandard!</string>
<string name="system_gpu_driver">Systemets GPU-driver</string>
<string name="installing_driver">Installerer driver...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Chcesz zastąpić obecny sterownik układu graficznego?</string>
<string name="select_gpu_driver_install">Zainstaluj</string>
<string name="select_gpu_driver_default">Domyślne</string>
<string name="select_gpu_driver_install_success">Zainstalowano %s</string>
<string name="select_gpu_driver_use_default">Aktywny domyślny sterownik GPU</string>
<string name="select_gpu_driver_error">Wybrano błędny sterownik, powrót do domyślnego. </string>
<string name="system_gpu_driver">Systemowy sterownik GPU</string>
<string name="installing_driver">Instalowanie sterownika...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Queres substituir o driver do GPU atual? </string>
<string name="select_gpu_driver_install">Instalar</string>
<string name="select_gpu_driver_default">Padrão</string>
<string name="select_gpu_driver_install_success">Instalado%s</string>
<string name="select_gpu_driver_use_default">Usar o driver padrão do GPU</string>
<string name="select_gpu_driver_error">Driver selecionado inválido, a usar o padrão do sistema!</string>
<string name="system_gpu_driver">Driver do GPU padrão</string>
<string name="installing_driver">A instalar o Driver...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Queres substituir o driver do GPU atual? </string>
<string name="select_gpu_driver_install">Instalar</string>
<string name="select_gpu_driver_default">Padrão</string>
<string name="select_gpu_driver_install_success">Instalado%s</string>
<string name="select_gpu_driver_use_default">Usar o driver padrão do GPU</string>
<string name="select_gpu_driver_error">Driver selecionado inválido, a usar o padrão do sistema!</string>
<string name="system_gpu_driver">Driver do GPU padrão</string>
<string name="installing_driver">A instalar o Driver...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Хотите заменить текущий драйвер ГП?</string>
<string name="select_gpu_driver_install">Установить</string>
<string name="select_gpu_driver_default">По умолчанию</string>
<string name="select_gpu_driver_install_success">Установлено %s</string>
<string name="select_gpu_driver_use_default">Используется стандартный драйвер ГП </string>
<string name="select_gpu_driver_error">Выбран неверный драйвер, используется стандартный системный!</string>
<string name="system_gpu_driver">Системный драйвер ГП</string>
<string name="installing_driver">Установка драйвера...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">Хочете замінити поточний драйвер ГП?</string>
<string name="select_gpu_driver_install">Встановити</string>
<string name="select_gpu_driver_default">За замовчуванням</string>
<string name="select_gpu_driver_install_success">Встановлено %s</string>
<string name="select_gpu_driver_use_default">Використовується стандартний драйвер ГП</string>
<string name="select_gpu_driver_error">Обрано неправильний драйвер, використовується стандартний системний!</string>
<string name="system_gpu_driver">Системний драйвер ГП</string>
<string name="installing_driver">Встановлення драйвера...</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">要取代您当前的 GPU 驱动程序吗?</string>
<string name="select_gpu_driver_install">安装</string>
<string name="select_gpu_driver_default">系统默认</string>
<string name="select_gpu_driver_install_success">已安装 %s</string>
<string name="select_gpu_driver_use_default">使用默认 GPU 驱动程序</string>
<string name="select_gpu_driver_error">选择的驱动程序无效,将使用系统默认的驱动程序!</string>
<string name="system_gpu_driver">系统 GPU 驱动程序</string>
<string name="installing_driver">正在安装驱动程序…</string>

View File

@ -171,7 +171,9 @@
<string name="select_gpu_driver_title">要取代您目前的 GPU 驅動程式嗎?</string>
<string name="select_gpu_driver_install">安裝</string>
<string name="select_gpu_driver_default">預設</string>
<string name="select_gpu_driver_install_success">已安裝 %s</string>
<string name="select_gpu_driver_use_default">使用預設 GPU 驅動程式</string>
<string name="select_gpu_driver_error">選取的驅動程式無效,將使用系統預設驅動程式!</string>
<string name="system_gpu_driver">系統 GPU 驅動程式</string>
<string name="installing_driver">正在安裝驅動程式…</string>

View File

@ -13,8 +13,6 @@
<dimen name="menu_width">256dp</dimen>
<dimen name="card_width">165dp</dimen>
<dimen name="icon_inset">24dp</dimen>
<dimen name="spacing_bottom_list_fab">72dp</dimen>
<dimen name="spacing_fab">24dp</dimen>
<dimen name="dialog_margin">20dp</dimen>
<dimen name="elevated_app_bar">3dp</dimen>

View File

@ -72,7 +72,6 @@
<string name="invalid_keys_error">Invalid encryption keys</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">The selected file is incorrect or corrupt. Please redump your keys.</string>
<string name="gpu_driver_manager">GPU Driver Manager</string>
<string name="install_gpu_driver">Install GPU driver</string>
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
<string name="advanced_settings">Advanced settings</string>
@ -235,17 +234,15 @@
<string name="export_failed">Export failed</string>
<string name="import_failed">Import failed</string>
<string name="cancelling">Cancelling</string>
<string name="install">Install</string>
<string name="delete">Delete</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Select GPU driver</string>
<string name="select_gpu_driver_title">Would you like to replace your current GPU driver?</string>
<string name="select_gpu_driver_install">Install</string>
<string name="select_gpu_driver_default">Default</string>
<string name="select_gpu_driver_install_success">Installed %s</string>
<string name="select_gpu_driver_use_default">Using default GPU driver</string>
<string name="select_gpu_driver_error">Invalid driver selected</string>
<string name="driver_already_installed">Driver already installed</string>
<string name="select_gpu_driver_error">Invalid driver selected, using system default!</string>
<string name="system_gpu_driver">System GPU driver</string>
<string name="installing_driver">Installing driver…</string>

View File

@ -3,8 +3,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.2" apply false
id("com.android.library") version "8.1.2" apply false
id("com.android.application") version "8.0.2" apply false
id("com.android.library") version "8.0.2" apply false
id("org.jetbrains.kotlin.android") version "1.8.21" apply false
}

View File

@ -77,7 +77,6 @@ void AudioRenderer::Wait() {
"{}, got {}",
Message::RenderResponse, msg);
}
PostDSPClearCommandBuffer();
}
void AudioRenderer::Send(Direction dir, u32 message) {
@ -97,14 +96,6 @@ void AudioRenderer::SetCommandBuffer(s32 session_id, CpuAddr buffer, u64 size, u
command_buffers[session_id].reset_buffer = reset;
}
void AudioRenderer::PostDSPClearCommandBuffer() noexcept {
for (auto& buffer : command_buffers) {
buffer.buffer = 0;
buffer.size = 0;
buffer.reset_buffer = false;
}
}
u32 AudioRenderer::GetRemainCommandCount(s32 session_id) const noexcept {
return command_buffers[session_id].remaining_command_count;
}

View File

@ -85,8 +85,6 @@ private:
*/
void CreateSinkStreams();
void PostDSPClearCommandBuffer() noexcept;
/// Core system
Core::System& system;
/// The output sink the AudioRenderer will send samples to

View File

@ -204,10 +204,6 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
// paused and we'll desync, so just play silence.
if (system.IsPaused() || system.IsShuttingDown()) {
if (system.IsShuttingDown()) {
{
std::scoped_lock lk{release_mutex};
queued_buffers.store(0);
}
release_cv.notify_one();
}

View File

@ -189,14 +189,6 @@ if(ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak::xbyak)
endif()
if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX))
target_sources(common
PRIVATE
arm64/native_clock.cpp
arm64/native_clock.h
)
endif()
if (MSVC)
target_compile_definitions(common PRIVATE
# The standard library doesn't provide any replacement for codecvt yet

View File

@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/arm64/native_clock.h"
namespace Common::Arm64 {
namespace {
NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) {
return (static_cast<NativeClock::FactorType>(num) << 64) / den;
}
u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) {
return static_cast<u64>((m * factor) >> 64);
}
} // namespace
NativeClock::NativeClock() {
const u64 host_cntfrq = GetHostCNTFRQ();
ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq);
us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq);
ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq);
guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq);
gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq);
}
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)};
}
std::chrono::microseconds NativeClock::GetTimeUS() const {
return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)};
}
std::chrono::milliseconds NativeClock::GetTimeMS() const {
return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)};
}
u64 NativeClock::GetCNTPCT() const {
return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor);
}
u64 NativeClock::GetGPUTick() const {
return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor);
}
u64 NativeClock::GetHostTicksNow() const {
u64 cntvct_el0 = 0;
asm volatile("dsb ish\n\t"
"mrs %[cntvct_el0], cntvct_el0\n\t"
"dsb ish\n\t"
: [cntvct_el0] "=r"(cntvct_el0));
return cntvct_el0;
}
u64 NativeClock::GetHostTicksElapsed() const {
return GetHostTicksNow();
}
bool NativeClock::IsNative() const {
return true;
}
u64 NativeClock::GetHostCNTFRQ() {
u64 cntfrq_el0 = 0;
asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0));
return cntfrq_el0;
}
} // namespace Common::Arm64

View File

@ -1,47 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/wall_clock.h"
namespace Common::Arm64 {
class NativeClock final : public WallClock {
public:
explicit NativeClock();
std::chrono::nanoseconds GetTimeNS() const override;
std::chrono::microseconds GetTimeUS() const override;
std::chrono::milliseconds GetTimeMS() const override;
u64 GetCNTPCT() const override;
u64 GetGPUTick() const override;
u64 GetHostTicksNow() const override;
u64 GetHostTicksElapsed() const override;
bool IsNative() const override;
static u64 GetHostCNTFRQ();
public:
using FactorType = unsigned __int128;
FactorType GetGuestCNTFRQFactor() const {
return guest_cntfrq_factor;
}
private:
FactorType ns_cntfrq_factor;
FactorType us_cntfrq_factor;
FactorType ms_cntfrq_factor;
FactorType guest_cntfrq_factor;
FactorType gputick_cntfrq_factor;
};
} // namespace Common::Arm64

View File

@ -39,12 +39,8 @@
#define Crash() exit(1)
#endif
#define LTO_NOINLINE __attribute__((noinline))
#else // _MSC_VER
#define LTO_NOINLINE
// Locale Cross-Compatibility
#define locale_t _locale_t

View File

@ -211,11 +211,6 @@ struct Elf64_Rela {
Elf64_Sxword r_addend; /* Addend */
};
/* RELR relocation table entry */
using Elf32_Relr = Elf32_Word;
using Elf64_Relr = Elf64_Xword;
/* How to extract and insert information held in the r_info field. */
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
@ -333,9 +328,6 @@ constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
constexpr u32 ElfDtRelrsz = 35; /* Size of RELR relative relocations */
constexpr u32 ElfDtRelr = 36; /* Address of RELR relative relocations */
constexpr u32 ElfDtRelrent = 37; /* Size of one RELR relative relocation */
} // namespace ELF
} // namespace Common

View File

@ -18,12 +18,10 @@
#define LOAD_DIR "load"
#define LOG_DIR "log"
#define NAND_DIR "nand"
#define PLAY_TIME_DIR "play_time"
#define SCREENSHOTS_DIR "screenshots"
#define SDMC_DIR "sdmc"
#define SHADER_DIR "shader"
#define TAS_DIR "tas"
#define ICONS_DIR "icons"
// yuzu-specific files

View File

@ -124,12 +124,10 @@ public:
GenerateYuzuPath(YuzuPath::LoadDir, yuzu_path / LOAD_DIR);
GenerateYuzuPath(YuzuPath::LogDir, yuzu_path / LOG_DIR);
GenerateYuzuPath(YuzuPath::NANDDir, yuzu_path / NAND_DIR);
GenerateYuzuPath(YuzuPath::PlayTimeDir, yuzu_path / PLAY_TIME_DIR);
GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR);
GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR);
GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR);
GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR);
GenerateYuzuPath(YuzuPath::IconsDir, yuzu_path / ICONS_DIR);
}
private:

View File

@ -20,12 +20,10 @@ enum class YuzuPath {
LoadDir, // Where cheat/mod files are stored.
LogDir, // Where log files are stored.
NANDDir, // Where the emulated NAND is stored.
PlayTimeDir, // Where play time data is stored.
ScreenshotsDir, // Where yuzu screenshots are stored.
SDMCDir, // Where the emulated SDMC is stored.
ShaderDir, // Where shaders are stored.
TASDir, // Where TAS scripts are stored.
IconsDir, // Where Icons for Windows shortcuts are stored.
};
/**

View File

@ -15,13 +15,12 @@
#include <condition_variable>
#include <stop_token>
#include <thread>
#include <utility>
namespace Common {
template <typename Condvar, typename Lock, typename Pred>
void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token, Pred&& pred) {
cv.wait(lk, token, std::forward<Pred>(pred));
cv.wait(lk, token, std::move(pred));
}
template <typename Rep, typename Period>
@ -110,7 +109,7 @@ public:
// Insert the callback.
stop_state_callback ret = ++m_next_callback;
m_callbacks.emplace(ret, std::move(f));
m_callbacks.emplace(ret, move(f));
return ret;
}
@ -163,7 +162,7 @@ private:
friend class stop_source;
template <typename Callback>
friend class stop_callback;
stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(std::move(stop_state)) {}
stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {}
private:
shared_ptr<polyfill::stop_state> m_stop_state;
@ -199,7 +198,7 @@ public:
private:
friend class jthread;
explicit stop_source(shared_ptr<polyfill::stop_state> stop_state)
: m_stop_state(std::move(stop_state)) {}
: m_stop_state(move(stop_state)) {}
private:
shared_ptr<polyfill::stop_state> m_stop_state;
@ -219,16 +218,16 @@ public:
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(st.m_stop_state) {
if (m_stop_state) {
m_callback = m_stop_state->insert_callback(std::move(cb));
m_callback = m_stop_state->insert_callback(move(cb));
}
}
template <typename C>
requires constructible_from<Callback, C>
explicit stop_callback(stop_token&& st,
C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
: m_stop_state(std::move(st.m_stop_state)) {
: m_stop_state(move(st.m_stop_state)) {
if (m_stop_state) {
m_callback = m_stop_state->insert_callback(std::move(cb));
m_callback = m_stop_state->insert_callback(move(cb));
}
}
~stop_callback() {
@ -261,7 +260,7 @@ public:
typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>>
explicit jthread(F&& f, Args&&... args)
: m_stop_state(make_shared<polyfill::stop_state>()),
m_thread(make_thread(std::forward<F>(f), std::forward<Args>(args)...)) {}
m_thread(make_thread(move(f), move(args)...)) {}
~jthread() {
if (joinable()) {
@ -318,9 +317,9 @@ private:
template <typename F, typename... Args>
thread make_thread(F&& f, Args&&... args) {
if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) {
return thread(std::forward<F>(f), get_stop_token(), std::forward<Args>(args)...);
return thread(move(f), get_stop_token(), move(args)...);
} else {
return thread(std::forward<F>(f), std::forward<Args>(args)...);
return thread(move(f), move(args)...);
}
}

View File

@ -45,7 +45,6 @@ SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true);
SWITCHABLE(MemoryLayout, true);
SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true);
@ -62,10 +61,6 @@ SWITCHABLE(u32, false);
SWITCHABLE(u8, false);
SWITCHABLE(u8, true);
// Used in UISettings
// TODO see if we can move this to uisettings.cpp
SWITCHABLE(ConfirmStop, true);
#undef SETTING
#undef SWITCHABLE
#endif

View File

@ -67,7 +67,6 @@ SWITCHABLE(CpuAccuracy, true);
SWITCHABLE(FullscreenMode, true);
SWITCHABLE(GpuAccuracy, true);
SWITCHABLE(Language, true);
SWITCHABLE(MemoryLayout, true);
SWITCHABLE(NvdecEmulation, false);
SWITCHABLE(Region, true);
SWITCHABLE(RendererBackend, true);
@ -84,10 +83,6 @@ SWITCHABLE(u32, false);
SWITCHABLE(u8, false);
SWITCHABLE(u8, true);
// Used in UISettings
// TODO see if we can move this to uisettings.h
SWITCHABLE(ConfirmStop, true);
#undef SETTING
#undef SWITCHABLE
#endif

View File

@ -133,8 +133,6 @@ ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
ENUM(FullscreenMode, Borderless, Exclusive);
ENUM(NvdecEmulation, Off, Cpu, Gpu);

View File

@ -11,7 +11,6 @@
#include <mach/mach.h>
#elif defined(_WIN32)
#include <windows.h>
#include "common/string_util.h"
#else
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
@ -83,8 +82,29 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
#ifdef _MSC_VER
// Sets the debugger-visible name of the current thread.
// Uses trick documented in:
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
void SetCurrentThreadName(const char* name) {
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push, 8)
struct THREADNAME_INFO {
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} info;
#pragma pack(pop)
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = std::numeric_limits<DWORD>::max();
info.dwFlags = 0;
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
} __except (EXCEPTION_CONTINUE_EXECUTION) {
}
}
#else // !MSVC_VER, so must be POSIX threads

View File

@ -10,10 +10,6 @@
#include "common/x64/rdtsc.h"
#endif
#if defined(ARCHITECTURE_arm64) && defined(__linux__)
#include "common/arm64/native_clock.h"
#endif
namespace Common {
class StandardWallClock final : public WallClock {
@ -57,7 +53,7 @@ private:
};
std::unique_ptr<WallClock> CreateOptimalClock() {
#if defined(ARCHITECTURE_x86_64)
#ifdef ARCHITECTURE_x86_64
const auto& caps = GetCPUCaps();
if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) {
@ -68,8 +64,6 @@ std::unique_ptr<WallClock> CreateOptimalClock() {
// - Is not more precise than 1 GHz (1ns resolution)
return std::make_unique<StandardWallClock>();
}
#elif defined(ARCHITECTURE_arm64) && defined(__linux__)
return std::make_unique<Arm64::NativeClock>();
#else
return std::make_unique<StandardWallClock>();
#endif

View File

@ -466,18 +466,14 @@ add_library(core STATIC
hle/service/caps/caps_a.h
hle/service/caps/caps_c.cpp
hle/service/caps/caps_c.h
hle/service/caps/caps_manager.cpp
hle/service/caps/caps_manager.h
hle/service/caps/caps_result.h
hle/service/caps/caps_u.cpp
hle/service/caps/caps_u.h
hle/service/caps/caps_sc.cpp
hle/service/caps/caps_sc.h
hle/service/caps/caps_ss.cpp
hle/service/caps/caps_ss.h
hle/service/caps/caps_su.cpp
hle/service/caps/caps_su.h
hle/service/caps/caps_types.h
hle/service/caps/caps_u.cpp
hle/service/caps/caps_u.h
hle/service/erpt/erpt.cpp
hle/service/erpt/erpt.h
hle/service/es/es.cpp

View File

@ -116,8 +116,11 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
}
}
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(dir->GetName(),
std::move(concat));
if (concat.empty()) {
return nullptr;
}
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
}
if (Common::FS::IsDir(path)) {

View File

@ -822,13 +822,11 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
const char p =
True(mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-';
reply += fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n",
mem_info.base_address,
mem_info.base_address + mem_info.size - 1, perm, state, l, i,
d, u, p, mem_info.ipc_count, mem_info.device_count);
reply +=
fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n",
mem_info.base_address, mem_info.base_address + mem_info.size - 1,
perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count);
}
const uintptr_t next_address = mem_info.base_address + mem_info.size;

View File

@ -107,56 +107,62 @@ static u64 romfs_get_hash_table_count(u64 num_entries) {
void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
std::shared_ptr<RomFSBuildDirectoryContext> parent) {
for (auto& child_romfs_file : romfs_dir->GetFiles()) {
const auto name = child_romfs_file->GetName();
const auto child = std::make_shared<RomFSBuildFileContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(name.size());
child->path = parent->path + "/" + name;
std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
if (ext_dir != nullptr && ext_dir->GetFile(name + ".stub") != nullptr) {
continue;
}
const auto entries = romfs_dir->GetEntries();
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
for (const auto& kv : entries) {
if (kv.second == VfsEntryType::Directory) {
const auto child = std::make_shared<RomFSBuildDirectoryContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
child->source = std::move(child_romfs_file);
if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
continue;
}
if (ext_dir != nullptr) {
if (const auto ips = ext_dir->GetFile(name + ".ips")) {
if (auto patched = PatchIPS(child->source, ips)) {
child->source = std::move(patched);
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
if (AddDirectory(parent, child)) {
child_dirs.push_back(child);
}
} else {
const auto child = std::make_shared<RomFSBuildFileContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
if (ext_dir != nullptr && ext_dir->GetFile(kv.first + ".stub") != nullptr) {
continue;
}
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
child->source = romfs_dir->GetFile(kv.first);
if (ext_dir != nullptr) {
if (const auto ips = ext_dir->GetFile(kv.first + ".ips")) {
if (auto patched = PatchIPS(child->source, ips)) {
child->source = std::move(patched);
}
}
}
child->size = child->source->GetSize();
AddFile(parent, child);
}
child->size = child->source->GetSize();
AddFile(parent, child);
}
for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) {
const auto name = child_romfs_dir->GetName();
const auto child = std::make_shared<RomFSBuildDirectoryContext>();
// Set child's path.
child->cur_path_ofs = parent->path_len + 1;
child->path_len = child->cur_path_ofs + static_cast<u32>(name.size());
child->path = parent->path + "/" + name;
if (ext_dir != nullptr && ext_dir->GetFile(name + ".stub") != nullptr) {
continue;
}
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
if (!AddDirectory(parent, child)) {
continue;
}
auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(name) : nullptr;
for (auto& child : child_dirs) {
auto subdir_name = std::string_view(child->path).substr(child->cur_path_ofs);
auto child_romfs_dir = romfs_dir->GetSubdirectory(subdir_name);
auto child_ext_dir = ext_dir != nullptr ? ext_dir->GetSubdirectory(subdir_name) : nullptr;
this->VisitDirectory(child_romfs_dir, child_ext_dir, child);
}
}
@ -287,7 +293,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
cur_entry.name_size = name_size;
out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source));
out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source);
std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
Common::AlignUp(cur_entry.name_size, 4));

View File

@ -377,16 +377,16 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs");
if (romfs_dir != nullptr)
layers.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(romfs_dir)));
layers.push_back(std::make_shared<CachedVfsDirectory>(romfs_dir));
auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext");
if (ext_dir != nullptr)
layers_ext.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(ext_dir)));
layers_ext.push_back(std::make_shared<CachedVfsDirectory>(ext_dir));
if (type == ContentRecordType::HtmlDocument) {
auto manual_dir = FindSubdirectoryCaseless(subdir, "manual_html");
if (manual_dir != nullptr)
layers.emplace_back(std::make_shared<CachedVfsDirectory>(std::move(manual_dir)));
layers.push_back(std::make_shared<CachedVfsDirectory>(manual_dir));
}
}
@ -400,7 +400,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
return;
}
layers.emplace_back(std::move(extracted));
layers.push_back(std::move(extracted));
auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
if (layered == nullptr) {

View File

@ -322,8 +322,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& open_di
return nullptr;
}
auto name = concat.front()->GetName();
return ConcatenatedVfsFile::MakeConcatenatedFile(std::move(name), std::move(concat));
return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
}
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {

View File

@ -133,7 +133,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
out = out->GetSubdirectories().front();
}
return std::make_shared<CachedVfsDirectory>(std::move(out));
return std::make_shared<CachedVfsDirectory>(out);
}
VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
@ -141,7 +141,8 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
return nullptr;
RomFSBuildContext ctx{dir, ext};
return ConcatenatedVfsFile::MakeConcatenatedFile(0, dir->GetName(), ctx.Build());
auto file_map = ctx.Build();
return ConcatenatedVfsFile::MakeConcatenatedFile(0, file_map, dir->GetName());
}
} // namespace FileSys

View File

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/vfs_vector.h"
#include "core/hle/api_version.h"
@ -13,9 +12,6 @@ std::string GetLongDisplayVersion() {
}
VirtualDir SystemVersion() {
LOG_WARNING(Common_Filesystem, "called - Using hardcoded firmware version '{}'",
GetLongDisplayVersion());
VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);

View File

@ -6,13 +6,13 @@
namespace FileSys {
CachedVfsDirectory::CachedVfsDirectory(VirtualDir&& source_dir)
CachedVfsDirectory::CachedVfsDirectory(VirtualDir& source_dir)
: name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) {
for (auto& dir : source_dir->GetSubdirectories()) {
dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(std::move(dir)));
dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(dir));
}
for (auto& file : source_dir->GetFiles()) {
files.emplace(file->GetName(), std::move(file));
files.emplace(file->GetName(), file);
}
}

View File

@ -11,7 +11,7 @@ namespace FileSys {
class CachedVfsDirectory : public ReadOnlyVfsDirectory {
public:
CachedVfsDirectory(VirtualDir&& source_directory);
CachedVfsDirectory(VirtualDir& source_directory);
~CachedVfsDirectory() override;
VirtualFile GetFile(std::string_view file_name) const override;

View File

@ -10,7 +10,7 @@
namespace FileSys {
ConcatenatedVfsFile::ConcatenatedVfsFile(std::string&& name_, ConcatenationMap&& concatenation_map_)
ConcatenatedVfsFile::ConcatenatedVfsFile(ConcatenationMap&& concatenation_map_, std::string&& name_)
: concatenation_map(std::move(concatenation_map_)), name(std::move(name_)) {
DEBUG_ASSERT(this->VerifyContinuity());
}
@ -30,8 +30,8 @@ bool ConcatenatedVfsFile::VerifyContinuity() const {
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
std::vector<VirtualFile>&& files) {
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualFile>& files,
std::string&& name) {
// Fold trivial cases.
if (files.empty()) {
return nullptr;
@ -46,21 +46,20 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
u64 last_offset = 0;
for (auto& file : files) {
const auto size = file->GetSize();
concatenation_map.emplace_back(ConcatenationEntry{
.offset = last_offset,
.file = std::move(file),
.file = file,
});
last_offset += size;
last_offset += file->GetSize();
}
return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
}
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name,
std::multimap<u64, VirtualFile>&& files) {
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
const std::multimap<u64, VirtualFile>& files,
std::string&& name) {
// Fold trivial cases.
if (files.empty()) {
return nullptr;
@ -77,8 +76,6 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::strin
// Iteration of a multimap is ordered, so offset will be strictly non-decreasing.
for (auto& [offset, file] : files) {
const auto size = file->GetSize();
if (offset > last_offset) {
concatenation_map.emplace_back(ConcatenationEntry{
.offset = last_offset,
@ -88,13 +85,13 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::strin
concatenation_map.emplace_back(ConcatenationEntry{
.offset = offset,
.file = std::move(file),
.file = file,
});
last_offset = offset + size;
last_offset = offset + file->GetSize();
}
return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
}
std::string ConcatenatedVfsFile::GetName() const {

View File

@ -24,20 +24,22 @@ private:
};
using ConcatenationMap = std::vector<ConcatenationEntry>;
explicit ConcatenatedVfsFile(std::string&& name,
std::vector<ConcatenationEntry>&& concatenation_map);
explicit ConcatenatedVfsFile(std::vector<ConcatenationEntry>&& concatenation_map,
std::string&& name);
bool VerifyContinuity() const;
public:
~ConcatenatedVfsFile() override;
/// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
static VirtualFile MakeConcatenatedFile(std::string&& name, std::vector<VirtualFile>&& files);
static VirtualFile MakeConcatenatedFile(const std::vector<VirtualFile>& files,
std::string&& name);
/// Convenience function that turns a map of offsets to files into a concatenated file, filling
/// gaps with a given filler byte.
static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name,
std::multimap<u64, VirtualFile>&& files);
static VirtualFile MakeConcatenatedFile(u8 filler_byte,
const std::multimap<u64, VirtualFile>& files,
std::string&& name);
std::string GetName() const override;
std::size_t GetSize() const override;

View File

@ -38,7 +38,7 @@ VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) cons
for (const auto& layer : dirs) {
auto dir = layer->GetDirectoryRelative(path);
if (dir != nullptr) {
out.emplace_back(std::move(dir));
out.push_back(std::move(dir));
}
}
@ -62,11 +62,11 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
std::set<std::string, std::less<>> out_names;
for (const auto& layer : dirs) {
for (auto& file : layer->GetFiles()) {
for (const auto& file : layer->GetFiles()) {
auto file_name = file->GetName();
if (!out_names.contains(file_name)) {
out_names.emplace(std::move(file_name));
out.emplace_back(std::move(file));
out.push_back(file);
}
}
}
@ -86,7 +86,7 @@ std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
std::vector<VirtualDir> out;
out.reserve(names.size());
for (const auto& subdir : names)
out.emplace_back(GetSubdirectory(subdir));
out.push_back(GetSubdirectory(subdir));
return out;
}

View File

@ -106,7 +106,7 @@ static_assert(KernelPageBufferAdditionalSize ==
/// memory.
static KPhysicalAddress TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout,
KVirtualAddress slab_addr) {
slab_addr -= memory_layout.GetSlabRegion().GetAddress();
slab_addr -= GetInteger(memory_layout.GetSlabRegionAddress());
return GetInteger(slab_addr) + Core::DramMemoryMap::SlabHeapBase;
}
@ -196,12 +196,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
auto& kernel = system.Kernel();
// Get the start of the slab region, since that's where we'll be working.
const KMemoryRegion& slab_region = memory_layout.GetSlabRegion();
KVirtualAddress address = slab_region.GetAddress();
// Clear the slab region.
// TODO: implement access to kernel VAs.
// std::memset(device_ptr, 0, slab_region.GetSize());
KVirtualAddress address = memory_layout.GetSlabRegionAddress();
// Initialize slab type array to be in sorted order.
std::array<KSlabType, KSlabType_Count> slab_types;

View File

@ -19,8 +19,4 @@ static inline KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
MainMemoryAddress);
}
static inline size_t GetInitialProcessBinarySize() {
return InitialProcessBinarySizeMax;
}
} // namespace Kernel

View File

@ -36,7 +36,6 @@ enum class KMemoryState : u32 {
FlagCanChangeAttribute = (1 << 24),
FlagCanCodeMemory = (1 << 25),
FlagLinearMapped = (1 << 26),
FlagCanPermissionLock = (1 << 27),
FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical |
@ -51,16 +50,12 @@ enum class KMemoryState : u32 {
FlagLinearMapped,
Free = static_cast<u32>(Svc::MemoryState::Free),
IoMemory = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap |
FlagCanAlignedDeviceMap,
IoRegister =
static_cast<u32>(Svc::MemoryState::Io) | FlagCanDeviceMap | FlagCanAlignedDeviceMap,
Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap |
FlagCanAlignedDeviceMap,
Static = static_cast<u32>(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical,
Code = static_cast<u32>(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess,
CodeData = static_cast<u32>(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess |
FlagCanCodeMemory | FlagCanPermissionLock,
FlagCanCodeMemory,
Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory,
Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted |
FlagLinearMapped,
@ -70,8 +65,7 @@ enum class KMemoryState : u32 {
AliasCode = static_cast<u32>(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess |
FlagCanCodeAlias,
AliasCodeData = static_cast<u32>(Svc::MemoryState::AliasCodeData) | FlagsData |
FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory |
FlagCanPermissionLock,
FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory,
Ipc = static_cast<u32>(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap |
FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
@ -79,7 +73,7 @@ enum class KMemoryState : u32 {
Stack = static_cast<u32>(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap |
FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped,
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagLinearMapped,
Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
@ -100,7 +94,7 @@ enum class KMemoryState : u32 {
NonDeviceIpc =
static_cast<u32>(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc,
Kernel = static_cast<u32>(Svc::MemoryState::Kernel),
Kernel = static_cast<u32>(Svc::MemoryState::Kernel) | FlagMapped,
GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
FlagReferenceCounted | FlagCanDebug | FlagLinearMapped,
@ -111,36 +105,34 @@ enum class KMemoryState : u32 {
Insecure = static_cast<u32>(Svc::MemoryState::Insecure) | FlagMapped | FlagReferenceCounted |
FlagLinearMapped | FlagCanChangeAttribute | FlagCanDeviceMap |
FlagCanAlignedDeviceMap | FlagCanQueryPhysical | FlagCanUseNonSecureIpc |
FlagCanUseNonDeviceIpc,
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000);
static_assert(static_cast<u32>(KMemoryState::IoMemory) == 0x00182001);
static_assert(static_cast<u32>(KMemoryState::IoRegister) == 0x00180001);
static_assert(static_cast<u32>(KMemoryState::Io) == 0x00182001);
static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002);
static_assert(static_cast<u32>(KMemoryState::Code) == 0x04DC7E03);
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x0FFEBD04);
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x07FEBD04);
static_assert(static_cast<u32>(KMemoryState::Normal) == 0x077EBD05);
static_assert(static_cast<u32>(KMemoryState::Shared) == 0x04402006);
static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x04DD7E08);
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09);
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x07FFBD09);
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400200C);
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D);
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);
static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x044C2812);
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00000013);
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x04402214);
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x04402015);
static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x055C3817);
static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x05583817);
enum class KMemoryPermission : u8 {
None = 0,
@ -190,9 +182,8 @@ enum class KMemoryAttribute : u8 {
IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked),
DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared),
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
PermissionLocked = static_cast<u8>(Svc::MemoryAttribute::PermissionLocked),
SetMask = Uncached | PermissionLocked,
SetMask = Uncached,
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
@ -270,10 +261,6 @@ struct KMemoryInfo {
return m_state;
}
constexpr Svc::MemoryState GetSvcState() const {
return static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask);
}
constexpr KMemoryPermission GetPermission() const {
return m_permission;
}
@ -339,10 +326,6 @@ public:
return this->GetEndAddress() - 1;
}
constexpr KMemoryState GetState() const {
return m_memory_state;
}
constexpr u16 GetIpcLockCount() const {
return m_ipc_lock_count;
}
@ -460,13 +443,6 @@ public:
}
}
constexpr void UpdateAttribute(KMemoryAttribute mask, KMemoryAttribute attr) {
ASSERT(False(mask & KMemoryAttribute::IpcLocked));
ASSERT(False(mask & KMemoryAttribute::DeviceShared));
m_attribute = (m_attribute & ~mask) | attr;
}
constexpr void Split(KMemoryBlock* block, KProcessAddress addr) {
ASSERT(this->GetAddress() < addr);
ASSERT(this->Contains(addr));

View File

@ -160,8 +160,8 @@ void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator,
}
// Update block state.
it->Update(state, perm, attr, it->GetAddress() == address,
static_cast<u8>(set_disable_attr), static_cast<u8>(clear_disable_attr));
it->Update(state, perm, attr, cur_address == address, static_cast<u8>(set_disable_attr),
static_cast<u8>(clear_disable_attr));
cur_address += cur_info.GetSize();
remaining_pages -= cur_info.GetNumPages();
}
@ -175,9 +175,7 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo
KProcessAddress address, size_t num_pages,
KMemoryState test_state, KMemoryPermission test_perm,
KMemoryAttribute test_attr, KMemoryState state,
KMemoryPermission perm, KMemoryAttribute attr,
KMemoryBlockDisableMergeAttribute set_disable_attr,
KMemoryBlockDisableMergeAttribute clear_disable_attr) {
KMemoryPermission perm, KMemoryAttribute attr) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
@ -216,8 +214,7 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo
}
// Update block state.
it->Update(state, perm, attr, false, static_cast<u8>(set_disable_attr),
static_cast<u8>(clear_disable_attr));
it->Update(state, perm, attr, false, 0, 0);
cur_address += cur_info.GetSize();
remaining_pages -= cur_info.GetNumPages();
} else {
@ -287,65 +284,6 @@ void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocat
this->CoalesceForUpdate(allocator, address, num_pages);
}
void KMemoryBlockManager::UpdateAttribute(KMemoryBlockManagerUpdateAllocator* allocator,
KProcessAddress address, size_t num_pages,
KMemoryAttribute mask, KMemoryAttribute attr) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
ASSERT(Common::IsAligned(GetInteger(address), PageSize));
KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
while (remaining_pages > 0) {
const size_t remaining_size = remaining_pages * PageSize;
KMemoryInfo cur_info = it->GetMemoryInfo();
if ((it->GetAttribute() & mask) != attr) {
// If we need to, create a new block before and insert it.
if (cur_info.GetAddress() != GetInteger(cur_address)) {
KMemoryBlock* new_block = allocator->Allocate();
it->Split(new_block, cur_address);
it = m_memory_block_tree.insert(*new_block);
it++;
cur_info = it->GetMemoryInfo();
cur_address = cur_info.GetAddress();
}
// If we need to, create a new block after and insert it.
if (cur_info.GetSize() > remaining_size) {
KMemoryBlock* new_block = allocator->Allocate();
it->Split(new_block, cur_address + remaining_size);
it = m_memory_block_tree.insert(*new_block);
cur_info = it->GetMemoryInfo();
}
// Update block state.
it->UpdateAttribute(mask, attr);
cur_address += cur_info.GetSize();
remaining_pages -= cur_info.GetNumPages();
} else {
// If we already have the right attributes, just advance.
if (cur_address + remaining_size < cur_info.GetEndAddress()) {
remaining_pages = 0;
cur_address += remaining_size;
} else {
remaining_pages =
(cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize;
cur_address = cur_info.GetEndAddress();
}
}
it++;
}
this->CoalesceForUpdate(allocator, address, num_pages);
}
// Debug.
bool KMemoryBlockManager::CheckState() const {
// Loop over every block, ensuring that we are sorted and coalesced.

View File

@ -115,11 +115,7 @@ public:
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm,
KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr,
KMemoryBlockDisableMergeAttribute clear_disable_attr);
void UpdateAttribute(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages, KMemoryAttribute mask, KMemoryAttribute attr);
KMemoryAttribute attr);
iterator FindIterator(KProcessAddress address) const {
return m_memory_block_tree.find(KMemoryBlock(

View File

@ -137,9 +137,11 @@ public:
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
}
const KMemoryRegion& GetSlabRegion() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab));
KVirtualAddress GetSlabRegionAddress() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
.GetAddress();
}
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
}

View File

@ -119,8 +119,7 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage
// Free each region to its corresponding heap.
size_t reserved_sizes[MaxManagerCount] = {};
const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
const size_t ini_size = GetInitialProcessBinarySize();
const KPhysicalAddress ini_end = ini_start + ini_size;
const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax;
const KPhysicalAddress ini_last = ini_end - 1;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
@ -138,13 +137,13 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage
}
// Open/reserve the ini memory.
manager.OpenFirst(ini_start, ini_size / PageSize);
reserved_sizes[it.GetAttributes()] += ini_size;
manager.OpenFirst(ini_start, InitialProcessBinarySizeMax / PageSize);
reserved_sizes[it.GetAttributes()] += InitialProcessBinarySizeMax;
// Free memory after the ini to the heap.
if (ini_last != cur_last) {
ASSERT(cur_end != 0);
manager.Free(ini_end, (cur_end - ini_end) / PageSize);
manager.Free(ini_end, cur_end - ini_end);
}
} else {
// Ensure there's no partial overlap with the ini image.

View File

@ -190,15 +190,9 @@ static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
constexpr inline auto KMemoryRegionType_DramKernelSecureAppletMemory =
KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(
KMemoryRegionAttr_LinearMapped);
constexpr inline const auto KMemoryRegionType_DramKernelSecureUnknown =
KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 1).SetAttribute(
KMemoryRegionAttr_LinearMapped);
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() ==
(0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_LinearMapped));
static_assert(KMemoryRegionType_DramKernelSecureUnknown.GetValue() ==
(0x28E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_LinearMapped));
constexpr inline auto KMemoryRegionType_DramReservedEarly =
KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
@ -223,18 +217,16 @@ constexpr inline auto KMemoryRegionType_DramPoolPartition =
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
(0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
// UNUSED: .Derive(4, 1);
// UNUSED: .Derive(4, 2);
constexpr inline const auto KMemoryRegionType_DramPoolManagement =
KMemoryRegionType_DramPoolPartition.Derive(4, 0).SetAttribute(
constexpr inline auto KMemoryRegionType_DramPoolManagement =
KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
KMemoryRegionAttr_CarveoutProtected);
constexpr inline const auto KMemoryRegionType_DramUserPool =
KMemoryRegionType_DramPoolPartition.Derive(4, 3);
constexpr inline auto KMemoryRegionType_DramUserPool =
KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
(0xE6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
(0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_CarveoutProtected));
static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
(0x266 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
(0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
constexpr inline auto KMemoryRegionType_DramApplicationPool =
KMemoryRegionType_DramUserPool.Derive(4, 0);
@ -245,63 +237,60 @@ constexpr inline auto KMemoryRegionType_DramSystemNonSecurePool =
constexpr inline auto KMemoryRegionType_DramSystemPool =
KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
(0xE66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
(0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramAppletPool.GetValue() ==
(0x1666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
(0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() ==
(0x1A66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
(0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
(0x2666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
(0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_CarveoutProtected));
constexpr inline auto KMemoryRegionType_VirtualDramHeapBase =
KMemoryRegionType_Dram.DeriveSparse(1, 4, 0);
KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
constexpr inline auto KMemoryRegionType_VirtualDramKernelPtHeap =
KMemoryRegionType_Dram.DeriveSparse(1, 4, 1);
KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
constexpr inline auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
KMemoryRegionType_Dram.DeriveSparse(1, 4, 2);
KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
// UNUSED: .Derive(4, 2);
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug =
KMemoryRegionType_Dram.Advance(2).Derive(4, 0);
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory =
KMemoryRegionType_Dram.Advance(2).Derive(4, 1);
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureUnknown =
KMemoryRegionType_Dram.Advance(2).Derive(4, 3);
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x32));
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x52));
static_assert(KMemoryRegionType_VirtualDramKernelSecureUnknown.GetValue() == (0x92));
// UNUSED: .DeriveSparse(2, 2, 0);
constexpr inline auto KMemoryRegionType_VirtualDramUnknownDebug =
KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
// UNUSED: .Derive(4, 3);
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt =
KMemoryRegionType_VirtualDramHeapBase.Derive(4, 0);
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement =
KMemoryRegionType_VirtualDramHeapBase.Derive(4, 1);
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool =
KMemoryRegionType_VirtualDramHeapBase.Derive(4, 2);
static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x31A);
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x51A);
static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x61A);
constexpr inline auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory =
KMemoryRegionType_Dram.DeriveSparse(3, 1, 0);
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62));
constexpr inline auto KMemoryRegionType_VirtualDramKernelInitPt =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
constexpr inline auto KMemoryRegionType_VirtualDramPoolManagement =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
constexpr inline auto KMemoryRegionType_VirtualDramUserPool =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
// NOTE: For unknown reason, the pools are derived out-of-order here.
// It's worth eventually trying to understand why Nintendo made this choice.
// UNUSED: .Derive(6, 0);
// UNUSED: .Derive(6, 1);
constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool =
KMemoryRegionType_VirtualDramUserPool.Derive(4, 0);
constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool =
KMemoryRegionType_VirtualDramUserPool.Derive(4, 1);
constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
KMemoryRegionType_VirtualDramUserPool.Derive(4, 2);
constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool =
KMemoryRegionType_VirtualDramUserPool.Derive(4, 3);
static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x361A);
static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x561A);
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x661A);
static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x961A);
constexpr inline auto KMemoryRegionType_VirtualDramAppletPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
constexpr inline auto KMemoryRegionType_VirtualDramApplicationPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
constexpr inline auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
constexpr inline auto KMemoryRegionType_VirtualDramSystemPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
constexpr inline auto KMemoryRegionType_ArchDeviceBase =
KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
@ -365,14 +354,12 @@ constexpr inline auto KMemoryRegionType_KernelTemp =
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelPtHeap;
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
} else if (KMemoryRegionType_DramKernelSecureUnknown.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelSecureUnknown;
} else if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
return KMemoryRegionType_VirtualDramUnknownDebug;
} else {

View File

@ -183,17 +183,12 @@ private:
class KScopedPageGroup {
public:
explicit KScopedPageGroup(const KPageGroup* gp, bool not_first = true) : m_pg(gp) {
explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) {
if (m_pg) {
if (not_first) {
m_pg->Open();
} else {
m_pg->OpenFirst();
}
m_pg->Open();
}
}
explicit KScopedPageGroup(const KPageGroup& gp, bool not_first = true)
: KScopedPageGroup(std::addressof(gp), not_first) {}
explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {}
~KScopedPageGroup() {
if (m_pg) {
m_pg->Close();

View File

@ -505,7 +505,7 @@ Result KPageTable::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress
R_TRY(this->CheckMemoryStateContiguous(
std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias,
KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::All & ~KMemoryAttribute::PermissionLocked, KMemoryAttribute::None));
KMemoryAttribute::All, KMemoryAttribute::None));
// Determine whether any pages being unmapped are code.
bool any_code_pages = false;
@ -1724,43 +1724,29 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
PageSize;
// While we have pages to map, map them.
{
// Create a page group for the current mapping range.
KPageGroup cur_pg(m_kernel, m_block_info_manager);
{
ON_RESULT_FAILURE_2 {
cur_pg.OpenFirst();
cur_pg.Close();
};
while (map_pages > 0) {
// Check if we're at the end of the physical block.
if (pg_pages == 0) {
// Ensure there are more pages to map.
ASSERT(pg_it != pg.end());
size_t remain_pages = map_pages;
while (remain_pages > 0) {
// Check if we're at the end of the physical block.
if (pg_pages == 0) {
// Ensure there are more pages to map.
ASSERT(pg_it != pg.end());
// Advance our physical block.
++pg_it;
pg_phys_addr = pg_it->GetAddress();
pg_pages = pg_it->GetNumPages();
}
// Add whatever we can to the current block.
const size_t cur_pages = std::min(pg_pages, remain_pages);
R_TRY(cur_pg.AddBlock(pg_phys_addr +
((pg_pages - cur_pages) * PageSize),
cur_pages));
// Advance.
remain_pages -= cur_pages;
pg_pages -= cur_pages;
}
// Advance our physical block.
++pg_it;
pg_phys_addr = pg_it->GetAddress();
pg_pages = pg_it->GetNumPages();
}
// Map the pages.
R_TRY(this->Operate(cur_address, map_pages, cur_pg,
OperationType::MapFirstGroup));
// Map whatever we can.
const size_t cur_pages = std::min(pg_pages, map_pages);
R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite,
OperationType::MapFirst, pg_phys_addr));
// Advance.
cur_address += cur_pages * PageSize;
map_pages -= cur_pages;
pg_phys_addr += cur_pages * PageSize;
pg_pages -= cur_pages;
}
}
@ -1784,11 +1770,7 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
m_memory_block_manager.UpdateIfMatch(
std::addressof(allocator), address, size / PageSize, KMemoryState::Free,
KMemoryPermission::None, KMemoryAttribute::None, KMemoryState::Normal,
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
address == this->GetAliasRegionStart()
? KMemoryBlockDisableMergeAttribute::Normal
: KMemoryBlockDisableMergeAttribute::None,
KMemoryBlockDisableMergeAttribute::None);
KMemoryPermission::UserReadWrite, KMemoryAttribute::None);
R_SUCCEED();
}
@ -1886,13 +1868,6 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
// Iterate over the memory, unmapping as we go.
auto it = m_memory_block_manager.FindIterator(cur_address);
const auto clear_merge_attr =
(it->GetState() == KMemoryState::Normal &&
it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address)
? KMemoryBlockDisableMergeAttribute::Normal
: KMemoryBlockDisableMergeAttribute::None;
while (true) {
// Check that the iterator is valid.
ASSERT(it != m_memory_block_manager.end());
@ -1930,7 +1905,7 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize,
KMemoryState::Free, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
clear_merge_attr);
KMemoryBlockDisableMergeAttribute::None);
// We succeeded.
R_SUCCEED();
@ -2404,7 +2379,8 @@ Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
KScopedPageTableUpdater updater(this);
// Perform mapping operation.
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
DisableMergeAttribute::DisableHead};
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
// Update the blocks.
@ -2446,7 +2422,8 @@ Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMem
KScopedPageTableUpdater updater(this);
// Perform mapping operation.
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
DisableMergeAttribute::DisableHead};
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
// Update the blocks.
@ -2675,18 +2652,11 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas
size_t num_allocator_blocks;
constexpr auto AttributeTestMask =
~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared);
const KMemoryState state_test_mask =
static_cast<KMemoryState>(((mask & static_cast<u32>(KMemoryAttribute::Uncached))
? static_cast<u32>(KMemoryState::FlagCanChangeAttribute)
: 0) |
((mask & static_cast<u32>(KMemoryAttribute::PermissionLocked))
? static_cast<u32>(KMemoryState::FlagCanPermissionLock)
: 0));
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
std::addressof(old_attr), std::addressof(num_allocator_blocks),
addr, size, state_test_mask, state_test_mask,
KMemoryPermission::None, KMemoryPermission::None,
AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
R_TRY(this->CheckMemoryState(
std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr),
std::addressof(num_allocator_blocks), addr, size, KMemoryState::FlagCanChangeAttribute,
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
// Create an update allocator.
Result allocator_result{ResultSuccess};
@ -2694,17 +2664,18 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
// If we need to, perform a change attribute operation.
if (True(KMemoryAttribute::Uncached & static_cast<KMemoryAttribute>(mask))) {
// Perform operation.
R_TRY(this->Operate(addr, num_pages, old_perm,
OperationType::ChangePermissionsAndRefreshAndFlush, 0));
}
// Determine the new attribute.
const KMemoryAttribute new_attr =
static_cast<KMemoryAttribute>(((old_attr & static_cast<KMemoryAttribute>(~mask)) |
static_cast<KMemoryAttribute>(attr & mask)));
// Perform operation.
this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh);
// Update the blocks.
m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages,
static_cast<KMemoryAttribute>(mask),
static_cast<KMemoryAttribute>(attr));
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm,
new_attr, KMemoryBlockDisableMergeAttribute::None,
KMemoryBlockDisableMergeAttribute::None);
R_SUCCEED();
}
@ -2892,8 +2863,7 @@ Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress
&KMemoryBlock::ShareToDevice, KMemoryPermission::None);
// Set whether the locked memory was io.
*out_is_io =
static_cast<Svc::MemoryState>(old_state & KMemoryState::Mask) == Svc::MemoryState::Io;
*out_is_io = old_state == KMemoryState::Io;
R_SUCCEED();
}
@ -2979,23 +2949,6 @@ Result KPageTable::UnlockForIpcUserBuffer(KProcessAddress address, size_t size)
KMemoryAttribute::Locked, nullptr));
}
Result KPageTable::LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
KMemoryPermission perm) {
R_RETURN(this->LockMemoryAndOpen(out, nullptr, address, size, KMemoryState::FlagCanTransfer,
KMemoryState::FlagCanTransfer, KMemoryPermission::All,
KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
KMemoryAttribute::None, perm, KMemoryAttribute::Locked));
}
Result KPageTable::UnlockForTransferMemory(KProcessAddress address, size_t size,
const KPageGroup& pg) {
R_RETURN(this->UnlockMemory(address, size, KMemoryState::FlagCanTransfer,
KMemoryState::FlagCanTransfer, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::All,
KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
KMemoryAttribute::Locked, std::addressof(pg)));
}
Result KPageTable::LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size) {
R_RETURN(this->LockMemoryAndOpen(
out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
@ -3051,10 +3004,9 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGr
ASSERT(num_pages == page_group.GetNumPages());
switch (operation) {
case OperationType::MapGroup:
case OperationType::MapFirstGroup: {
case OperationType::MapGroup: {
// We want to maintain a new reference to every page in the group.
KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
KScopedPageGroup spg(page_group);
for (const auto& node : page_group) {
const size_t size{node.GetNumPages() * PageSize};
@ -3096,6 +3048,7 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
break;
}
case OperationType::MapFirst:
case OperationType::Map: {
ASSERT(map_addr);
ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize));
@ -3103,7 +3056,11 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
// Open references to pages, if we should.
if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) {
m_kernel.MemoryManager().Open(map_addr, num_pages);
if (operation == OperationType::MapFirst) {
m_kernel.MemoryManager().OpenFirst(map_addr, num_pages);
} else {
m_kernel.MemoryManager().Open(map_addr, num_pages);
}
}
break;
}
@ -3113,7 +3070,6 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
}
case OperationType::ChangePermissions:
case OperationType::ChangePermissionsAndRefresh:
case OperationType::ChangePermissionsAndRefreshAndFlush:
break;
default:
ASSERT(false);
@ -3133,79 +3089,79 @@ void KPageTable::FinalizeUpdate(PageLinkedList* page_list) {
}
}
KProcessAddress KPageTable::GetRegionAddress(Svc::MemoryState state) const {
KProcessAddress KPageTable::GetRegionAddress(KMemoryState state) const {
switch (state) {
case Svc::MemoryState::Free:
case Svc::MemoryState::Kernel:
case KMemoryState::Free:
case KMemoryState::Kernel:
return m_address_space_start;
case Svc::MemoryState::Normal:
case KMemoryState::Normal:
return m_heap_region_start;
case Svc::MemoryState::Ipc:
case Svc::MemoryState::NonSecureIpc:
case Svc::MemoryState::NonDeviceIpc:
case KMemoryState::Ipc:
case KMemoryState::NonSecureIpc:
case KMemoryState::NonDeviceIpc:
return m_alias_region_start;
case Svc::MemoryState::Stack:
case KMemoryState::Stack:
return m_stack_region_start;
case Svc::MemoryState::Static:
case Svc::MemoryState::ThreadLocal:
case KMemoryState::Static:
case KMemoryState::ThreadLocal:
return m_kernel_map_region_start;
case Svc::MemoryState::Io:
case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Transfered:
case Svc::MemoryState::SharedTransfered:
case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut:
case Svc::MemoryState::Coverage:
case Svc::MemoryState::Insecure:
case KMemoryState::Io:
case KMemoryState::Shared:
case KMemoryState::AliasCode:
case KMemoryState::AliasCodeData:
case KMemoryState::Transfered:
case KMemoryState::SharedTransfered:
case KMemoryState::SharedCode:
case KMemoryState::GeneratedCode:
case KMemoryState::CodeOut:
case KMemoryState::Coverage:
case KMemoryState::Insecure:
return m_alias_code_region_start;
case Svc::MemoryState::Code:
case Svc::MemoryState::CodeData:
case KMemoryState::Code:
case KMemoryState::CodeData:
return m_code_region_start;
default:
UNREACHABLE();
}
}
size_t KPageTable::GetRegionSize(Svc::MemoryState state) const {
size_t KPageTable::GetRegionSize(KMemoryState state) const {
switch (state) {
case Svc::MemoryState::Free:
case Svc::MemoryState::Kernel:
case KMemoryState::Free:
case KMemoryState::Kernel:
return m_address_space_end - m_address_space_start;
case Svc::MemoryState::Normal:
case KMemoryState::Normal:
return m_heap_region_end - m_heap_region_start;
case Svc::MemoryState::Ipc:
case Svc::MemoryState::NonSecureIpc:
case Svc::MemoryState::NonDeviceIpc:
case KMemoryState::Ipc:
case KMemoryState::NonSecureIpc:
case KMemoryState::NonDeviceIpc:
return m_alias_region_end - m_alias_region_start;
case Svc::MemoryState::Stack:
case KMemoryState::Stack:
return m_stack_region_end - m_stack_region_start;
case Svc::MemoryState::Static:
case Svc::MemoryState::ThreadLocal:
case KMemoryState::Static:
case KMemoryState::ThreadLocal:
return m_kernel_map_region_end - m_kernel_map_region_start;
case Svc::MemoryState::Io:
case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Transfered:
case Svc::MemoryState::SharedTransfered:
case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut:
case Svc::MemoryState::Coverage:
case Svc::MemoryState::Insecure:
case KMemoryState::Io:
case KMemoryState::Shared:
case KMemoryState::AliasCode:
case KMemoryState::AliasCodeData:
case KMemoryState::Transfered:
case KMemoryState::SharedTransfered:
case KMemoryState::SharedCode:
case KMemoryState::GeneratedCode:
case KMemoryState::CodeOut:
case KMemoryState::Coverage:
case KMemoryState::Insecure:
return m_alias_code_region_end - m_alias_code_region_start;
case Svc::MemoryState::Code:
case Svc::MemoryState::CodeData:
case KMemoryState::Code:
case KMemoryState::CodeData:
return m_code_region_end - m_code_region_start;
default:
UNREACHABLE();
}
}
bool KPageTable::CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const {
bool KPageTable::CanContain(KProcessAddress addr, size_t size, KMemoryState state) const {
const KProcessAddress end = addr + size;
const KProcessAddress last = end - 1;
@ -3219,32 +3175,32 @@ bool KPageTable::CanContain(KProcessAddress addr, size_t size, Svc::MemoryState
const bool is_in_alias = !(end <= m_alias_region_start || m_alias_region_end <= addr ||
m_alias_region_start == m_alias_region_end);
switch (state) {
case Svc::MemoryState::Free:
case Svc::MemoryState::Kernel:
case KMemoryState::Free:
case KMemoryState::Kernel:
return is_in_region;
case Svc::MemoryState::Io:
case Svc::MemoryState::Static:
case Svc::MemoryState::Code:
case Svc::MemoryState::CodeData:
case Svc::MemoryState::Shared:
case Svc::MemoryState::AliasCode:
case Svc::MemoryState::AliasCodeData:
case Svc::MemoryState::Stack:
case Svc::MemoryState::ThreadLocal:
case Svc::MemoryState::Transfered:
case Svc::MemoryState::SharedTransfered:
case Svc::MemoryState::SharedCode:
case Svc::MemoryState::GeneratedCode:
case Svc::MemoryState::CodeOut:
case Svc::MemoryState::Coverage:
case Svc::MemoryState::Insecure:
case KMemoryState::Io:
case KMemoryState::Static:
case KMemoryState::Code:
case KMemoryState::CodeData:
case KMemoryState::Shared:
case KMemoryState::AliasCode:
case KMemoryState::AliasCodeData:
case KMemoryState::Stack:
case KMemoryState::ThreadLocal:
case KMemoryState::Transfered:
case KMemoryState::SharedTransfered:
case KMemoryState::SharedCode:
case KMemoryState::GeneratedCode:
case KMemoryState::CodeOut:
case KMemoryState::Coverage:
case KMemoryState::Insecure:
return is_in_region && !is_in_heap && !is_in_alias;
case Svc::MemoryState::Normal:
case KMemoryState::Normal:
ASSERT(is_in_heap);
return is_in_region && !is_in_alias;
case Svc::MemoryState::Ipc:
case Svc::MemoryState::NonSecureIpc:
case Svc::MemoryState::NonDeviceIpc:
case KMemoryState::Ipc:
case KMemoryState::NonSecureIpc:
case KMemoryState::NonDeviceIpc:
ASSERT(is_in_alias);
return is_in_region && !is_in_heap;
default:
@ -3308,16 +3264,21 @@ Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, KProces
Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
KMemoryBlockManager::const_iterator it,
KProcessAddress last_addr, KMemoryState state_mask,
KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
ASSERT(this->IsLockedByCurrentThread());
// Get information about the first block.
const KProcessAddress last_addr = addr + size - 1;
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
KMemoryInfo info = it->GetMemoryInfo();
// If the start address isn't aligned, we need a block.
const size_t blocks_for_start_align =
(Common::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
// Validate all blocks in the range have correct state.
const KMemoryState first_state = info.m_state;
const KMemoryPermission first_perm = info.m_permission;
@ -3343,6 +3304,10 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission*
info = it->GetMemoryInfo();
}
// If the end address isn't aligned, we need a block.
const size_t blocks_for_end_align =
(Common::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
// Write output state.
if (out_state != nullptr) {
*out_state = first_state;
@ -3353,39 +3318,9 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission*
if (out_attr != nullptr) {
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
}
// If the end address isn't aligned, we need a block.
if (out_blocks_needed != nullptr) {
const size_t blocks_for_end_align =
(Common::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress())
? 1
: 0;
*out_blocks_needed = blocks_for_end_align;
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
}
R_SUCCEED();
}
Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
ASSERT(this->IsLockedByCurrentThread());
// Check memory state.
const KProcessAddress last_addr = addr + size - 1;
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
R_TRY(this->CheckMemoryState(out_state, out_perm, out_attr, out_blocks_needed, it, last_addr,
state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
// If the start address isn't aligned, we need a block.
if (out_blocks_needed != nullptr &&
Common::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) {
++(*out_blocks_needed);
}
R_SUCCEED();
}
@ -3453,11 +3388,6 @@ Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* out_K
new_attr, KMemoryBlockDisableMergeAttribute::Locked,
KMemoryBlockDisableMergeAttribute::None);
// If we have an output page group, open.
if (out_pg) {
out_pg->Open();
}
R_SUCCEED();
}

View File

@ -104,9 +104,6 @@ public:
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
Result LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
KMemoryPermission perm);
Result UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup& pg);
Result LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size);
Result UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg);
Result MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
@ -126,6 +123,8 @@ public:
return m_block_info_manager;
}
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
KPhysicalAddress phys_addr, KProcessAddress region_start,
size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
@ -160,21 +159,6 @@ public:
void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
const KPageGroup& pg);
KProcessAddress GetRegionAddress(Svc::MemoryState state) const;
size_t GetRegionSize(Svc::MemoryState state) const;
bool CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const;
KProcessAddress GetRegionAddress(KMemoryState state) const {
return this->GetRegionAddress(static_cast<Svc::MemoryState>(state & KMemoryState::Mask));
}
size_t GetRegionSize(KMemoryState state) const {
return this->GetRegionSize(static_cast<Svc::MemoryState>(state & KMemoryState::Mask));
}
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const {
return this->CanContain(addr, size,
static_cast<Svc::MemoryState>(state & KMemoryState::Mask));
}
protected:
struct PageLinkedList {
private:
@ -217,13 +201,12 @@ protected:
private:
enum class OperationType : u32 {
Map = 0,
MapGroup = 1,
MapFirstGroup = 2,
MapFirst = 1,
MapGroup = 2,
Unmap = 3,
ChangePermissions = 4,
ChangePermissionsAndRefresh = 5,
ChangePermissionsAndRefreshAndFlush = 6,
Separate = 7,
Separate = 6,
};
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
@ -242,6 +225,8 @@ private:
Result Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm,
OperationType operation, KPhysicalAddress map_addr = 0);
void FinalizeUpdate(PageLinkedList* page_list);
KProcessAddress GetRegionAddress(KMemoryState state) const;
size_t GetRegionSize(KMemoryState state) const;
KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
size_t num_pages, size_t alignment, size_t offset,
@ -262,13 +247,6 @@ private:
Result CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
KMemoryBlockManager::const_iterator it, KProcessAddress last_addr,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
KProcessAddress addr, size_t size, KMemoryState state_mask,

View File

@ -149,7 +149,7 @@ u64 KProcess::GetTotalPhysicalMemoryUsed() {
}
u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() {
return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceSize();
return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceUsage();
}
bool KProcess::ReleaseUserException(KThread* thread) {

View File

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_transfer_memory.h"
@ -10,50 +9,28 @@
namespace Kernel {
KTransferMemory::KTransferMemory(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{kernel} {}
: KAutoObjectWithSlabHeapAndContainer{kernel} {}
KTransferMemory::~KTransferMemory() = default;
Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
Svc::MemoryPermission own_perm) {
Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size,
Svc::MemoryPermission owner_perm) {
// Set members.
m_owner = GetCurrentProcessPointer(m_kernel);
// Get the owner page table.
auto& page_table = m_owner->GetPageTable();
// Construct the page group, guarding to make sure our state is valid on exit.
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
// Lock the memory.
R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
ConvertToKMemoryPermission(own_perm)));
// TODO(bunnei): Lock for transfer memory
// Set remaining tracking members.
m_owner->Open();
m_owner_perm = own_perm;
m_address = addr;
m_owner_perm = owner_perm;
m_address = address;
m_size = size;
m_is_initialized = true;
m_is_mapped = false;
// We succeeded.
pg_guard.Cancel();
R_SUCCEED();
}
void KTransferMemory::Finalize() {
// Unlock.
if (!m_is_mapped) {
const size_t size = m_page_group->GetNumPages() * PageSize;
ASSERT(R_SUCCEEDED(
m_owner->GetPageTable().UnlockForTransferMemory(m_address, size, *m_page_group)));
}
// Close the page group.
m_page_group->Close();
m_page_group->Finalize();
}
void KTransferMemory::Finalize() {}
void KTransferMemory::PostDestroy(uintptr_t arg) {
KProcess* owner = reinterpret_cast<KProcess*>(arg);
@ -61,54 +38,4 @@ void KTransferMemory::PostDestroy(uintptr_t arg) {
owner->Close();
}
Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Validate the permission.
R_UNLESS(m_owner_perm == map_perm, ResultInvalidState);
// Lock ourselves.
KScopedLightLock lk(m_lock);
// Ensure we're not already mapped.
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered
: KMemoryState::SharedTransfered;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
address, *m_page_group, state, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
m_is_mapped = true;
R_SUCCEED();
}
Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Lock ourselves.
KScopedLightLock lk(m_lock);
// Unmap the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered
: KMemoryState::SharedTransfered;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
// Mark ourselves as unmapped.
ASSERT(m_is_mapped);
m_is_mapped = false;
R_SUCCEED();
}
size_t KTransferMemory::GetSize() const {
return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0;
}
} // namespace Kernel

View File

@ -3,9 +3,6 @@
#pragma once
#include <optional>
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
@ -51,19 +48,16 @@ public:
return m_address;
}
size_t GetSize() const;
Result Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm);
Result Unmap(KProcessAddress address, size_t size);
size_t GetSize() const {
return m_is_initialized ? m_size : 0;
}
private:
std::optional<KPageGroup> m_page_group{};
KProcess* m_owner{};
KProcessAddress m_address{};
KLightLock m_lock;
Svc::MemoryPermission m_owner_perm{};
size_t m_size{};
bool m_is_initialized{};
bool m_is_mapped{};
};
} // namespace Kernel

View File

@ -373,7 +373,7 @@ struct KernelCore::Impl {
static inline thread_local u8 host_thread_id = UINT8_MAX;
/// Sets the host thread ID for the caller.
LTO_NOINLINE u32 SetHostThreadId(std::size_t core_id) {
u32 SetHostThreadId(std::size_t core_id) {
// This should only be called during core init.
ASSERT(host_thread_id == UINT8_MAX);
@ -384,13 +384,13 @@ struct KernelCore::Impl {
}
/// Gets the host thread ID for the caller
LTO_NOINLINE u32 GetHostThreadId() const {
u32 GetHostThreadId() const {
return host_thread_id;
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
LTO_NOINLINE KThread* GetHostDummyThread(KThread* existing_thread) {
const auto initialize{[](KThread* thread) LTO_NOINLINE {
KThread* GetHostDummyThread(KThread* existing_thread) {
const auto initialize{[](KThread* thread) {
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
return thread;
}};
@ -424,11 +424,11 @@ struct KernelCore::Impl {
static inline thread_local bool is_phantom_mode_for_singlecore{false};
LTO_NOINLINE bool IsPhantomModeForSingleCore() const {
bool IsPhantomModeForSingleCore() const {
return is_phantom_mode_for_singlecore;
}
LTO_NOINLINE void SetIsPhantomModeForSingleCore(bool value) {
void SetIsPhantomModeForSingleCore(bool value) {
ASSERT(!is_multicore);
is_phantom_mode_for_singlecore = value;
}
@ -439,14 +439,14 @@ struct KernelCore::Impl {
static inline thread_local KThread* current_thread{nullptr};
LTO_NOINLINE KThread* GetCurrentEmuThread() {
KThread* GetCurrentEmuThread() {
if (!current_thread) {
current_thread = GetHostDummyThread(nullptr);
}
return current_thread;
}
LTO_NOINLINE void SetCurrentEmuThread(KThread* thread) {
void SetCurrentEmuThread(KThread* thread) {
current_thread = thread;
}
@ -623,33 +623,14 @@ struct KernelCore::Impl {
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
GetInteger(slab_start_phys_addr), slab_region_size, KMemoryRegionType_DramKernelSlab));
// Insert a physical region for the secure applet memory.
const auto secure_applet_end_phys_addr =
slab_end_phys_addr + KSystemControl::SecureAppletMemorySize;
if constexpr (KSystemControl::SecureAppletMemorySize > 0) {
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
GetInteger(slab_end_phys_addr), KSystemControl::SecureAppletMemorySize,
KMemoryRegionType_DramKernelSecureAppletMemory));
}
// Insert a physical region for the unknown debug2 region.
constexpr size_t SecureUnknownRegionSize = 0;
const size_t secure_unknown_size = SecureUnknownRegionSize;
const auto secure_unknown_end_phys_addr = secure_applet_end_phys_addr + secure_unknown_size;
if constexpr (SecureUnknownRegionSize > 0) {
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
GetInteger(secure_applet_end_phys_addr), secure_unknown_size,
KMemoryRegionType_DramKernelSecureUnknown));
}
// Determine size available for kernel page table heaps, requiring > 8 MB.
const KPhysicalAddress resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
const size_t page_table_heap_size = resource_end_phys_addr - secure_unknown_end_phys_addr;
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
ASSERT(page_table_heap_size / 4_MiB > 2);
// Insert a physical region for the kernel page table heap region
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
GetInteger(secure_unknown_end_phys_addr), page_table_heap_size,
GetInteger(slab_end_phys_addr), page_table_heap_size,
KMemoryRegionType_DramKernelPtHeap));
// All DRAM regions that we haven't tagged by this point will be mapped under the linear

Some files were not shown because too many files have changed in this diff Show More