Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a5fb9de6fa | |||
| 26f9d1f122 |
@@ -1,7 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# Gets a UTC timestamp and sets the provided variable to it
|
||||
# Gets a UTC timstamp and sets the provided variable to it
|
||||
function(get_timestamp _var)
|
||||
string(TIMESTAMP timestamp UTC)
|
||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||
|
||||
Vendored
-7176
File diff suppressed because it is too large
Load Diff
Vendored
+370
-454
File diff suppressed because it is too large
Load Diff
Vendored
+370
-454
File diff suppressed because it is too large
Load Diff
Vendored
+370
-454
File diff suppressed because it is too large
Load Diff
Vendored
+371
-455
File diff suppressed because it is too large
Load Diff
Vendored
+370
-454
File diff suppressed because it is too large
Load Diff
Vendored
+373
-459
File diff suppressed because it is too large
Load Diff
Vendored
+444
-530
File diff suppressed because it is too large
Load Diff
Vendored
-7171
File diff suppressed because it is too large
Load Diff
Vendored
+370
-454
File diff suppressed because it is too large
Load Diff
Vendored
+374
-460
File diff suppressed because it is too large
Load Diff
Vendored
+387
-471
File diff suppressed because it is too large
Load Diff
Vendored
+371
-455
File diff suppressed because it is too large
Load Diff
Vendored
+373
-459
File diff suppressed because it is too large
Load Diff
Vendored
+399
-486
File diff suppressed because it is too large
Load Diff
Vendored
+371
-455
File diff suppressed because it is too large
Load Diff
Vendored
+453
-541
File diff suppressed because it is too large
Load Diff
Vendored
+453
-540
File diff suppressed because it is too large
Load Diff
Vendored
+371
-455
File diff suppressed because it is too large
Load Diff
Vendored
+370
-454
File diff suppressed because it is too large
Load Diff
Vendored
+371
-455
File diff suppressed because it is too large
Load Diff
Vendored
+371
-455
File diff suppressed because it is too large
Load Diff
Vendored
+372
-458
File diff suppressed because it is too large
Load Diff
Vendored
+372
-458
File diff suppressed because it is too large
Load Diff
Vendored
+372
-458
File diff suppressed because it is too large
Load Diff
Vendored
+371
-457
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -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)
|
||||
|
||||
Vendored
-7529
File diff suppressed because it is too large
Load Diff
Vendored
-772
@@ -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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
Vendored
-2282
File diff suppressed because it is too large
Load Diff
Vendored
-426
@@ -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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -15,13 +15,9 @@ 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.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.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
|
||||
|
||||
@@ -75,7 +71,7 @@ object NativeLibrary {
|
||||
return if (isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.openContentUri(path, openmode)
|
||||
} else {
|
||||
openContentUri(appContext, path, openmode)
|
||||
FileUtil.openContentUri(path, openmode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +81,7 @@ object NativeLibrary {
|
||||
return if (isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.getFileSize(path)
|
||||
} else {
|
||||
getFileSize(appContext, path)
|
||||
FileUtil.getFileSize(path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +91,7 @@ object NativeLibrary {
|
||||
return if (isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.exists(path)
|
||||
} else {
|
||||
exists(appContext, path)
|
||||
FileUtil.exists(path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +101,7 @@ object NativeLibrary {
|
||||
return if (isNativePath(path!!)) {
|
||||
YuzuApplication.documentsTree!!.isDirectory(path)
|
||||
} else {
|
||||
isDirectory(appContext, path)
|
||||
FileUtil.isDirectory(path)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class YuzuApplication : Application() {
|
||||
application = this
|
||||
documentsTree = DocumentsTree()
|
||||
DirectoryInitialization.start()
|
||||
GpuDriverHelper.initializeDriverParameters(applicationContext)
|
||||
GpuDriverHelper.initializeDriverParameters()
|
||||
NativeLibrary.logDeviceInfo()
|
||||
|
||||
createNotificationChannels()
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
// 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.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
|
||||
) {
|
||||
// Ignore file exceptions when a user selects an invalid zip
|
||||
try {
|
||||
GpuDriverHelper.copyDriverToInternalStorage(result)
|
||||
} catch (_: IOException) {
|
||||
return@newInstance getString(R.string.select_gpu_driver_error)
|
||||
}
|
||||
|
||||
val driverData = GpuDriverHelper.customDriverData
|
||||
if (driverData.name == null) {
|
||||
return@newInstance getString(R.string.select_gpu_driver_error)
|
||||
}
|
||||
|
||||
val driverInList =
|
||||
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
|
||||
if (driverInList != null) {
|
||||
return@newInstance getString(R.string.driver_already_installed)
|
||||
} else {
|
||||
driverViewModel.addDriver(
|
||||
Pair(
|
||||
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}",
|
||||
driverData
|
||||
)
|
||||
)
|
||||
driverViewModel.setNewDriverInstalled(true)
|
||||
}
|
||||
return@newInstance Any()
|
||||
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// 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"
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ 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
|
||||
@@ -50,6 +51,7 @@ 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
|
||||
@@ -70,6 +72,7 @@ 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
|
||||
|
||||
@@ -299,6 +302,21 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,17 +350,6 @@ 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()
|
||||
|
||||
@@ -5,7 +5,6 @@ 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
|
||||
@@ -28,7 +27,6 @@ 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
|
||||
@@ -37,6 +35,7 @@ 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
|
||||
@@ -50,6 +49,7 @@ 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,13 +107,17 @@ class HomeSettingsFragment : Fragment() {
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.install_gpu_driver,
|
||||
R.string.gpu_driver_manager,
|
||||
R.string.install_gpu_driver_description,
|
||||
R.drawable.ic_exit,
|
||||
{ driverInstaller() },
|
||||
R.drawable.ic_build,
|
||||
{
|
||||
binding.root.findNavController()
|
||||
.navigate(R.id.action_homeSettingsFragment_to_driverManagerFragment)
|
||||
},
|
||||
{ GpuDriverHelper.supportsCustomDriverLoading() },
|
||||
R.string.custom_driver_not_supported,
|
||||
R.string.custom_driver_not_supported_description
|
||||
R.string.custom_driver_not_supported_description,
|
||||
driverViewModel.selectedDriverMetadata
|
||||
)
|
||||
)
|
||||
add(
|
||||
@@ -292,31 +296,6 @@ 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,
|
||||
|
||||
+6
-2
@@ -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,6 +78,10 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
|
||||
requireActivity().supportFragmentManager,
|
||||
MessageDialogFragment.TAG
|
||||
)
|
||||
|
||||
else -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
taskViewModel.clear()
|
||||
}
|
||||
@@ -115,7 +119,7 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
|
||||
private const val CANCELLABLE = "Cancellable"
|
||||
|
||||
fun newInstance(
|
||||
activity: AppCompatActivity,
|
||||
activity: FragmentActivity,
|
||||
titleId: Int,
|
||||
cancellable: Boolean = false,
|
||||
task: () -> Any
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
@@ -29,12 +29,10 @@ 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
|
||||
@@ -43,7 +41,6 @@ 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
|
||||
@@ -343,11 +340,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
|
||||
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
||||
if (FileUtil.copyUriToInternalStorage(
|
||||
applicationContext,
|
||||
result,
|
||||
dstPath,
|
||||
"prod.keys"
|
||||
)
|
||||
) != null
|
||||
) {
|
||||
if (NativeLibrary.reloadKeys()) {
|
||||
Toast.makeText(
|
||||
@@ -446,11 +442,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
|
||||
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
||||
if (FileUtil.copyUriToInternalStorage(
|
||||
applicationContext,
|
||||
result,
|
||||
dstPath,
|
||||
"key_retail.bin"
|
||||
)
|
||||
) != null
|
||||
) {
|
||||
if (NativeLibrary.reloadKeys()) {
|
||||
Toast.makeText(
|
||||
@@ -469,59 +464,6 @@ 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> ->
|
||||
|
||||
@@ -7,7 +7,6 @@ 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 {
|
||||
@@ -22,7 +21,7 @@ class DocumentsTree {
|
||||
|
||||
fun openContentUri(filepath: String, openMode: String?): Int {
|
||||
val node = resolvePath(filepath) ?: return -1
|
||||
return FileUtil.openContentUri(YuzuApplication.appContext, node.uri.toString(), openMode)
|
||||
return FileUtil.openContentUri(node.uri.toString(), openMode)
|
||||
}
|
||||
|
||||
fun getFileSize(filepath: String): Long {
|
||||
@@ -30,7 +29,7 @@ class DocumentsTree {
|
||||
return if (node == null || node.isDirectory) {
|
||||
0
|
||||
} else {
|
||||
FileUtil.getFileSize(YuzuApplication.appContext, node.uri.toString())
|
||||
FileUtil.getFileSize(node.uri.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +66,7 @@ class DocumentsTree {
|
||||
* @param parent parent node of this level
|
||||
*/
|
||||
private fun structTree(parent: DocumentsNode) {
|
||||
val documents = FileUtil.listFiles(YuzuApplication.appContext, parent.uri!!)
|
||||
val documents = FileUtil.listFiles(parent.uri!!)
|
||||
for (document in documents) {
|
||||
val node = DocumentsNode(document)
|
||||
node.parent = parent
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.DocumentsContract
|
||||
@@ -11,7 +10,6 @@ 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
|
||||
@@ -21,6 +19,8 @@ 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,6 +29,8 @@ 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
|
||||
@@ -36,11 +38,11 @@ object FileUtil {
|
||||
* @param filename file display name.
|
||||
* @return boolean
|
||||
*/
|
||||
fun createFile(context: Context?, directory: String?, filename: String): DocumentFile? {
|
||||
fun createFile(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")) {
|
||||
@@ -56,16 +58,15 @@ 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(context: Context?, directory: String?, directoryName: String?): DocumentFile? {
|
||||
fun createDir(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)
|
||||
@@ -77,13 +78,12 @@ 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(context: Context, path: String, openMode: String?): Int {
|
||||
fun openContentUri(path: String, openMode: String?): Int {
|
||||
try {
|
||||
val uri = Uri.parse(path)
|
||||
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, openMode!!)
|
||||
@@ -103,11 +103,10 @@ 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(context: Context, uri: Uri): Array<MinimalDocumentFile> {
|
||||
fun listFiles(uri: Uri): Array<MinimalDocumentFile> {
|
||||
val resolver = context.contentResolver
|
||||
val columns = arrayOf(
|
||||
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
|
||||
@@ -145,7 +144,7 @@ object FileUtil {
|
||||
* @param path Native content uri path
|
||||
* @return bool
|
||||
*/
|
||||
fun exists(context: Context, path: String?): Boolean {
|
||||
fun exists(path: String?): Boolean {
|
||||
var c: Cursor? = null
|
||||
try {
|
||||
val mUri = Uri.parse(path)
|
||||
@@ -165,7 +164,7 @@ object FileUtil {
|
||||
* @param path content uri path
|
||||
* @return bool
|
||||
*/
|
||||
fun isDirectory(context: Context, path: String): Boolean {
|
||||
fun isDirectory(path: String): Boolean {
|
||||
val resolver = context.contentResolver
|
||||
val columns = arrayOf(
|
||||
DocumentsContract.Document.COLUMN_MIME_TYPE
|
||||
@@ -210,10 +209,10 @@ object FileUtil {
|
||||
return filename
|
||||
}
|
||||
|
||||
fun getFilesName(context: Context, path: String): Array<String> {
|
||||
fun getFilesName(path: String): Array<String> {
|
||||
val uri = Uri.parse(path)
|
||||
val files: MutableList<String> = ArrayList()
|
||||
for (file in listFiles(context, uri)) {
|
||||
for (file in listFiles(uri)) {
|
||||
files.add(file.filename)
|
||||
}
|
||||
return files.toTypedArray()
|
||||
@@ -225,7 +224,7 @@ object FileUtil {
|
||||
* @return long file size
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getFileSize(context: Context, path: String): Long {
|
||||
fun getFileSize(path: String): Long {
|
||||
val resolver = context.contentResolver
|
||||
val columns = arrayOf(
|
||||
DocumentsContract.Document.COLUMN_SIZE
|
||||
@@ -245,44 +244,38 @@ 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(
|
||||
context: Context,
|
||||
sourceUri: Uri?,
|
||||
sourceUri: Uri,
|
||||
destinationParentPath: String,
|
||||
destinationFilename: String
|
||||
): Boolean {
|
||||
var input: InputStream? = null
|
||||
var output: FileOutputStream? = null
|
||||
destinationFilename: String = ""
|
||||
): File? =
|
||||
try {
|
||||
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)
|
||||
val fileName =
|
||||
if (destinationFilename == "") getFilename(sourceUri) else "/$destinationFilename"
|
||||
val inputStream = context.contentResolver.openInputStream(sourceUri)!!
|
||||
|
||||
val destinationFile = File("$destinationParentPath$fileName")
|
||||
if (destinationFile.exists()) {
|
||||
destinationFile.delete()
|
||||
}
|
||||
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.outputStream().use { fos ->
|
||||
inputStream.use { it.copyTo(fos) }
|
||||
}
|
||||
destinationFile
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
} catch (e: NullPointerException) {
|
||||
null
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the given zip file into the given directory.
|
||||
@@ -368,4 +361,12 @@ 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)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ object GameHelper {
|
||||
// Ensure keys are loaded so that ROM metadata can be decrypted.
|
||||
NativeLibrary.reloadKeys()
|
||||
|
||||
addGamesRecursive(games, FileUtil.listFiles(context, gamesUri), 3)
|
||||
addGamesRecursive(games, FileUtil.listFiles(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(YuzuApplication.appContext, it.uri),
|
||||
FileUtil.listFiles(it.uri),
|
||||
depth - 1
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -3,64 +3,33 @@
|
||||
|
||||
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.utils.FileUtil.copyUriToInternalStorage
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import java.util.zip.ZipException
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
object GpuDriverHelper {
|
||||
private const val META_JSON_FILENAME = "meta.json"
|
||||
private const val DRIVER_INTERNAL_FILENAME = "gpu_driver.zip"
|
||||
private var fileRedirectionPath: String? = null
|
||||
private var driverInstallationPath: String? = null
|
||||
var driverInstallationPath: String? = null
|
||||
private var hookLibPath: String? = null
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun unzip(zipFilePath: String, destDir: String) {
|
||||
val dir = File(destDir)
|
||||
val driverStoragePath get() = DirectoryInitialization.userDirectory!! + "/gpu_drivers/"
|
||||
|
||||
// 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) {
|
||||
fun initializeDriverParameters() {
|
||||
try {
|
||||
// Initialize the file redirection directory.
|
||||
fileRedirectionPath =
|
||||
context.getExternalFilesDir(null)!!.canonicalPath + "/gpu/vk_file_redirect/"
|
||||
fileRedirectionPath = YuzuApplication.appContext
|
||||
.getExternalFilesDir(null)!!.canonicalPath + "/gpu/vk_file_redirect/"
|
||||
|
||||
// Initialize the driver installation directory.
|
||||
driverInstallationPath = context.filesDir.canonicalPath + "/gpu_driver/"
|
||||
driverInstallationPath = YuzuApplication.appContext
|
||||
.filesDir.canonicalPath + "/gpu_driver/"
|
||||
} catch (e: IOException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
@@ -69,68 +38,169 @@ object GpuDriverHelper {
|
||||
initializeDirectories()
|
||||
|
||||
// Initialize hook libraries directory.
|
||||
hookLibPath = context.applicationInfo.nativeLibraryDir + "/"
|
||||
hookLibPath = YuzuApplication.appContext.applicationInfo.nativeLibraryDir + "/"
|
||||
|
||||
// Initialize GPU driver.
|
||||
NativeLibrary.initializeGpuDriver(
|
||||
hookLibPath,
|
||||
driverInstallationPath,
|
||||
customDriverLibraryName,
|
||||
customDriverData.libraryName,
|
||||
fileRedirectionPath
|
||||
)
|
||||
}
|
||||
|
||||
fun installDefaultDriver(context: Context) {
|
||||
// Removing the installed driver will result in the backend using the default system driver.
|
||||
val driverInstallationDir = File(driverInstallationPath!!)
|
||||
deleteRecursive(driverInstallationDir)
|
||||
initializeDriverParameters(context)
|
||||
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 installCustomDriver(context: Context, driverPathUri: Uri?) {
|
||||
fun installDefaultDriver() {
|
||||
// Removing the installed driver will result in the backend using the default system driver.
|
||||
File(driverInstallationPath!!).deleteRecursively()
|
||||
initializeDriverParameters()
|
||||
}
|
||||
|
||||
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 {
|
||||
// Revert to system default in the event the specified driver is bad.
|
||||
installDefaultDriver(context)
|
||||
installDefaultDriver()
|
||||
|
||||
// Ensure we have directories.
|
||||
initializeDirectories()
|
||||
|
||||
// Copy the zip file URI into our private storage.
|
||||
copyUriToInternalStorage(
|
||||
context,
|
||||
driverPathUri,
|
||||
driverInstallationPath!!,
|
||||
DRIVER_INTERNAL_FILENAME
|
||||
)
|
||||
// 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
|
||||
}
|
||||
|
||||
// Unzip the driver.
|
||||
try {
|
||||
unzip(driverInstallationPath + DRIVER_INTERNAL_FILENAME, driverInstallationPath!!)
|
||||
FileUtil.unzipToInternalStorage(
|
||||
BufferedInputStream(copiedFile.inputStream()),
|
||||
File(driverInstallationPath!!)
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
// Initialize the driver parameters.
|
||||
initializeDriverParameters(context)
|
||||
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()
|
||||
}
|
||||
|
||||
external fun supportsCustomDriverLoading(): Boolean
|
||||
|
||||
// Parse the custom driver metadata to retrieve the name.
|
||||
val customDriverName: String?
|
||||
get() {
|
||||
val metadata = GpuDriverMetadata(driverInstallationPath + META_JSON_FILENAME)
|
||||
return metadata.name
|
||||
}
|
||||
val customDriverData: GpuDriverMetadata
|
||||
get() = GpuDriverMetadata(File(driverInstallationPath + META_JSON_FILENAME))
|
||||
|
||||
// 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() {
|
||||
fun initializeDirectories() {
|
||||
// Ensure the file redirection directory exists.
|
||||
val fileRedirectionDir = File(fileRedirectionPath!!)
|
||||
if (!fileRedirectionDir.exists()) {
|
||||
@@ -141,14 +211,10 @@ object GpuDriverHelper {
|
||||
if (!driverInstallationDir.exists()) {
|
||||
driverInstallationDir.mkdirs()
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteRecursive(fileOrDirectory: File) {
|
||||
if (fileOrDirectory.isDirectory) {
|
||||
for (child in fileOrDirectory.listFiles()!!) {
|
||||
deleteRecursive(child)
|
||||
}
|
||||
// Ensure the driver storage directory exists
|
||||
val driverStorageDirectory = File(driverStoragePath)
|
||||
if (!driverStorageDirectory.exists()) {
|
||||
driverStorageDirectory.mkdirs()
|
||||
}
|
||||
fileOrDirectory.delete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,29 +4,29 @@
|
||||
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(metadataFilePath: String) {
|
||||
var name: String? = null
|
||||
var description: String? = null
|
||||
var author: String? = null
|
||||
var vendor: String? = null
|
||||
var driverVersion: String? = null
|
||||
var minApi = 0
|
||||
var libraryName: String? = null
|
||||
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
|
||||
}
|
||||
|
||||
init {
|
||||
try {
|
||||
val json = JSONObject(getStringFromFile(metadataFilePath))
|
||||
val json = JSONObject(FileUtil.getStringFromFile(metadataFile))
|
||||
name = json.getString("name")
|
||||
description = json.getString("description")
|
||||
author = json.getString("author")
|
||||
vendor = json.getString("vendor")
|
||||
driverVersion = json.getString("driverVersion")
|
||||
version = json.getString("driverVersion")
|
||||
minApi = json.getInt("minApi")
|
||||
libraryName = json.getString("libraryName")
|
||||
} catch (e: JSONException) {
|
||||
@@ -36,12 +36,84 @@ class GpuDriverMetadata(metadataFilePath: String) {
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@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)
|
||||
/**
|
||||
* 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()
|
||||
|
||||
var name: String? = null
|
||||
var description: String? = null
|
||||
var author: String? = null
|
||||
var vendor: String? = null
|
||||
var version: String? = null
|
||||
var minApi = 0
|
||||
var libraryName: String? = null
|
||||
|
||||
companion object {
|
||||
private const val MAX_META_SIZE_BYTES = 500000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +218,7 @@ public:
|
||||
return;
|
||||
}
|
||||
m_window->OnSurfaceChanged(m_native_window);
|
||||
m_system.Renderer().NotifySurfaceChanged();
|
||||
}
|
||||
|
||||
void ConfigureFilesystemProvider(const std::string& filepath) {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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>
|
||||
@@ -22,6 +22,9 @@
|
||||
<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
|
||||
@@ -95,5 +98,9 @@
|
||||
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>
|
||||
|
||||
@@ -168,9 +168,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -170,9 +170,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -171,9 +171,7 @@
|
||||
<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>
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
<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>
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<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>
|
||||
@@ -234,15 +235,17 @@
|
||||
<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, using system default!</string>
|
||||
<string name="select_gpu_driver_error">Invalid driver selected</string>
|
||||
<string name="driver_already_installed">Driver already installed</string>
|
||||
<string name="system_gpu_driver">System GPU driver</string>
|
||||
<string name="installing_driver">Installing driver…</string>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace AudioCore::Renderer {
|
||||
|
||||
/**
|
||||
* AudioRenderer command for preparing depop.
|
||||
* Adds the previously output last samples to the depop buffer.
|
||||
* Adds the previusly output last samples to the depop buffer.
|
||||
*/
|
||||
struct DepopPrepareCommand : ICommand {
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -135,11 +135,6 @@ std::u16string UTF8ToUTF16(std::string_view input) {
|
||||
return convert.from_bytes(input.data(), input.data() + input.size());
|
||||
}
|
||||
|
||||
std::u32string UTF8ToUTF32(std::string_view input) {
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
|
||||
return convert.from_bytes(input.data(), input.data() + input.size());
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::wstring CPToUTF16(u32 code_page, std::string_view input) {
|
||||
const auto size =
|
||||
|
||||
@@ -38,7 +38,6 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
||||
|
||||
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
|
||||
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
|
||||
[[nodiscard]] std::u32string UTF8ToUTF32(std::string_view input);
|
||||
|
||||
#ifdef _WIN32
|
||||
[[nodiscard]] std::string UTF16ToUTF8(std::wstring_view input);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -702,8 +698,6 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/consumer_base.cpp
|
||||
hle/service/nvnflinger/consumer_base.h
|
||||
hle/service/nvnflinger/consumer_listener.h
|
||||
hle/service/nvnflinger/fb_share_buffer_manager.cpp
|
||||
hle/service/nvnflinger/fb_share_buffer_manager.h
|
||||
hle/service/nvnflinger/graphic_buffer_producer.cpp
|
||||
hle/service/nvnflinger/graphic_buffer_producer.h
|
||||
hle/service/nvnflinger/hos_binder_driver_server.cpp
|
||||
|
||||
@@ -1078,10 +1078,6 @@ void System::ApplySettings() {
|
||||
impl->RefreshTime();
|
||||
|
||||
if (IsPoweredOn()) {
|
||||
if (Settings::values.custom_rtc_enabled) {
|
||||
const s64 posix_time{Settings::values.custom_rtc.GetValue()};
|
||||
GetTimeManager().UpdateLocalSystemClockTime(posix_time);
|
||||
}
|
||||
Renderer().RefreshBaseSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <atomic>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
@@ -14,7 +12,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core.h"
|
||||
#include "core/debugger/gdbstub.h"
|
||||
@@ -71,16 +68,10 @@ static std::string EscapeGDB(std::string_view data) {
|
||||
}
|
||||
|
||||
static std::string EscapeXML(std::string_view data) {
|
||||
std::u32string converted = U"[Encoding error]";
|
||||
try {
|
||||
converted = Common::UTF8ToUTF32(data);
|
||||
} catch (std::range_error&) {
|
||||
}
|
||||
|
||||
std::string escaped;
|
||||
escaped.reserve(data.size());
|
||||
|
||||
for (char32_t c : converted) {
|
||||
for (char c : data) {
|
||||
switch (c) {
|
||||
case '&':
|
||||
escaped += "&";
|
||||
@@ -95,11 +86,7 @@ static std::string EscapeXML(std::string_view data) {
|
||||
escaped += ">";
|
||||
break;
|
||||
default:
|
||||
if (c > 0x7f) {
|
||||
escaped += fmt::format("&#{};", static_cast<u32>(c));
|
||||
} else {
|
||||
escaped += static_cast<char>(c);
|
||||
}
|
||||
escaped += c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/loader/loader.h"
|
||||
@@ -96,13 +95,6 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
|
||||
return Loader::ResultStatus::Success;
|
||||
}
|
||||
|
||||
Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
|
||||
const u64 original_program_id = aci_header.title_id;
|
||||
SCOPE_EXIT({ aci_header.title_id = original_program_id; });
|
||||
|
||||
return this->Load(file);
|
||||
}
|
||||
|
||||
/*static*/ ProgramMetadata ProgramMetadata::GetDefault() {
|
||||
// Allow use of cores 0~3 and thread priorities 1~63.
|
||||
constexpr u32 default_thread_info_capability = 0x30007F7;
|
||||
|
||||
@@ -56,7 +56,6 @@ public:
|
||||
static ProgramMetadata GetDefault();
|
||||
|
||||
Loader::ResultStatus Load(VirtualFile file);
|
||||
Loader::ResultStatus Reload(VirtualFile file);
|
||||
|
||||
/// Load from parameters instead of NPDM file, used for KIP
|
||||
void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, s32 main_thread_prio,
|
||||
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
|
||||
}
|
||||
|
||||
// Renames the file to name. Returns whether or not the operation was successful.
|
||||
// Renames the file to name. Returns whether or not the operation was successsful.
|
||||
virtual bool Rename(std::string_view name) = 0;
|
||||
|
||||
// Returns the full path of this file as a string, recursively
|
||||
|
||||
@@ -61,7 +61,7 @@ bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_at
|
||||
found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
|
||||
this->insert(*found);
|
||||
} else {
|
||||
// If we can't reuse, adjust the old region.
|
||||
// If we can't re-use, adjust the old region.
|
||||
found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
|
||||
this->insert(*found);
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/literals.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_address_space_info.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
@@ -338,14 +337,11 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
|
||||
}
|
||||
|
||||
void KPageTable::Finalize() {
|
||||
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
||||
if (Settings::IsFastmemEnabled()) {
|
||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size);
|
||||
}
|
||||
};
|
||||
|
||||
// Finalize memory blocks.
|
||||
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback));
|
||||
m_memory_block_manager.Finalize(m_memory_block_slab_manager,
|
||||
[&](KProcessAddress addr, u64 size) {
|
||||
m_memory->UnmapRegion(*m_page_table_impl, addr, size);
|
||||
});
|
||||
|
||||
// Release any insecure mapped memory.
|
||||
if (m_mapped_insecure_memory) {
|
||||
@@ -2949,23 +2945,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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -71,59 +71,15 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
|
||||
}
|
||||
|
||||
Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size,
|
||||
MemoryPermission map_perm) {
|
||||
// Validate the address/size.
|
||||
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Validate the permission.
|
||||
R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidState);
|
||||
|
||||
// Get the transfer memory.
|
||||
KScopedAutoObject trmem = GetCurrentProcess(system.Kernel())
|
||||
.GetHandleTable()
|
||||
.GetObject<KTransferMemory>(trmem_handle);
|
||||
R_UNLESS(trmem.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Verify that the mapping is in range.
|
||||
R_UNLESS(GetCurrentProcess(system.Kernel())
|
||||
.GetPageTable()
|
||||
.CanContain(address, size, KMemoryState::Transfered),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Map the transfer memory.
|
||||
R_TRY(trmem->Map(address, size, map_perm));
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
MemoryPermission owner_perm) {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address,
|
||||
uint64_t size) {
|
||||
// Validate the address/size.
|
||||
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Get the transfer memory.
|
||||
KScopedAutoObject trmem = GetCurrentProcess(system.Kernel())
|
||||
.GetHandleTable()
|
||||
.GetObject<KTransferMemory>(trmem_handle);
|
||||
R_UNLESS(trmem.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Verify that the mapping is in range.
|
||||
R_UNLESS(GetCurrentProcess(system.Kernel())
|
||||
.GetPageTable()
|
||||
.CanContain(address, size, KMemoryState::Transfered),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Unmap the transfer memory.
|
||||
R_TRY(trmem->Unmap(address, size));
|
||||
|
||||
R_SUCCEED();
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultNotImplemented);
|
||||
}
|
||||
|
||||
Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,
|
||||
|
||||
+16
-256
@@ -8,7 +8,6 @@
|
||||
#include "common/settings.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
@@ -20,7 +19,6 @@
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
||||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
||||
#include "core/hle/service/am/applets/applet_profile_select.h"
|
||||
#include "core/hle/service/am/applets/applet_web_browser.h"
|
||||
@@ -31,17 +29,15 @@
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
||||
#include "core/hle/service/pm/pm.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/hle/service/vi/vi_results.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::AM {
|
||||
@@ -194,7 +190,7 @@ IDisplayController::IDisplayController(Core::System& system_)
|
||||
{4, nullptr, "UpdateCallerAppletCaptureImage"},
|
||||
{5, nullptr, "GetLastForegroundCaptureImageEx"},
|
||||
{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||
{7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
|
||||
{7, nullptr, "GetCallerAppletCaptureImageEx"},
|
||||
{8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
|
||||
{9, nullptr, "CopyBetweenCaptureBuffers"},
|
||||
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
||||
@@ -212,8 +208,8 @@ IDisplayController::IDisplayController(Core::System& system_)
|
||||
{23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
|
||||
{24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"},
|
||||
{25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
|
||||
{26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||
{27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||
{26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||
{27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -223,15 +219,6 @@ IDisplayController::IDisplayController(Core::System& system_)
|
||||
|
||||
IDisplayController::~IDisplayController() = default;
|
||||
|
||||
void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(1u);
|
||||
rb.Push(0);
|
||||
}
|
||||
|
||||
void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -239,22 +226,6 @@ void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(1U);
|
||||
rb.Push(0);
|
||||
}
|
||||
|
||||
void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
IDebugFunctions::IDebugFunctions(Core::System& system_)
|
||||
: ServiceFramework{system_, "IDebugFunctions"} {
|
||||
// clang-format off
|
||||
@@ -314,14 +285,14 @@ ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger&
|
||||
{20, nullptr, "SetDesirableKeyboardLayout"},
|
||||
{21, nullptr, "GetScreenShotProgramId"},
|
||||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
|
||||
{41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
|
||||
{42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
|
||||
{43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
|
||||
{41, nullptr, "IsSystemBufferSharingEnabled"},
|
||||
{42, nullptr, "GetSystemSharedLayerHandle"},
|
||||
{43, nullptr, "GetSystemSharedBufferHandle"},
|
||||
{44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
|
||||
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
|
||||
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
|
||||
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
|
||||
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
|
||||
{51, nullptr, "ApproveToDisplay"},
|
||||
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||
{61, nullptr, "SetMediaPlaybackState"},
|
||||
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
|
||||
@@ -520,50 +491,6 @@ void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
|
||||
rb.Push(*layer_id);
|
||||
}
|
||||
|
||||
void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(this->EnsureBufferSharingEnabled());
|
||||
}
|
||||
|
||||
void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(this->EnsureBufferSharingEnabled());
|
||||
rb.Push<s64>(system_shared_buffer_id);
|
||||
rb.Push<s64>(system_shared_layer_id);
|
||||
}
|
||||
|
||||
void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(this->EnsureBufferSharingEnabled());
|
||||
rb.Push<s64>(system_shared_buffer_id);
|
||||
}
|
||||
|
||||
Result ISelfController::EnsureBufferSharingEnabled() {
|
||||
if (buffer_sharing_enabled) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) {
|
||||
return VI::ResultOperationFailed;
|
||||
}
|
||||
|
||||
const auto display_id = nvnflinger.OpenDisplay("Default");
|
||||
const auto result = nvnflinger.GetSystemBufferManager().Initialize(
|
||||
&system_shared_buffer_id, &system_shared_layer_id, *display_id);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
buffer_sharing_enabled = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
@@ -589,13 +516,6 @@ void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
idle_time_detection_extension = rp.Pop<u32>();
|
||||
@@ -764,70 +684,9 @@ void AppletMessageQueue::OperationModeChanged() {
|
||||
on_operation_mode_changed->Signal();
|
||||
}
|
||||
|
||||
ILockAccessor::ILockAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &ILockAccessor::TryLock, "TryLock"},
|
||||
{2, &ILockAccessor::Unlock, "Unlock"},
|
||||
{3, &ILockAccessor::GetEvent, "GetEvent"},
|
||||
{4,&ILockAccessor::IsLocked, "IsLocked"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
|
||||
}
|
||||
|
||||
ILockAccessor::~ILockAccessor() = default;
|
||||
|
||||
void ILockAccessor::TryLock(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto return_handle = rp.Pop<bool>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
|
||||
|
||||
// TODO: When return_handle is true this function should return the lock handle
|
||||
|
||||
is_locked = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_locked);
|
||||
}
|
||||
|
||||
void ILockAccessor::Unlock(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
is_locked = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ILockAccessor::GetEvent(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
lock_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(lock_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ILockAccessor::IsLocked(HLERequestContext& ctx) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u8>(is_locked);
|
||||
}
|
||||
|
||||
ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue_)
|
||||
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
|
||||
service_context{system_, "ICommonStateGetter"} {
|
||||
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
|
||||
@@ -840,14 +699,14 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
{7, nullptr, "GetCradleStatus"},
|
||||
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
|
||||
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
|
||||
{10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
|
||||
{10, nullptr, "RequestToAcquireSleepLock"},
|
||||
{11, nullptr, "ReleaseSleepLock"},
|
||||
{12, nullptr, "ReleaseSleepLockTransiently"},
|
||||
{13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
|
||||
{13, nullptr, "GetAcquiredSleepLockEvent"},
|
||||
{14, nullptr, "GetWakeupCount"},
|
||||
{20, nullptr, "PushToGeneralChannel"},
|
||||
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
|
||||
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
|
||||
{31, nullptr, "GetReaderLockAccessorEx"},
|
||||
{32, nullptr, "GetWriterLockAccessorEx"},
|
||||
{40, nullptr, "GetCradleFwVersion"},
|
||||
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
|
||||
@@ -865,7 +724,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
{65, nullptr, "GetApplicationIdByContentActionName"},
|
||||
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
|
||||
{67, nullptr, "CancelCpuBoostMode"},
|
||||
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
|
||||
{68, nullptr, "GetBuiltInDisplayType"},
|
||||
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
|
||||
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
|
||||
{91, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
@@ -886,8 +745,6 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent");
|
||||
|
||||
// Configure applets to be in foreground state
|
||||
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
|
||||
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
|
||||
@@ -936,36 +793,6 @@ void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
|
||||
rb.Push(static_cast<u8>(FocusState::InFocus));
|
||||
}
|
||||
|
||||
void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// Sleep lock is acquired immediately.
|
||||
sleep_lock_event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unknown = rp.Pop<u32>();
|
||||
|
||||
LOG_INFO(Service_AM, "called, unknown={}", unknown);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILockAccessor>(system);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(sleep_lock_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
@@ -1042,14 +869,6 @@ void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
|
||||
apm_sys->SetCpuBoostMode(ctx);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(0);
|
||||
}
|
||||
|
||||
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto system_button{rp.PopEnum<SystemButtonType>()};
|
||||
@@ -1566,19 +1385,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
switch (system.GetAppletManager().GetCurrentAppletId()) {
|
||||
case Applets::AppletId::Cabinet:
|
||||
PushInShowCabinetData();
|
||||
break;
|
||||
case Applets::AppletId::MiiEdit:
|
||||
PushInShowMiiEditData();
|
||||
break;
|
||||
case Applets::AppletId::PhotoViewer:
|
||||
PushInShowAlbum();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
PushInShowMiiEditData();
|
||||
}
|
||||
|
||||
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
|
||||
@@ -1624,7 +1431,7 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
const LibraryAppletInfo applet_info{
|
||||
.applet_id = system.GetAppletManager().GetCurrentAppletId(),
|
||||
.applet_id = Applets::AppletId::MiiEdit,
|
||||
.library_applet_mode = Applets::LibraryAppletMode::AllForeground,
|
||||
};
|
||||
|
||||
@@ -1652,52 +1459,6 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext&
|
||||
rb.PushRaw(applet_info);
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowAlbum() {
|
||||
const Applets::CommonArguments arguments{
|
||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||
.size = Applets::CommonArgumentSize::Version3,
|
||||
.library_version = 1,
|
||||
.theme_color = Applets::ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data{2};
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
queue_data.emplace_back(std::move(argument_data));
|
||||
queue_data.emplace_back(std::move(settings_data));
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
|
||||
const Applets::CommonArguments arguments{
|
||||
.arguments_version = Applets::CommonArgumentVersion::Version3,
|
||||
.size = Applets::CommonArgumentSize::Version3,
|
||||
.library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1),
|
||||
.theme_color = Applets::ThemeColor::BasicBlack,
|
||||
.play_startup_sound = true,
|
||||
.system_tick = system.CoreTiming().GetClockTicks(),
|
||||
};
|
||||
|
||||
const Applets::StartParamForAmiiboSettings amiibo_settings{
|
||||
.param_1 = 0,
|
||||
.applet_mode = system.GetAppletManager().GetCabinetMode(),
|
||||
.flags = Applets::CabinetFlags::None,
|
||||
.amiibo_settings_1 = 0,
|
||||
.device_handle = 0,
|
||||
.tag_info{},
|
||||
.register_info{},
|
||||
.amiibo_settings_3{},
|
||||
};
|
||||
|
||||
std::vector<u8> argument_data(sizeof(arguments));
|
||||
std::vector<u8> settings_data(sizeof(amiibo_settings));
|
||||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
|
||||
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
|
||||
queue_data.emplace_back(std::move(argument_data));
|
||||
queue_data.emplace_back(std::move(settings_data));
|
||||
}
|
||||
|
||||
void ILibraryAppletSelfAccessor::PushInShowMiiEditData() {
|
||||
struct MiiEditV3 {
|
||||
Applets::MiiEditAppletInputCommon common;
|
||||
@@ -2474,7 +2235,7 @@ void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
|
||||
const auto applet_id = system.GetAppletManager().GetCurrentAppletId();
|
||||
const auto applet_id = Applets::AppletId::MiiEdit;
|
||||
const auto applet_mode = Applets::LibraryAppletMode::AllForeground;
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
||||
@@ -2495,5 +2256,4 @@ void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx)
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -122,10 +122,7 @@ public:
|
||||
~IDisplayController() override;
|
||||
|
||||
private:
|
||||
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
|
||||
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
|
||||
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
|
||||
@@ -153,13 +150,9 @@ private:
|
||||
void SetRestartMessageEnabled(HLERequestContext& ctx);
|
||||
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
|
||||
void SetAlbumImageOrientation(HLERequestContext& ctx);
|
||||
void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
|
||||
void GetSystemSharedBufferHandle(HLERequestContext& ctx);
|
||||
void GetSystemSharedLayerHandle(HLERequestContext& ctx);
|
||||
void CreateManagedDisplayLayer(HLERequestContext& ctx);
|
||||
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
|
||||
void SetHandlesRequestToDisplay(HLERequestContext& ctx);
|
||||
void ApproveToDisplay(HLERequestContext& ctx);
|
||||
void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
|
||||
void ReportUserIsActive(HLERequestContext& ctx);
|
||||
@@ -171,8 +164,6 @@ private:
|
||||
void SaveCurrentScreenshot(HLERequestContext& ctx);
|
||||
void SetRecordVolumeMuted(HLERequestContext& ctx);
|
||||
|
||||
Result EnsureBufferSharingEnabled();
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
Enable = 1,
|
||||
@@ -188,30 +179,10 @@ private:
|
||||
|
||||
u32 idle_time_detection_extension = 0;
|
||||
u64 num_fatal_sections_entered = 0;
|
||||
u64 system_shared_buffer_id = 0;
|
||||
u64 system_shared_layer_id = 0;
|
||||
bool is_auto_sleep_disabled = false;
|
||||
bool buffer_sharing_enabled = false;
|
||||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
||||
};
|
||||
|
||||
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
|
||||
public:
|
||||
explicit ILockAccessor(Core::System& system_);
|
||||
~ILockAccessor() override;
|
||||
|
||||
private:
|
||||
void TryLock(HLERequestContext& ctx);
|
||||
void Unlock(HLERequestContext& ctx);
|
||||
void GetEvent(HLERequestContext& ctx);
|
||||
void IsLocked(HLERequestContext& ctx);
|
||||
|
||||
bool is_locked{};
|
||||
|
||||
Kernel::KEvent* lock_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
public:
|
||||
explicit ICommonStateGetter(Core::System& system_,
|
||||
@@ -252,9 +223,6 @@ private:
|
||||
void GetEventHandle(HLERequestContext& ctx);
|
||||
void ReceiveMessage(HLERequestContext& ctx);
|
||||
void GetCurrentFocusState(HLERequestContext& ctx);
|
||||
void RequestToAcquireSleepLock(HLERequestContext& ctx);
|
||||
void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
|
||||
void GetReaderLockAccessorEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
|
||||
void GetOperationMode(HLERequestContext& ctx);
|
||||
void GetPerformanceMode(HLERequestContext& ctx);
|
||||
@@ -266,15 +234,12 @@ private:
|
||||
void EndVrModeEx(HLERequestContext& ctx);
|
||||
void GetDefaultDisplayResolution(HLERequestContext& ctx);
|
||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||
void GetBuiltInDisplayType(HLERequestContext& ctx);
|
||||
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
|
||||
void GetSettingsPlatformRegion(HLERequestContext& ctx);
|
||||
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
bool vr_mode_state{};
|
||||
Kernel::KEvent* sleep_lock_event;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
};
|
||||
|
||||
class IStorageImpl {
|
||||
@@ -346,8 +311,6 @@ private:
|
||||
void ExitProcessAndReturn(HLERequestContext& ctx);
|
||||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
|
||||
|
||||
void PushInShowAlbum();
|
||||
void PushInShowCabinetData();
|
||||
void PushInShowMiiEditData();
|
||||
|
||||
std::deque<std::vector<u8>> queue_data;
|
||||
|
||||
@@ -28,8 +28,8 @@ public:
|
||||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
|
||||
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
|
||||
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
|
||||
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
|
||||
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
|
||||
{22, nullptr, "GetHomeMenuFunctions"},
|
||||
{23, nullptr, "GetGlobalStateController"},
|
||||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -110,22 +110,6 @@ private:
|
||||
rb.PushIpcInterface<IAppletCommonFunctions>(system);
|
||||
}
|
||||
|
||||
void GetHomeMenuFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IHomeMenuFunctions>(system);
|
||||
}
|
||||
|
||||
void GetGlobalStateController(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGlobalStateController>(system);
|
||||
}
|
||||
|
||||
void GetDebugFunctions(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
|
||||
@@ -29,15 +29,6 @@ enum class CabinetAppletVersion : u32 {
|
||||
Version1 = 0x1,
|
||||
};
|
||||
|
||||
enum class CabinetFlags : u8 {
|
||||
None = 0,
|
||||
DeviceHandle = 1 << 0,
|
||||
TagInfo = 1 << 1,
|
||||
RegisterInfo = 1 << 2,
|
||||
All = DeviceHandle | TagInfo | RegisterInfo,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(CabinetFlags)
|
||||
|
||||
enum class CabinetResult : u8 {
|
||||
Cancel = 0,
|
||||
TagInfo = 1 << 1,
|
||||
@@ -60,7 +51,7 @@ static_assert(sizeof(AmiiboSettingsStartParam) == 0x30,
|
||||
struct StartParamForAmiiboSettings {
|
||||
u8 param_1;
|
||||
Service::NFP::CabinetMode applet_mode;
|
||||
CabinetFlags flags;
|
||||
u8 flags;
|
||||
u8 amiibo_settings_1;
|
||||
u64 device_handle;
|
||||
Service::NFP::TagInfo tag_info;
|
||||
|
||||
@@ -138,10 +138,6 @@ void Error::Initialize() {
|
||||
CopyArgumentData(data, args->application_error);
|
||||
error_code = Result(args->application_error.error_code);
|
||||
break;
|
||||
case ErrorAppletMode::ShowErrorPctl:
|
||||
CopyArgumentData(data, args->error_record);
|
||||
error_code = Decode64BitError(args->error_record.error_code_64);
|
||||
break;
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
CopyArgumentData(data, args->error_record);
|
||||
error_code = Decode64BitError(args->error_record.error_code_64);
|
||||
@@ -195,7 +191,6 @@ void Error::Execute() {
|
||||
frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
|
||||
break;
|
||||
}
|
||||
case ErrorAppletMode::ShowErrorPctl:
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
reporter.SaveErrorReport(title_id, error_code,
|
||||
fmt::format("{:016X}", args->error_record.posix_time));
|
||||
|
||||
@@ -223,9 +223,9 @@ void StubApplet::Initialize() {
|
||||
|
||||
const auto data = broker.PeekDataToAppletForDebug();
|
||||
system.GetReporter().SaveUnimplementedAppletReport(
|
||||
static_cast<u32>(id), static_cast<u32>(common_args.arguments_version),
|
||||
common_args.library_version, static_cast<u32>(common_args.theme_color),
|
||||
common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive);
|
||||
static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
|
||||
common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
|
||||
data.normal, data.interactive);
|
||||
|
||||
LogCurrentStorage(broker, "Initialize");
|
||||
}
|
||||
|
||||
@@ -199,14 +199,6 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
|
||||
return frontend;
|
||||
}
|
||||
|
||||
NFP::CabinetMode AppletManager::GetCabinetMode() const {
|
||||
return cabinet_mode;
|
||||
}
|
||||
|
||||
AppletId AppletManager::GetCurrentAppletId() const {
|
||||
return current_applet_id;
|
||||
}
|
||||
|
||||
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||
if (set.cabinet != nullptr) {
|
||||
frontend.cabinet = std::move(set.cabinet);
|
||||
@@ -245,14 +237,6 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||
}
|
||||
}
|
||||
|
||||
void AppletManager::SetCabinetMode(NFP::CabinetMode mode) {
|
||||
cabinet_mode = mode;
|
||||
}
|
||||
|
||||
void AppletManager::SetCurrentAppletId(AppletId applet_id) {
|
||||
current_applet_id = applet_id;
|
||||
}
|
||||
|
||||
void AppletManager::SetDefaultAppletFrontendSet() {
|
||||
ClearAll();
|
||||
SetDefaultAppletsIfMissing();
|
||||
|
||||
@@ -34,10 +34,6 @@ class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service::NFP {
|
||||
enum class CabinetMode : u8;
|
||||
} // namespace Service::NFP
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorage;
|
||||
@@ -45,8 +41,6 @@ class IStorage;
|
||||
namespace Applets {
|
||||
|
||||
enum class AppletId : u32 {
|
||||
None = 0x00,
|
||||
Application = 0x01,
|
||||
OverlayDisplay = 0x02,
|
||||
QLaunch = 0x03,
|
||||
Starter = 0x04,
|
||||
@@ -77,32 +71,6 @@ enum class LibraryAppletMode : u32 {
|
||||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
enum class CommonArgumentVersion : u32 {
|
||||
Version0,
|
||||
Version1,
|
||||
Version2,
|
||||
Version3,
|
||||
};
|
||||
|
||||
enum class CommonArgumentSize : u32 {
|
||||
Version3 = 0x20,
|
||||
};
|
||||
|
||||
enum class ThemeColor : u32 {
|
||||
BasicWhite = 0,
|
||||
BasicBlack = 3,
|
||||
};
|
||||
|
||||
struct CommonArguments {
|
||||
CommonArgumentVersion arguments_version;
|
||||
CommonArgumentSize size;
|
||||
u32 library_version;
|
||||
ThemeColor theme_color;
|
||||
bool play_startup_sound;
|
||||
u64_le system_tick;
|
||||
};
|
||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||
|
||||
class AppletDataBroker final {
|
||||
public:
|
||||
explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
|
||||
@@ -193,6 +161,16 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
struct CommonArguments {
|
||||
u32_le arguments_version;
|
||||
u32_le size;
|
||||
u32_le library_version;
|
||||
u32_le theme_color;
|
||||
bool play_startup_sound;
|
||||
u64_le system_tick;
|
||||
};
|
||||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
|
||||
|
||||
CommonArguments common_args{};
|
||||
AppletDataBroker broker;
|
||||
LibraryAppletMode applet_mode;
|
||||
@@ -241,12 +219,8 @@ public:
|
||||
~AppletManager();
|
||||
|
||||
const AppletFrontendSet& GetAppletFrontendSet() const;
|
||||
NFP::CabinetMode GetCabinetMode() const;
|
||||
AppletId GetCurrentAppletId() const;
|
||||
|
||||
void SetAppletFrontendSet(AppletFrontendSet set);
|
||||
void SetCabinetMode(NFP::CabinetMode mode);
|
||||
void SetCurrentAppletId(AppletId applet_id);
|
||||
void SetDefaultAppletFrontendSet();
|
||||
void SetDefaultAppletsIfMissing();
|
||||
void ClearAll();
|
||||
@@ -254,9 +228,6 @@ public:
|
||||
std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
|
||||
|
||||
private:
|
||||
AppletId current_applet_id{};
|
||||
NFP::CabinetMode cabinet_mode{};
|
||||
|
||||
AppletFrontendSet frontend;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/caps/caps_a.h"
|
||||
#include "core/hle/service/caps/caps_c.h"
|
||||
#include "core/hle/service/caps/caps_manager.h"
|
||||
#include "core/hle/service/caps/caps_sc.h"
|
||||
#include "core/hle/service/caps/caps_ss.h"
|
||||
#include "core/hle/service/caps/caps_su.h"
|
||||
@@ -16,21 +15,13 @@ namespace Service::Capture {
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
auto album_manager = std::make_shared<AlbumManager>();
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:a", std::make_shared<IAlbumAccessorService>(system, album_manager));
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:c", std::make_shared<IAlbumControlService>(system, album_manager));
|
||||
server_manager->RegisterNamedService(
|
||||
"caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
|
||||
|
||||
server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system));
|
||||
server_manager->RegisterNamedService("caps:sc",
|
||||
std::make_shared<IScreenShotControlService>(system));
|
||||
server_manager->RegisterNamedService("caps:su",
|
||||
std::make_shared<IScreenShotApplicationService>(system));
|
||||
|
||||
server_manager->RegisterNamedService("caps:a", std::make_shared<CAPS_A>(system));
|
||||
server_manager->RegisterNamedService("caps:c", std::make_shared<CAPS_C>(system));
|
||||
server_manager->RegisterNamedService("caps:u", std::make_shared<CAPS_U>(system));
|
||||
server_manager->RegisterNamedService("caps:sc", std::make_shared<CAPS_SC>(system));
|
||||
server_manager->RegisterNamedService("caps:ss", std::make_shared<CAPS_SS>(system));
|
||||
server_manager->RegisterNamedService("caps:su", std::make_shared<CAPS_SU>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user