Compare commits

...

63 Commits

Author SHA1 Message Date
4e5a7c0ee6 Android #98 2023-10-12 00:57:36 +00:00
da6824d9fd Merge pull request #11720 from lat9nq/dbg-syms
ci/linux: Upload separated debug symbols
2023-10-11 17:55:17 -04:00
b36f45b239 Merge pull request #11740 from german77/shorcuts
yuzu: Save multiple resolutions per icon
2023-10-11 17:55:08 -04:00
07ae6659e7 Merge pull request #11744 from Kelebek1/no_res_no_rescaled
Do not set rescaled flag when rescaling is disabled
2023-10-11 17:54:59 -04:00
880b004321 Merge pull request #11750 from lat9nq/2022g
externals/tzdb_to_nx: Update to 221202
2023-10-11 17:54:50 -04:00
21ebe3e462 externals/tzdb_to_nx: Update to 221202
This updates us to an eggert/tz commit downstream of 2022g that compiles. This
seems to be the revision Nintendo is using for 17.0.0, if the data checksums
are anything to go off of.
2023-10-11 16:42:31 -04:00
84b0e29b56 Merge pull request #11734 from Kelebek1/device_local_buffer_alloc
Do not allocate DeviceLocal buffers as mapped
2023-10-11 09:24:28 -04:00
5ecdcfa334 Merge pull request #11735 from Kelebek1/clear_command_buffer_post_dsp
Clear DSP buffer after each execution
2023-10-11 09:24:16 -04:00
5f4857691e Merge pull request #11683 from Kelebek1/do_not_sync_on_written_buffer
Do not double sync written buffers, move mark written to binding
2023-10-11 09:24:05 -04:00
b50ce645ac Merge pull request #11144 from flodavid/master
Enable controller interaction in Controller Applet
2023-10-11 09:23:52 -04:00
b6d19329ac Merge pull request #11743 from Squall-Leonhart/IFREMOVED
Fix mistaken usage of info.block instead of level_info.block
2023-10-11 11:56:47 +02:00
8c769b71a1 Do not set rescaled flag when rescaling is disabled 2023-10-11 10:29:19 +01:00
9512992fe2 Fix mistaken usage of info.block instead of level_info.block
Fixed an error on my part, in the last change I had mistakenly passed unadjusted block info into FullUploadSwizzles and UnswizzleImage

Revert (my mistaken changing of) the construction of SwizzleParameters in UnswizzleImage and FullUploadSwizzles to use level_info.block instead of info.block. This ensures that the block information used in the swizzling process is correctly adjusted for each mip level.
2023-10-11 19:12:33 +11:00
6b10f04322 yuzu: Save multiple resolutions per icon 2023-10-10 17:24:49 -06:00
c206a04747 ci/linux: Fix find parameter order
Co-authored-by: liamwhite <liamwhite@users.noreply.github.com>
2023-10-10 13:50:50 -04:00
ec6ddaf766 Clear DSP buffer after each execution 2023-10-10 18:22:08 +01:00
36ea7565fa Merge pull request #11534 from Squall-Leonhart/IFREMOVED
Partial revert of #10433 (Texture Cache Util: Fix block depth adjustment on slices)
2023-10-10 12:44:48 -04:00
00b0938f10 ci/linux: Upload separated debug symbols
Creates a new archive with a debug suffix that contains the debug symbols from
compiling yuzu for mainline. The yuzu executable also gets a GNU debug link to the symbols file.
ci/linux: Compile with debug symbols and upload separately

Currently only uploads for yuzu but yuzu-cmd or other future executables can be
added to the for-loop's parameters.
2023-10-10 11:55:55 -04:00
ed58445111 Not not allocate DeviceLocal buffers as mapped 2023-10-10 12:49:07 +01:00
b28b05e2aa Merge pull request #11718 from liamwhite/arm64-native-clock
common: add arm64 native clock
2023-10-10 11:48:06 +02:00
8151a4d301 Merge pull request #11650 from german77/lle_album
service: am: Add support for LLE Album Applet
2023-10-10 11:47:13 +02:00
8ac8d703b9 Merge pull request #11686 from liamwhite/trmem
kernel: implement transfer memory
2023-10-10 11:45:56 +02:00
1c1959eaeb Merge pull request #11716 from Squall-Leonhart/Z327444
add Z32, FLOAT, UINT, UINT, UINT, LINEAR to format lookup table
2023-10-08 17:12:00 -04:00
c0d152affa Merge pull request #11705 from FearlessTobi/windows-sc
yuzu: Add desktop shortcut support for Windows (continuation of #11344)
2023-10-08 17:11:52 -04:00
85d99f873f Merge pull request #10519 from mdmrk/master
yuzu-qt: Track play time
2023-10-08 17:11:34 -04:00
21bc2c14bc common: add arm64 native clock 2023-10-08 12:54:23 -04:00
54fa1115a6 add Z32, FLOAT, UINT, UINT, UINT, LINEAR to format lookup table
Should fix and close #11711
2023-10-09 02:13:17 +11:00
8347e5cdb9 service: caps: Implement album manager and reorganize service 2023-10-07 20:57:20 -06:00
dac53b4ba0 externals: stb: Split library into cpp file 2023-10-07 20:57:19 -06:00
0bb7990c49 service: Stub multiple functions to increase stability of album applet 2023-10-07 20:57:10 -06:00
9ef9ca0927 yuzu: Add desktop shortcut support for Windows
Allows creating desktop shortcuts with icons for yuzu games.

Co-Authored-By: Jeroen van Schijndel <13182141+roenyroeny@users.noreply.github.com>
2023-10-07 21:24:11 -04:00
bd42bba71c Merge pull request #11656 from liamwhite/recreate-surface-automatically
vk_present_manager: recreate surface on any surface loss
2023-10-07 12:49:54 -04:00
a27f94830a Merge pull request #11677 from Squall-Leonhart/D32FTOABGR8
Implements D32_Float to A8B8G8R8_UNORM format copy
2023-10-07 12:49:48 -04:00
bd6f9f1d91 Merge pull request #11630 from Kelebek1/clear_stencil_requires_depth_test
Enable depth test on depthstencil clear path
2023-10-07 12:49:37 -04:00
bf15aa093c Merge pull request #11639 from liamwhite/no-program-id-change
loader: don't reassign program ID on npdm reparse
2023-10-07 12:49:32 -04:00
0e9b839b6f Merge pull request #11648 from liamwhite/unicode-nonsense
gdbserver: use numeric character references for unicode
2023-10-07 12:49:27 -04:00
15a5bdd979 Merge pull request #11544 from Kelebek1/reduce_stream_buffer_renderdoc
Allow GPUs without rebar to open multiple RenderDoc captures
2023-10-07 12:49:19 -04:00
fc4cde7513 Merge pull request #11669 from german77/settings2
yuzu: Fix custom rtc and mute audio settings
2023-10-07 10:55:21 -04:00
ff3859d482 Merge pull request #11688 from Kelebek1/x8d42
Implement X8_D24 pixel format
2023-10-07 10:55:14 -04:00
10de8f2c60 Merge pull request #11684 from Kelebek1/disable_push_descriptor_maxwell
Disable push descriptor for Pascal and older nVidia architectures
2023-10-07 10:54:52 -04:00
51b89fddd0 update shader to confirmed format copy 2023-10-07 18:28:09 +11:00
f585dec48d Allow GPUs without rebar to open multiple RenderDoc captures 2023-10-06 07:52:06 +01:00
ad1a9f3d3a Implement X8_D24 format 2023-10-06 00:58:30 +01:00
e797a917a9 kernel: implement transfer memory 2023-10-04 22:32:27 -04:00
71044f6def Rework nvidia architecture detection, disable push descriptor for Pascal and older 2023-10-05 03:13:42 +01:00
a764f49910 Mark a buffer GPU modified after the buffers are confirmed, do not double synch them 2023-10-05 00:19:11 +01:00
a17cde7b2c lets not convert depth to greyscale since this makes the exhaust and tire smoke light gray/white
tiresmoke should be a darker gray.
2023-10-05 03:14:53 +11:00
a84c928827 Fix CI Formatting check 2023-10-04 19:12:08 +11:00
9568d3bc60 Implements D32_Float to A8B8G8R8_UNORM format copy
Corrects some visual issues in games such as Disney SpeedStorm
2023-10-04 19:07:05 +11:00
0fe935a5de core: Update clocks when settings are saved 2023-10-03 20:20:26 -06:00
c84c35ac74 yuzu: Fix mute when in background setting 2023-10-03 20:12:06 -06:00
b32940d3ea vk_present_manager: recreate surface on any surface loss 2023-10-02 19:07:18 -04:00
c334959440 service: caps: Partially implement IAlbumAccessorService 2023-10-02 12:38:03 -06:00
2fa53ec1d9 yuzu: Allow to launch album applet from firmware 2023-10-02 11:29:12 -06:00
e37ad99f22 externals: Add stb_image and stb_image_resize 2023-10-02 11:29:12 -06:00
38394f36d7 gdbserver: use numeric character references for unicode 2023-10-01 19:22:08 -04:00
2f0db2708c loader: don't reassign program ID on npdm reparse 2023-09-30 11:35:42 -04:00
1a246bf135 Enable depth test on stencil clear path 2023-09-28 21:19:51 +01:00
02b897ce27 Reuse part of my previous idea to to use num_levels to check within AdjustMipBlockSize
The partial revert was not enough for Tsukihime, this might do the trick
2023-09-20 03:27:13 +10:00
79f0202045 Partial revert of #10433
The If block in this change was causing some 2D textures to be treated as if their mip 0 was a 3D Slice, this could be ascertained as the same texture viewed from different distances would render fine, but then close up would look like a decoding failure.

It also resulted in some 3D ASTC textures not being scaled appropriate leading to broken graphical effects such as the jagged TOTK recall animation being a circle, as the If block was only accepting the image based on its original info without any adjustments applied.
2023-09-18 23:28:53 +10:00
667ec28697 Address review comments 2023-08-27 19:45:25 -04:00
5464423667 yuzu-qt: Track play time 2023-08-26 22:20:19 -04:00
b881949b6d yuzu: Enable controller interaction in Controller Applet 2023-07-25 19:03:12 +02:00
111 changed files with 13473 additions and 460 deletions

View File

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

View File

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

View File

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

View File

@ -1,3 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

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

View File

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

View File

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

View File

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

7529
externals/stb/stb_image.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

772
externals/stb/stb_image.h vendored Normal file
View File

@ -0,0 +1,772 @@
// 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.
------------------------------------------------------------------------------
*/

2282
externals/stb/stb_image_resize.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

426
externals/stb/stb_image_resize.h vendored Normal file
View File

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

View File

@ -218,7 +218,6 @@ public:
return;
}
m_window->OnSurfaceChanged(m_native_window);
m_system.Renderer().NotifySurfaceChanged();
}
void ConfigureFilesystemProvider(const std::string& filepath) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -135,6 +135,11 @@ 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 =

View File

@ -38,6 +38,7 @@ 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);

View File

@ -10,6 +10,10 @@
#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 {
@ -53,7 +57,7 @@ private:
};
std::unique_ptr<WallClock> CreateOptimalClock() {
#ifdef ARCHITECTURE_x86_64
#if defined(ARCHITECTURE_x86_64)
const auto& caps = GetCPUCaps();
if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) {
@ -64,6 +68,8 @@ std::unique_ptr<WallClock> CreateOptimalClock() {
// - Is not more precise than 1 GHz (1ns resolution)
return std::make_unique<StandardWallClock>();
}
#elif defined(ARCHITECTURE_arm64) && defined(__linux__)
return std::make_unique<Arm64::NativeClock>();
#else
return std::make_unique<StandardWallClock>();
#endif

View File

@ -466,14 +466,18 @@ 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_u.cpp
hle/service/caps/caps_u.h
hle/service/caps/caps_manager.cpp
hle/service/caps/caps_manager.h
hle/service/caps/caps_result.h
hle/service/caps/caps_sc.cpp
hle/service/caps/caps_sc.h
hle/service/caps/caps_ss.cpp
hle/service/caps/caps_ss.h
hle/service/caps/caps_su.cpp
hle/service/caps/caps_su.h
hle/service/caps/caps_types.h
hle/service/caps/caps_u.cpp
hle/service/caps/caps_u.h
hle/service/erpt/erpt.cpp
hle/service/erpt/erpt.h
hle/service/es/es.cpp

View File

@ -1078,6 +1078,10 @@ 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();
}
}

View File

@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <atomic>
#include <codecvt>
#include <locale>
#include <numeric>
#include <optional>
#include <thread>
@ -12,6 +14,7 @@
#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"
@ -68,10 +71,16 @@ 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 (char c : data) {
for (char32_t c : converted) {
switch (c) {
case '&':
escaped += "&amp;";
@ -86,7 +95,11 @@ static std::string EscapeXML(std::string_view data) {
escaped += "&gt;";
break;
default:
escaped += c;
if (c > 0x7f) {
escaped += fmt::format("&#{};", static_cast<u32>(c));
} else {
escaped += static_cast<char>(c);
}
break;
}
}

View File

@ -5,6 +5,7 @@
#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"
@ -95,6 +96,13 @@ 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;

View File

@ -56,6 +56,7 @@ 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,

View File

@ -2949,6 +2949,23 @@ 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,

View File

@ -104,6 +104,9 @@ 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,

View File

@ -1,6 +1,7 @@
// 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"
@ -9,28 +10,50 @@
namespace Kernel {
KTransferMemory::KTransferMemory(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer{kernel} {}
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{kernel} {}
KTransferMemory::~KTransferMemory() = default;
Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size,
Svc::MemoryPermission owner_perm) {
Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
Svc::MemoryPermission own_perm) {
// Set members.
m_owner = GetCurrentProcessPointer(m_kernel);
// TODO(bunnei): Lock for transfer memory
// 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)));
// Set remaining tracking members.
m_owner->Open();
m_owner_perm = owner_perm;
m_address = address;
m_size = size;
m_owner_perm = own_perm;
m_address = addr;
m_is_initialized = true;
m_is_mapped = false;
// We succeeded.
pg_guard.Cancel();
R_SUCCEED();
}
void KTransferMemory::Finalize() {}
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::PostDestroy(uintptr_t arg) {
KProcess* owner = reinterpret_cast<KProcess*>(arg);
@ -38,4 +61,54 @@ void KTransferMemory::PostDestroy(uintptr_t arg) {
owner->Close();
}
Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Validate the permission.
R_UNLESS(m_owner_perm == map_perm, ResultInvalidState);
// Lock ourselves.
KScopedLightLock lk(m_lock);
// Ensure we're not already mapped.
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered
: KMemoryState::SharedTransfered;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
address, *m_page_group, state, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
m_is_mapped = true;
R_SUCCEED();
}
Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
// Lock ourselves.
KScopedLightLock lk(m_lock);
// Unmap the memory.
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
? KMemoryState::Transfered
: KMemoryState::SharedTransfered;
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
// Mark ourselves as unmapped.
ASSERT(m_is_mapped);
m_is_mapped = false;
R_SUCCEED();
}
size_t KTransferMemory::GetSize() const {
return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0;
}
} // namespace Kernel

View File

@ -3,6 +3,9 @@
#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"
@ -48,16 +51,19 @@ public:
return m_address;
}
size_t GetSize() const {
return m_is_initialized ? m_size : 0;
}
size_t GetSize() const;
Result Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm);
Result Unmap(KProcessAddress address, size_t size);
private:
std::optional<KPageGroup> m_page_group{};
KProcess* m_owner{};
KProcessAddress m_address{};
KLightLock m_lock;
Svc::MemoryPermission m_owner_perm{};
size_t m_size{};
bool m_is_initialized{};
bool m_is_mapped{};
};
} // namespace Kernel

View File

@ -71,15 +71,59 @@ 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 owner_perm) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
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();
}
Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address,
uint64_t size) {
UNIMPLEMENTED();
R_THROW(ResultNotImplemented);
// 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();
}
Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,

View File

@ -31,7 +31,7 @@
#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.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/ns.h"
@ -764,6 +764,66 @@ 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_)},
@ -787,7 +847,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, nullptr, "GetReaderLockAccessorEx"},
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
{32, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"},
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
@ -805,7 +865,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"},
{68, nullptr, "GetBuiltInDisplayType"},
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
@ -886,6 +946,18 @@ void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
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");
@ -970,6 +1042,14 @@ 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>()};
@ -1493,6 +1573,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
case Applets::AppletId::MiiEdit:
PushInShowMiiEditData();
break;
case Applets::AppletId::PhotoViewer:
PushInShowAlbum();
break;
default:
break;
}
@ -1569,6 +1652,23 @@ 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,

View File

@ -195,6 +195,23 @@ private:
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_,
@ -237,6 +254,7 @@ private:
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);
@ -248,6 +266,7 @@ 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);
@ -327,6 +346,7 @@ private:
void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void PushInShowAlbum();
void PushInShowCabinetData();
void PushInShowMiiEditData();

View File

@ -28,8 +28,8 @@ public:
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
{22, nullptr, "GetHomeMenuFunctions"},
{23, nullptr, "GetGlobalStateController"},
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
};
// clang-format on
@ -110,6 +110,22 @@ 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");

View File

@ -138,6 +138,10 @@ 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);
@ -191,6 +195,7 @@ 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));

View File

@ -4,6 +4,7 @@
#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"
@ -15,13 +16,21 @@ 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));
}

View File

@ -3,93 +3,12 @@
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Core {
class System;
}
namespace Service::SM {
class ServiceManager;
}
namespace Service::Capture {
enum class AlbumImageOrientation {
Orientation0 = 0,
Orientation1 = 1,
Orientation2 = 2,
Orientation3 = 3,
};
enum class AlbumReportOption : s32 {
Disable = 0,
Enable = 1,
};
enum class ContentType : u8 {
Screenshot = 0,
Movie = 1,
ExtraMovie = 3,
};
enum class AlbumStorage : u8 {
NAND = 0,
SD = 1,
};
struct AlbumFileDateTime {
s16 year{};
s8 month{};
s8 day{};
s8 hour{};
s8 minute{};
s8 second{};
s8 uid{};
};
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
struct AlbumEntry {
u64 size{};
u64 application_id{};
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(6);
};
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
struct AlbumFileEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{1}; // Set to 1 on official SW
};
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
struct ApplicationAlbumEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{1}; // Set to 1 on official SW
};
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
struct ApplicationAlbumFileEntry {
ApplicationAlbumEntry entry{};
AlbumFileDateTime datetime{};
u64 unknown{};
};
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
"ApplicationAlbumFileEntry has incorrect size.");
void LoopProcess(Core::System& system);
} // namespace Service::Capture

View File

@ -1,40 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/caps/caps_a.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> {
public:
explicit IAlbumAccessorSession(Core::System& system_)
: ServiceFramework{system_, "IAlbumAccessorSession"} {
// clang-format off
static const FunctionInfo functions[] = {
{2001, nullptr, "OpenAlbumMovieReadStream"},
{2002, nullptr, "CloseAlbumMovieReadStream"},
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
{2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
{2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
{2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
};
// clang-format on
RegisterHandlers(functions);
}
};
CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
IAlbumAccessorService::IAlbumAccessorService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager)
: ServiceFramework{system_, "caps:a"}, manager{album_manager} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAlbumFileCount"},
{1, nullptr, "GetAlbumFileList"},
{2, nullptr, "LoadAlbumFile"},
{3, nullptr, "DeleteAlbumFile"},
{3, &IAlbumAccessorService::DeleteAlbumFile, "DeleteAlbumFile"},
{4, nullptr, "StorageCopyAlbumFile"},
{5, nullptr, "IsAlbumMounted"},
{5, &IAlbumAccessorService::IsAlbumMounted, "IsAlbumMounted"},
{6, nullptr, "GetAlbumUsage"},
{7, nullptr, "GetAlbumFileSize"},
{8, nullptr, "LoadAlbumFileThumbnail"},
@ -47,18 +33,18 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
{15, nullptr, "GetAlbumUsage3"},
{16, nullptr, "GetAlbumMountResult"},
{17, nullptr, "GetAlbumUsage16"},
{18, nullptr, "Unknown18"},
{18, &IAlbumAccessorService::Unknown18, "Unknown18"},
{19, nullptr, "Unknown19"},
{100, nullptr, "GetAlbumFileCountEx0"},
{101, nullptr, "GetAlbumFileListEx0"},
{101, &IAlbumAccessorService::GetAlbumFileListEx0, "GetAlbumFileListEx0"},
{202, nullptr, "SaveEditedScreenShot"},
{301, nullptr, "GetLastThumbnail"},
{302, nullptr, "GetLastOverlayMovieThumbnail"},
{401, nullptr, "GetAutoSavingStorage"},
{401, &IAlbumAccessorService::GetAutoSavingStorage, "GetAutoSavingStorage"},
{501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
{1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
{1002, nullptr, "LoadAlbumScreenShotImageEx1"},
{1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"},
{1002, &IAlbumAccessorService::LoadAlbumScreenShotImageEx1, "LoadAlbumScreenShotImageEx1"},
{1003, &IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1, "LoadAlbumScreenShotThumbnailImageEx1"},
{8001, nullptr, "ForceAlbumUnmounted"},
{8002, nullptr, "ResetAlbumMountStatus"},
{8011, nullptr, "RefreshAlbumCache"},
@ -74,6 +60,199 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
RegisterHandlers(functions);
}
CAPS_A::~CAPS_A() = default;
IAlbumAccessorService::~IAlbumAccessorService() = default;
void IAlbumAccessorService::DeleteAlbumFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}",
file_id.application_id, file_id.storage, file_id.type);
Result result = manager->DeleteAlbumFile(file_id);
result = TranslateResult(result);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IAlbumAccessorService::IsAlbumMounted(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<AlbumStorage>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
Result result = manager->IsAlbumMounted(storage);
const bool is_mounted = result.IsSuccess();
result = TranslateResult(result);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push<u8>(is_mounted);
}
void IAlbumAccessorService::Unknown18(HLERequestContext& ctx) {
struct UnknownBuffer {
INSERT_PADDING_BYTES(0x10);
};
static_assert(sizeof(UnknownBuffer) == 0x10, "UnknownBuffer is an invalid size");
LOG_WARNING(Service_Capture, "(STUBBED) called");
std::vector<UnknownBuffer> buffer{};
if (!buffer.empty()) {
ctx.WriteBuffer(buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(buffer.size()));
}
void IAlbumAccessorService::GetAlbumFileListEx0(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<AlbumStorage>()};
const auto flags{rp.Pop<u8>()};
const auto album_entry_size{ctx.GetWriteBufferNumElements<AlbumEntry>()};
LOG_INFO(Service_Capture, "called, storage={}, flags={}", storage, flags);
std::vector<AlbumEntry> entries;
Result result = manager->GetAlbumFileList(entries, storage, flags);
result = TranslateResult(result);
entries.resize(std::min(album_entry_size, entries.size()));
if (!entries.empty()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push(entries.size());
}
void IAlbumAccessorService::GetAutoSavingStorage(HLERequestContext& ctx) {
LOG_WARNING(Service_Capture, "(STUBBED) called");
bool is_autosaving{};
Result result = manager->GetAutoSavingStorage(is_autosaving);
result = TranslateResult(result);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push<u8>(is_autosaving);
}
void IAlbumAccessorService::LoadAlbumScreenShotImageEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
const auto image_buffer_size{ctx.GetWriteBufferSize(1)};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
std::vector<u8> image;
LoadAlbumScreenShotImageOutput image_output;
Result result =
manager->LoadAlbumScreenShotImage(image_output, image, file_id, decoder_options);
result = TranslateResult(result);
if (image.size() > image_buffer_size) {
result = ResultWorkMemoryError;
}
if (result.IsSuccess()) {
ctx.WriteBuffer(image_output, 0);
ctx.WriteBuffer(image, 1);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IAlbumAccessorService::LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_id{rp.PopRaw<AlbumFileId>()};
const auto decoder_options{rp.PopRaw<ScreenShotDecodeOption>()};
LOG_INFO(Service_Capture, "called, application_id=0x{:0x}, storage={}, type={}, flags={}",
file_id.application_id, file_id.storage, file_id.type, decoder_options.flags);
std::vector<u8> image(ctx.GetWriteBufferSize(1));
LoadAlbumScreenShotImageOutput image_output;
Result result =
manager->LoadAlbumScreenShotThumbnail(image_output, image, file_id, decoder_options);
result = TranslateResult(result);
if (result.IsSuccess()) {
ctx.WriteBuffer(image_output, 0);
ctx.WriteBuffer(image, 1);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
Result IAlbumAccessorService::TranslateResult(Result in_result) {
if (in_result.IsSuccess()) {
return in_result;
}
if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) {
if (in_result.description - 0x514 < 100) {
return ResultInvalidFileData;
}
if (in_result.description - 0x5dc < 100) {
return ResultInvalidFileData;
}
if (in_result.description - 0x578 < 100) {
if (in_result == ResultFileCountLimit) {
return ResultUnknown22;
}
return ResultUnknown25;
}
if (in_result.raw < ResultUnknown1801.raw) {
if (in_result == ResultUnknown1202) {
return ResultUnknown810;
}
if (in_result == ResultUnknown1203) {
return ResultUnknown810;
}
if (in_result == ResultUnknown1701) {
return ResultUnknown5;
}
} else if (in_result.raw < ResultUnknown1803.raw) {
if (in_result == ResultUnknown1801) {
return ResultUnknown5;
}
if (in_result == ResultUnknown1802) {
return ResultUnknown6;
}
} else {
if (in_result == ResultUnknown1803) {
return ResultUnknown7;
}
if (in_result == ResultUnknown1804) {
return ResultOutOfRange;
}
}
return ResultUnknown1024;
}
if (in_result.module == ErrorModule::FS) {
if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) ||
(((in_result.description - 3000) >> 3) < 0x271)) {
// TODO: Translate FS error
return in_result;
}
}
return in_result;
}
} // namespace Service::Capture

View File

@ -10,11 +10,26 @@ class System;
}
namespace Service::Capture {
class AlbumManager;
class CAPS_A final : public ServiceFramework<CAPS_A> {
class IAlbumAccessorService final : public ServiceFramework<IAlbumAccessorService> {
public:
explicit CAPS_A(Core::System& system_);
~CAPS_A() override;
explicit IAlbumAccessorService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager);
~IAlbumAccessorService() override;
private:
void DeleteAlbumFile(HLERequestContext& ctx);
void IsAlbumMounted(HLERequestContext& ctx);
void Unknown18(HLERequestContext& ctx);
void GetAlbumFileListEx0(HLERequestContext& ctx);
void GetAutoSavingStorage(HLERequestContext& ctx);
void LoadAlbumScreenShotImageEx1(HLERequestContext& ctx);
void LoadAlbumScreenShotThumbnailImageEx1(HLERequestContext& ctx);
Result TranslateResult(Result in_result);
std::shared_ptr<AlbumManager> manager = nullptr;
};
} // namespace Service::Capture

View File

@ -3,53 +3,21 @@
#include "common/logging/log.h"
#include "core/hle/service/caps/caps_c.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> {
public:
explicit IAlbumControlSession(Core::System& system_)
: ServiceFramework{system_, "IAlbumControlSession"} {
// clang-format off
static const FunctionInfo functions[] = {
{2001, nullptr, "OpenAlbumMovieReadStream"},
{2002, nullptr, "CloseAlbumMovieReadStream"},
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
{2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
{2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
{2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
{2401, nullptr, "OpenAlbumMovieWriteStream"},
{2402, nullptr, "FinishAlbumMovieWriteStream"},
{2403, nullptr, "CommitAlbumMovieWriteStream"},
{2404, nullptr, "DiscardAlbumMovieWriteStream"},
{2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"},
{2406, nullptr, "CommitAlbumMovieWriteStreamEx"},
{2411, nullptr, "StartAlbumMovieWriteStreamDataSection"},
{2412, nullptr, "EndAlbumMovieWriteStreamDataSection"},
{2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"},
{2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"},
{2421, nullptr, "ReadDataFromAlbumMovieWriteStream"},
{2422, nullptr, "WriteDataToAlbumMovieWriteStream"},
{2424, nullptr, "WriteMetaToAlbumMovieWriteStream"},
{2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"},
{2433, nullptr, "GetAlbumMovieWriteStreamDataSize"},
{2434, nullptr, "SetAlbumMovieWriteStreamDataSize"},
};
// clang-format on
RegisterHandlers(functions);
}
};
CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
IAlbumControlService::IAlbumControlService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager)
: ServiceFramework{system_, "caps:c"}, manager{album_manager} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "CaptureRawImage"},
{2, nullptr, "CaptureRawImageWithTimeout"},
{33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"},
{33, &IAlbumControlService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{1001, nullptr, "RequestTakingScreenShot"},
{1002, nullptr, "RequestTakingScreenShotWithTimeout"},
{1011, nullptr, "NotifyTakingScreenShotRefused"},
@ -72,9 +40,9 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
RegisterHandlers(functions);
}
CAPS_C::~CAPS_C() = default;
IAlbumControlService::~IAlbumControlService() = default;
void CAPS_C::SetShimLibraryVersion(HLERequestContext& ctx) {
void IAlbumControlService::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};

View File

@ -10,14 +10,18 @@ class System;
}
namespace Service::Capture {
class AlbumManager;
class CAPS_C final : public ServiceFramework<CAPS_C> {
class IAlbumControlService final : public ServiceFramework<IAlbumControlService> {
public:
explicit CAPS_C(Core::System& system_);
~CAPS_C() override;
explicit IAlbumControlService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager);
~IAlbumControlService() override;
private:
void SetShimLibraryVersion(HLERequestContext& ctx);
std::shared_ptr<AlbumManager> manager = nullptr;
};
} // namespace Service::Capture

View File

@ -0,0 +1,342 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <sstream>
#include <stb_image.h>
#include <stb_image_resize.h>
#include "common/fs/file.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_result.h"
namespace Service::Capture {
AlbumManager::AlbumManager() {}
AlbumManager::~AlbumManager() = default;
Result AlbumManager::DeleteAlbumFile(const AlbumFileId& file_id) {
if (file_id.storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
std::filesystem::path path;
const auto result = GetFile(path, file_id);
if (result.IsError()) {
return result;
}
if (!Common::FS::RemoveFile(path)) {
return ResultFileNotFound;
}
return ResultSuccess;
}
Result AlbumManager::IsAlbumMounted(AlbumStorage storage) {
if (storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
is_mounted = true;
if (storage == AlbumStorage::Sd) {
FindScreenshots();
}
return is_mounted ? ResultSuccess : ResultIsNotMounted;
}
Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const {
if (storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
for (auto& [file_id, path] : album_files) {
if (file_id.storage != storage) {
continue;
}
if (out_entries.size() >= SdAlbumFileLimit) {
break;
}
const auto entry_size = Common::FS::GetSize(path);
out_entries.push_back({
.entry_size = entry_size,
.file_id = file_id,
});
}
return ResultSuccess;
}
Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const {
if (!is_mounted) {
return ResultIsNotMounted;
}
for (auto& [file_id, path] : album_files) {
if (file_id.type != contex_type) {
continue;
}
if (file_id.date > start_date) {
continue;
}
if (file_id.date < end_date) {
continue;
}
if (out_entries.size() >= SdAlbumFileLimit) {
break;
}
const auto entry_size = Common::FS::GetSize(path);
ApplicationAlbumFileEntry entry{.entry =
{
.size = entry_size,
.hash{},
.datetime = file_id.date,
.storage = file_id.storage,
.content = contex_type,
.unknown = 1,
},
.datetime = file_id.date,
.unknown = {}};
out_entries.push_back(entry);
}
return ResultSuccess;
}
Result AlbumManager::GetAutoSavingStorage(bool& out_is_autosaving) const {
out_is_autosaving = false;
return ResultSuccess;
}
Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
std::vector<u8>& out_image,
const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const {
if (file_id.storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
out_image_output = {
.width = 1280,
.height = 720,
.attribute =
{
.unknown_0{},
.orientation = AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
},
};
std::filesystem::path path;
const auto result = GetFile(path, file_id);
if (result.IsError()) {
return result;
}
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
+static_cast<int>(out_image_output.height), decoder_options.flags);
}
Result AlbumManager::LoadAlbumScreenShotThumbnail(
LoadAlbumScreenShotImageOutput& out_image_output, std::vector<u8>& out_image,
const AlbumFileId& file_id, const ScreenShotDecodeOption& decoder_options) const {
if (file_id.storage > AlbumStorage::Sd) {
return ResultInvalidStorage;
}
if (!is_mounted) {
return ResultIsNotMounted;
}
out_image_output = {
.width = 320,
.height = 180,
.attribute =
{
.unknown_0{},
.orientation = AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
},
};
std::filesystem::path path;
const auto result = GetFile(path, file_id);
if (result.IsError()) {
return result;
}
out_image.resize(out_image_output.height * out_image_output.width * STBI_rgb_alpha);
return LoadImage(out_image, path, static_cast<int>(out_image_output.width),
+static_cast<int>(out_image_output.height), decoder_options.flags);
}
Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
const auto file = album_files.find(file_id);
if (file == album_files.end()) {
return ResultFileNotFound;
}
out_path = file->second;
return ResultSuccess;
}
void AlbumManager::FindScreenshots() {
is_mounted = false;
album_files.clear();
// TODO: Swap this with a blocking operation.
const auto screenshots_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir);
Common::FS::IterateDirEntries(
screenshots_dir,
[this](const std::filesystem::path& full_path) {
AlbumEntry entry;
if (GetAlbumEntry(entry, full_path).IsError()) {
return true;
}
while (album_files.contains(entry.file_id)) {
if (++entry.file_id.date.unique_id == 0) {
break;
}
}
album_files[entry.file_id] = full_path;
return true;
},
Common::FS::DirEntryFilter::File);
is_mounted = true;
}
Result AlbumManager::GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const {
std::istringstream line_stream(path.filename().string());
std::string date;
std::string application;
std::string time;
// Parse filename to obtain entry properties
std::getline(line_stream, application, '_');
std::getline(line_stream, date, '_');
std::getline(line_stream, time, '_');
std::istringstream date_stream(date);
std::istringstream time_stream(time);
std::string year;
std::string month;
std::string day;
std::string hour;
std::string minute;
std::string second;
std::getline(date_stream, year, '-');
std::getline(date_stream, month, '-');
std::getline(date_stream, day, '-');
std::getline(time_stream, hour, '-');
std::getline(time_stream, minute, '-');
std::getline(time_stream, second, '-');
try {
out_entry = {
.entry_size = 1,
.file_id{
.application_id = static_cast<u64>(std::stoll(application, 0, 16)),
.date =
{
.year = static_cast<u16>(std::stoi(year)),
.month = static_cast<u8>(std::stoi(month)),
.day = static_cast<u8>(std::stoi(day)),
.hour = static_cast<u8>(std::stoi(hour)),
.minute = static_cast<u8>(std::stoi(minute)),
.second = static_cast<u8>(std::stoi(second)),
.unique_id = 0,
},
.storage = AlbumStorage::Sd,
.type = ContentType::Screenshot,
.unknown = 1,
},
};
} catch (const std::invalid_argument&) {
return ResultUnknown;
} catch (const std::out_of_range&) {
return ResultUnknown;
} catch (const std::exception&) {
return ResultUnknown;
}
return ResultSuccess;
}
Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::path& path,
int width, int height, ScreenShotDecoderFlag flag) const {
if (out_image.size() != static_cast<std::size_t>(width * height * STBI_rgb_alpha)) {
return ResultUnknown;
}
const Common::FS::IOFile db_file{path, Common::FS::FileAccessMode::Read,
Common::FS::FileType::BinaryFile};
std::vector<u8> raw_file(db_file.GetSize());
if (db_file.Read(raw_file) != raw_file.size()) {
return ResultUnknown;
}
int filter_flag = STBIR_FILTER_DEFAULT;
int original_width, original_height, color_channels;
const auto dbi_image =
stbi_load_from_memory(raw_file.data(), static_cast<int>(raw_file.size()), &original_width,
&original_height, &color_channels, STBI_rgb_alpha);
if (dbi_image == nullptr) {
return ResultUnknown;
}
switch (flag) {
case ScreenShotDecoderFlag::EnableFancyUpsampling:
filter_flag = STBIR_FILTER_TRIANGLE;
break;
case ScreenShotDecoderFlag::EnableBlockSmoothing:
filter_flag = STBIR_FILTER_BOX;
break;
default:
filter_flag = STBIR_FILTER_DEFAULT;
break;
}
stbir_resize_uint8_srgb(dbi_image, original_width, original_height, 0, out_image.data(), width,
height, 0, STBI_rgb_alpha, 3, filter_flag);
return ResultSuccess;
}
} // namespace Service::Capture

View File

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <unordered_map>
#include "common/fs/fs.h"
#include "core/hle/result.h"
#include "core/hle/service/caps/caps_types.h"
namespace Core {
class System;
}
namespace std {
// Hash used to create lists from AlbumFileId data
template <>
struct hash<Service::Capture::AlbumFileId> {
size_t operator()(const Service::Capture::AlbumFileId& pad_id) const noexcept {
u64 hash_value = (static_cast<u64>(pad_id.date.year) << 8);
hash_value ^= (static_cast<u64>(pad_id.date.month) << 7);
hash_value ^= (static_cast<u64>(pad_id.date.day) << 6);
hash_value ^= (static_cast<u64>(pad_id.date.hour) << 5);
hash_value ^= (static_cast<u64>(pad_id.date.minute) << 4);
hash_value ^= (static_cast<u64>(pad_id.date.second) << 3);
hash_value ^= (static_cast<u64>(pad_id.date.unique_id) << 2);
hash_value ^= (static_cast<u64>(pad_id.storage) << 1);
hash_value ^= static_cast<u64>(pad_id.type);
return static_cast<size_t>(hash_value);
}
};
} // namespace std
namespace Service::Capture {
class AlbumManager {
public:
explicit AlbumManager();
~AlbumManager();
Result DeleteAlbumFile(const AlbumFileId& file_id);
Result IsAlbumMounted(AlbumStorage storage);
Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
u8 flags) const;
Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
ContentType contex_type, AlbumFileDateTime start_date,
AlbumFileDateTime end_date, u64 aruid) const;
Result GetAutoSavingStorage(bool& out_is_autosaving) const;
Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
std::vector<u8>& out_image, const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const;
Result LoadAlbumScreenShotThumbnail(LoadAlbumScreenShotImageOutput& out_image_output,
std::vector<u8>& out_image, const AlbumFileId& file_id,
const ScreenShotDecodeOption& decoder_options) const;
private:
static constexpr std::size_t NandAlbumFileLimit = 1000;
static constexpr std::size_t SdAlbumFileLimit = 10000;
void FindScreenshots();
Result GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const;
Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
int height, ScreenShotDecoderFlag flag) const;
bool is_mounted{};
std::unordered_map<AlbumFileId, std::filesystem::path> album_files;
};
} // namespace Service::Capture

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::Capture {
constexpr Result ResultWorkMemoryError(ErrorModule::Capture, 3);
constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12);
constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);
constexpr Result ResultUnknown22(ErrorModule::Capture, 22);
constexpr Result ResultFileNotFound(ErrorModule::Capture, 23);
constexpr Result ResultInvalidFileData(ErrorModule::Capture, 24);
constexpr Result ResultUnknown25(ErrorModule::Capture, 25);
constexpr Result ResultReadBufferShortage(ErrorModule::Capture, 30);
constexpr Result ResultUnknown810(ErrorModule::Capture, 810);
constexpr Result ResultUnknown1024(ErrorModule::Capture, 1024);
constexpr Result ResultUnknown1202(ErrorModule::Capture, 1202);
constexpr Result ResultUnknown1203(ErrorModule::Capture, 1203);
constexpr Result ResultFileCountLimit(ErrorModule::Capture, 1401);
constexpr Result ResultUnknown1701(ErrorModule::Capture, 1701);
constexpr Result ResultUnknown1801(ErrorModule::Capture, 1801);
constexpr Result ResultUnknown1802(ErrorModule::Capture, 1802);
constexpr Result ResultUnknown1803(ErrorModule::Capture, 1803);
constexpr Result ResultUnknown1804(ErrorModule::Capture, 1804);
} // namespace Service::Capture

View File

@ -5,7 +5,8 @@
namespace Service::Capture {
CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
IScreenShotControlService::IScreenShotControlService(Core::System& system_)
: ServiceFramework{system_, "caps:sc"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "CaptureRawImage"},
@ -34,6 +35,6 @@ CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
RegisterHandlers(functions);
}
CAPS_SC::~CAPS_SC() = default;
IScreenShotControlService::~IScreenShotControlService() = default;
} // namespace Service::Capture

View File

@ -11,10 +11,10 @@ class System;
namespace Service::Capture {
class CAPS_SC final : public ServiceFramework<CAPS_SC> {
class IScreenShotControlService final : public ServiceFramework<IScreenShotControlService> {
public:
explicit CAPS_SC(Core::System& system_);
~CAPS_SC() override;
explicit IScreenShotControlService(Core::System& system_);
~IScreenShotControlService() override;
};
} // namespace Service::Capture

View File

@ -5,7 +5,8 @@
namespace Service::Capture {
CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
IScreenShotService::IScreenShotService(Core::System& system_)
: ServiceFramework{system_, "caps:ss"} {
// clang-format off
static const FunctionInfo functions[] = {
{201, nullptr, "SaveScreenShot"},
@ -21,6 +22,6 @@ CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
RegisterHandlers(functions);
}
CAPS_SS::~CAPS_SS() = default;
IScreenShotService::~IScreenShotService() = default;
} // namespace Service::Capture

View File

@ -11,10 +11,10 @@ class System;
namespace Service::Capture {
class CAPS_SS final : public ServiceFramework<CAPS_SS> {
class IScreenShotService final : public ServiceFramework<IScreenShotService> {
public:
explicit CAPS_SS(Core::System& system_);
~CAPS_SS() override;
explicit IScreenShotService(Core::System& system_);
~IScreenShotService() override;
};
} // namespace Service::Capture

View File

@ -7,10 +7,11 @@
namespace Service::Capture {
CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_)
: ServiceFramework{system_, "caps:su"} {
// clang-format off
static const FunctionInfo functions[] = {
{32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"},
{32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{201, nullptr, "SaveScreenShot"},
{203, nullptr, "SaveScreenShotEx0"},
{205, nullptr, "SaveScreenShotEx1"},
@ -21,9 +22,9 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
RegisterHandlers(functions);
}
CAPS_SU::~CAPS_SU() = default;
IScreenShotApplicationService::~IScreenShotApplicationService() = default;
void CAPS_SU::SetShimLibraryVersion(HLERequestContext& ctx) {
void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};

View File

@ -11,10 +11,10 @@ class System;
namespace Service::Capture {
class CAPS_SU final : public ServiceFramework<CAPS_SU> {
class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
public:
explicit CAPS_SU(Core::System& system_);
~CAPS_SU() override;
explicit IScreenShotApplicationService(Core::System& system_);
~IScreenShotApplicationService() override;
private:
void SetShimLibraryVersion(HLERequestContext& ctx);

View File

@ -0,0 +1,184 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::Capture {
// This is nn::album::ImageOrientation
enum class AlbumImageOrientation {
None,
Rotate90,
Rotate180,
Rotate270,
};
// This is nn::album::AlbumReportOption
enum class AlbumReportOption : s32 {
Disable,
Enable,
};
enum class ContentType : u8 {
Screenshot = 0,
Movie = 1,
ExtraMovie = 3,
};
enum class AlbumStorage : u8 {
Nand,
Sd,
};
enum class ScreenShotDecoderFlag : u64 {
None = 0,
EnableFancyUpsampling = 1 << 0,
EnableBlockSmoothing = 1 << 1,
};
// This is nn::capsrv::AlbumFileDateTime
struct AlbumFileDateTime {
u16 year{};
u8 month{};
u8 day{};
u8 hour{};
u8 minute{};
u8 second{};
u8 unique_id{};
friend constexpr bool operator==(const AlbumFileDateTime&, const AlbumFileDateTime&) = default;
friend constexpr bool operator>(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
if (a.year > b.year) {
return true;
}
if (a.month > b.month) {
return true;
}
if (a.day > b.day) {
return true;
}
if (a.hour > b.hour) {
return true;
}
if (a.minute > b.minute) {
return true;
}
return a.second > b.second;
};
friend constexpr bool operator<(const AlbumFileDateTime& a, const AlbumFileDateTime& b) {
if (a.year < b.year) {
return true;
}
if (a.month < b.month) {
return true;
}
if (a.day < b.day) {
return true;
}
if (a.hour < b.hour) {
return true;
}
if (a.minute < b.minute) {
return true;
}
return a.second < b.second;
};
};
static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size.");
// This is nn::album::AlbumEntry
struct AlbumFileEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{}; // Set to 1 on official SW
};
static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size.");
struct AlbumFileId {
u64 application_id{};
AlbumFileDateTime date{};
AlbumStorage storage{};
ContentType type{};
INSERT_PADDING_BYTES(0x5);
u8 unknown{};
friend constexpr bool operator==(const AlbumFileId&, const AlbumFileId&) = default;
};
static_assert(sizeof(AlbumFileId) == 0x18, "AlbumFileId is an invalid size");
// This is nn::capsrv::AlbumEntry
struct AlbumEntry {
u64 entry_size{};
AlbumFileId file_id{};
};
static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size.");
// This is nn::capsrv::ApplicationAlbumEntry
struct ApplicationAlbumEntry {
u64 size{}; // Size of the entry
u64 hash{}; // AES256 with hardcoded key over AlbumEntry
AlbumFileDateTime datetime{};
AlbumStorage storage{};
ContentType content{};
INSERT_PADDING_BYTES(5);
u8 unknown{1}; // Set to 1 on official SW
};
static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size.");
// This is nn::capsrv::ApplicationAlbumFileEntry
struct ApplicationAlbumFileEntry {
ApplicationAlbumEntry entry{};
AlbumFileDateTime datetime{};
u64 unknown{};
};
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
"ApplicationAlbumFileEntry has incorrect size.");
struct ApplicationData {
std::array<u8, 0x400> data{};
u32 data_size{};
};
static_assert(sizeof(ApplicationData) == 0x404, "ApplicationData is an invalid size");
struct ScreenShotAttribute {
u32 unknown_0{};
AlbumImageOrientation orientation{};
u32 unknown_1{};
u32 unknown_2{};
INSERT_PADDING_BYTES(0x30);
};
static_assert(sizeof(ScreenShotAttribute) == 0x40, "ScreenShotAttribute is an invalid size");
struct ScreenShotDecodeOption {
ScreenShotDecoderFlag flags{};
INSERT_PADDING_BYTES(0x18);
};
static_assert(sizeof(ScreenShotDecodeOption) == 0x20, "ScreenShotDecodeOption is an invalid size");
struct LoadAlbumScreenShotImageOutput {
s64 width{};
s64 height{};
ScreenShotAttribute attribute{};
INSERT_PADDING_BYTES(0x400);
};
static_assert(sizeof(LoadAlbumScreenShotImageOutput) == 0x450,
"LoadAlbumScreenShotImageOutput is an invalid size");
struct LoadAlbumScreenShotImageOutputForApplication {
s64 width{};
s64 height{};
ScreenShotAttribute attribute{};
ApplicationData data{};
INSERT_PADDING_BYTES(0xAC);
};
static_assert(sizeof(LoadAlbumScreenShotImageOutputForApplication) == 0x500,
"LoadAlbumScreenShotImageOutput is an invalid size");
} // namespace Service::Capture

View File

@ -2,45 +2,29 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/caps/caps.h"
#include "core/hle/service/caps/caps_manager.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/caps/caps_u.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
class IAlbumAccessorApplicationSession final
: public ServiceFramework<IAlbumAccessorApplicationSession> {
public:
explicit IAlbumAccessorApplicationSession(Core::System& system_)
: ServiceFramework{system_, "IAlbumAccessorApplicationSession"} {
// clang-format off
static const FunctionInfo functions[] = {
{2001, nullptr, "OpenAlbumMovieReadStream"},
{2002, nullptr, "CloseAlbumMovieReadStream"},
{2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
{2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
{2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
};
// clang-format on
RegisterHandlers(functions);
}
};
CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
IAlbumApplicationService::IAlbumApplicationService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager)
: ServiceFramework{system_, "caps:u"}, manager{album_manager} {
// clang-format off
static const FunctionInfo functions[] = {
{32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
{102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
{103, nullptr, "DeleteAlbumContentsFileForApplication"},
{104, nullptr, "GetAlbumContentsFileSizeForApplication"},
{32, &IAlbumApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
{102, &IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated, "GetAlbumFileList0AafeAruidDeprecated"},
{103, nullptr, "DeleteAlbumFileByAruid"},
{104, nullptr, "GetAlbumFileSizeByAruid"},
{105, nullptr, "DeleteAlbumFileByAruidForDebug"},
{110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"},
{120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"},
{130, nullptr, "PrecheckToCreateContentsForApplication"},
{110, nullptr, "LoadAlbumScreenShotImageByAruid"},
{120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
{130, nullptr, "PrecheckToCreateContentsByAruid"},
{140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
{142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
{142, &IAlbumApplicationService::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
{144, nullptr, "GetAllAlbumFileList3AaeAruid"},
{60002, nullptr, "OpenAccessorSessionForApplication"},
@ -50,9 +34,9 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
RegisterHandlers(functions);
}
CAPS_U::~CAPS_U() = default;
IAlbumApplicationService::~IAlbumApplicationService() = default;
void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
void IAlbumApplicationService::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
@ -64,10 +48,7 @@ void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) {
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
// output entries (which is copied to a s32 by official SW).
void IAlbumApplicationService::GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto pid{rp.Pop<s32>()};
const auto content_type{rp.PopEnum<ContentType>()};
@ -75,26 +56,49 @@ void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) {
const auto end_posix_time{rp.Pop<s64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
// TODO: Update this when we implement the album.
// Currently we do not have a method of accessing album entries, set this to 0 for now.
constexpr u32 total_entries_1{};
constexpr u32 total_entries_2{};
LOG_WARNING(Service_Capture,
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
"end_posix_time={}, applet_resource_user_id={}",
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id);
LOG_WARNING(
Service_Capture,
"(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
"end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
total_entries_1, total_entries_2);
// TODO: Translate posix to DateTime
std::vector<ApplicationAlbumFileEntry> entries;
const Result result =
manager->GetAlbumFileList(entries, content_type, {}, {}, applet_resource_user_id);
if (!entries.empty()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(total_entries_1);
rb.Push(total_entries_2);
rb.Push(result);
rb.Push<u64>(entries.size());
}
void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
GetAlbumContentsFileListForApplication(ctx);
void IAlbumApplicationService::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto pid{rp.Pop<s32>()};
const auto content_type{rp.PopEnum<ContentType>()};
const auto start_date_time{rp.PopRaw<AlbumFileDateTime>()};
const auto end_date_time{rp.PopRaw<AlbumFileDateTime>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_Capture,
"(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid,
content_type, applet_resource_user_id);
std::vector<ApplicationAlbumFileEntry> entries;
const Result result = manager->GetAlbumFileList(entries, content_type, start_date_time,
end_date_time, applet_resource_user_id);
if (!entries.empty()) {
ctx.WriteBuffer(entries);
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
rb.Push<u64>(entries.size());
}
} // namespace Service::Capture

View File

@ -10,16 +10,20 @@ class System;
}
namespace Service::Capture {
class AlbumManager;
class CAPS_U final : public ServiceFramework<CAPS_U> {
class IAlbumApplicationService final : public ServiceFramework<IAlbumApplicationService> {
public:
explicit CAPS_U(Core::System& system_);
~CAPS_U() override;
explicit IAlbumApplicationService(Core::System& system_,
std::shared_ptr<AlbumManager> album_manager);
~IAlbumApplicationService() override;
private:
void SetShimLibraryVersion(HLERequestContext& ctx);
void GetAlbumContentsFileListForApplication(HLERequestContext& ctx);
void GetAlbumFileList0AafeAruidDeprecated(HLERequestContext& ctx);
void GetAlbumFileList3AaeAruid(HLERequestContext& ctx);
std::shared_ptr<AlbumManager> manager = nullptr;
};
} // namespace Service::Capture

View File

@ -545,6 +545,16 @@ void IGeneralService::IsAnyInternetRequestAccepted(HLERequestContext& ctx) {
}
}
void IGeneralService::IsAnyForegroundRequestAccepted(HLERequestContext& ctx) {
const bool is_accepted{};
LOG_WARNING(Service_NIFM, "(STUBBED) called, is_accepted={}", is_accepted);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(is_accepted);
}
IGeneralService::IGeneralService(Core::System& system_)
: ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
// clang-format off
@ -569,7 +579,7 @@ IGeneralService::IGeneralService(Core::System& system_)
{19, nullptr, "SetEthernetCommunicationEnabled"},
{20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
{21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
{22, nullptr, "IsAnyForegroundRequestAccepted"},
{22, &IGeneralService::IsAnyForegroundRequestAccepted, "IsAnyForegroundRequestAccepted"},
{23, nullptr, "PutToSleep"},
{24, nullptr, "WakeUp"},
{25, nullptr, "GetSsidListVersion"},

View File

@ -35,6 +35,7 @@ private:
void GetInternetConnectionStatus(HLERequestContext& ctx);
void IsEthernetCommunicationEnabled(HLERequestContext& ctx);
void IsAnyInternetRequestAccepted(HLERequestContext& ctx);
void IsAnyForegroundRequestAccepted(HLERequestContext& ctx);
Network::RoomNetwork& network;
};

View File

@ -7,6 +7,7 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/errors.h"
@ -502,8 +503,8 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{47, &IContentManagementInterface::GetTotalSpaceSize, "GetTotalSpaceSize"},
{48, &IContentManagementInterface::GetFreeSpaceSize, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
@ -516,6 +517,28 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
IContentManagementInterface::~IContentManagementInterface() = default;
void IContentManagementInterface::GetTotalSpaceSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<FileSys::StorageId>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetFileSystemController().GetTotalSpaceSize(storage));
}
void IContentManagementInterface::GetFreeSpaceSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage{rp.PopEnum<FileSys::StorageId>()};
LOG_INFO(Service_Capture, "called, storage={}", storage);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(system.GetFileSystemController().GetFreeSpaceSize(storage));
}
IDocumentInterface::IDocumentInterface(Core::System& system_)
: ServiceFramework{system_, "IDocumentInterface"} {
// clang-format off

View File

@ -48,6 +48,10 @@ class IContentManagementInterface final : public ServiceFramework<IContentManage
public:
explicit IContentManagementInterface(Core::System& system_);
~IContentManagementInterface() override;
private:
void GetTotalSpaceSize(HLERequestContext& ctx);
void GetFreeSpaceSize(HLERequestContext& ctx);
};
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {

View File

@ -33,7 +33,7 @@ public:
{1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
{1002, nullptr, "ConfirmLaunchApplicationPermission"},
{1003, nullptr, "ConfirmResumeApplicationPermission"},
{1004, nullptr, "ConfirmSnsPostPermission"},
{1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
{1005, nullptr, "ConfirmSystemSettingsPermission"},
{1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
{1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
@ -236,6 +236,13 @@ private:
states.free_communication = true;
}
void ConfirmSnsPostPermission(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(Error::ResultNoFreeCommunication);
}
void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
const bool is_temporary_unlocked = false;

View File

@ -118,7 +118,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
return {ResultStatus::ErrorMissingNPDM, {}};
}
const ResultStatus result2 = metadata.Load(npdm);
const ResultStatus result2 = metadata.Reload(npdm);
if (result2 != ResultStatus::Success) {
return {result2, {}};
}

View File

@ -544,7 +544,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
it++;
}
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 16> downloads;
u64 total_size_bytes = 0;
u64 largest_copy = 0;
for (const IntervalSet& intervals : committed_ranges) {
@ -914,6 +914,11 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
const u32 offset = buffer.Offset(binding.cpu_addr);
const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
}
if constexpr (NEEDS_BIND_STORAGE_INDEX) {
runtime.BindStorageBuffer(stage, binding_index, buffer, offset, size, is_written);
++binding_index;
@ -931,6 +936,11 @@ void BufferCache<P>::BindHostGraphicsTextureBuffers(size_t stage) {
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
const bool is_written = ((channel_state->written_texture_buffers[stage] >> index) & 1) != 0;
if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
}
const u32 offset = buffer.Offset(binding.cpu_addr);
const PixelFormat format = binding.format;
if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
@ -962,6 +972,8 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
const u32 offset = buffer.Offset(binding.cpu_addr);
host_bindings.buffers.push_back(&buffer);
host_bindings.offsets.push_back(offset);
@ -1011,6 +1023,11 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
const u32 offset = buffer.Offset(binding.cpu_addr);
const bool is_written =
((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
}
if constexpr (NEEDS_BIND_STORAGE_INDEX) {
runtime.BindComputeStorageBuffer(binding_index, buffer, offset, size, is_written);
++binding_index;
@ -1028,6 +1045,12 @@ void BufferCache<P>::BindHostComputeTextureBuffers() {
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
const bool is_written =
((channel_state->written_compute_texture_buffers >> index) & 1) != 0;
if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, size);
}
const u32 offset = buffer.Offset(binding.cpu_addr);
const PixelFormat format = binding.format;
if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) {
@ -1201,16 +1224,11 @@ void BufferCache<P>::UpdateUniformBuffers(size_t stage) {
template <class P>
void BufferCache<P>::UpdateStorageBuffers(size_t stage) {
const u32 written_mask = channel_state->written_storage_buffers[stage];
ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
// Resolve buffer
Binding& binding = channel_state->storage_buffers[stage][index];
const BufferId buffer_id = FindBuffer(binding.cpu_addr, binding.size);
binding.buffer_id = buffer_id;
// Mark buffer as written if needed
if (((written_mask >> index) & 1) != 0) {
MarkWrittenBuffer(buffer_id, binding.cpu_addr, binding.size);
}
});
}
@ -1219,10 +1237,6 @@ void BufferCache<P>::UpdateTextureBuffers(size_t stage) {
ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) {
Binding& binding = channel_state->texture_buffers[stage][index];
binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
// Mark buffer as written if needed
if (((channel_state->written_texture_buffers[stage] >> index) & 1) != 0) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
}
});
}
@ -1252,7 +1266,6 @@ void BufferCache<P>::UpdateTransformFeedbackBuffer(u32 index) {
.size = size,
.buffer_id = buffer_id,
};
MarkWrittenBuffer(buffer_id, *cpu_addr, size);
}
template <class P>
@ -1279,10 +1292,6 @@ void BufferCache<P>::UpdateComputeStorageBuffers() {
// Resolve buffer
Binding& binding = channel_state->compute_storage_buffers[index];
binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
// Mark as written if needed
if (((channel_state->written_compute_storage_buffers >> index) & 1) != 0) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
}
});
}
@ -1291,18 +1300,11 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) {
Binding& binding = channel_state->compute_texture_buffers[index];
binding.buffer_id = FindBuffer(binding.cpu_addr, binding.size);
// Mark as written if needed
if (((channel_state->written_compute_texture_buffers >> index) & 1) != 0) {
MarkWrittenBuffer(binding.buffer_id, binding.cpu_addr, binding.size);
}
});
}
template <class P>
void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, VAddr cpu_addr, u32 size) {
if (memory_tracker.IsRegionCpuModified(cpu_addr, size)) {
SynchronizeBuffer(slot_buffers[buffer_id], cpu_addr, size);
}
memory_tracker.MarkRegionAsGpuModified(cpu_addr, size);
const IntervalType base_interval{cpu_addr, cpu_addr + size};

View File

@ -19,6 +19,7 @@ set(SHADER_FILES
block_linear_unswizzle_2d.comp
block_linear_unswizzle_3d.comp
convert_abgr8_to_d24s8.frag
convert_d32f_to_abgr8.frag
convert_d24s8_to_abgr8.frag
convert_depth_to_float.frag
convert_float_to_depth.frag

View File

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#version 450
layout(binding = 0) uniform sampler2D depth_tex;
layout(location = 0) out vec4 color;
void main() {
ivec2 coord = ivec2(gl_FragCoord.xy);
float depth = textureLod(depth_tex, coord, 0).r;
color = vec4(depth, depth, depth, 1.0);
}

View File

@ -89,9 +89,6 @@ public:
void RequestScreenshot(void* data, std::function<void(bool)> callback,
const Layout::FramebufferLayout& layout);
/// This is called to notify the rendering backend of a surface change
virtual void NotifySurfaceChanged() {}
protected:
Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
std::unique_ptr<Core::Frontend::GraphicsContext> context;

View File

@ -1048,6 +1048,10 @@ void Image::Scale(bool up_scale) {
}
bool Image::ScaleUp(bool ignore) {
const auto& resolution = runtime->resolution;
if (!resolution.active) {
return false;
}
if (True(flags & ImageFlagBits::Rescaled)) {
return false;
}
@ -1060,9 +1064,6 @@ bool Image::ScaleUp(bool ignore) {
return false;
}
flags |= ImageFlagBits::Rescaled;
if (!runtime->resolution.active) {
return false;
}
has_scaled = true;
if (ignore) {
current_texture = upscaled_backup.handle;
@ -1073,13 +1074,14 @@ bool Image::ScaleUp(bool ignore) {
}
bool Image::ScaleDown(bool ignore) {
const auto& resolution = runtime->resolution;
if (!resolution.active) {
return false;
}
if (False(flags & ImageFlagBits::Rescaled)) {
return false;
}
flags &= ~ImageFlagBits::Rescaled;
if (!runtime->resolution.active) {
return false;
}
if (ignore) {
current_texture = texture.handle;
return true;

View File

@ -116,6 +116,7 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> FORMAT_TAB
{GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, // E5B9G9R9_FLOAT
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, // D32_FLOAT
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16_UNORM
{GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8}, // X8_D24_UNORM
{GL_STENCIL_INDEX8, GL_STENCIL, GL_UNSIGNED_BYTE}, // S8_UINT
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24_UNORM_S8_UINT
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // S8_UINT_D24_UNORM

View File

@ -9,6 +9,7 @@
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h"
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
@ -433,6 +434,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
@ -557,6 +559,13 @@ void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
convert_d32f_to_abgr8_frag);
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
}
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
@ -609,6 +618,8 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
const VkPipelineLayout layout = *clear_color_pipeline_layout;
scheduler.RequestRenderpass(dst_framebuffer);
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
constexpr std::array blend_constants{0.0f, 0.0f, 0.0f, 0.0f};
cmdbuf.SetBlendConstants(blend_constants.data());
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
BindBlitState(cmdbuf, dst_region);
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth);
@ -865,7 +876,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.depthTestEnable = VK_FALSE,
.depthTestEnable = key.depth_clear,
.depthWriteEnable = key.depth_clear,
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
.depthBoundsTestEnable = VK_FALSE,

View File

@ -67,6 +67,8 @@ public:
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
void ConvertD32FToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
void ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
@ -128,6 +130,7 @@ private:
vk::ShaderModule convert_depth_to_float_frag;
vk::ShaderModule convert_float_to_depth_frag;
vk::ShaderModule convert_abgr8_to_d24s8_frag;
vk::ShaderModule convert_d32f_to_abgr8_frag;
vk::ShaderModule convert_d24s8_to_abgr8_frag;
vk::ShaderModule convert_s8d24_to_abgr8_frag;
vk::Sampler linear_sampler;
@ -146,6 +149,7 @@ private:
vk::Pipeline convert_d16_to_r16_pipeline;
vk::Pipeline convert_r16_to_d16_pipeline;
vk::Pipeline convert_abgr8_to_d24s8_pipeline;
vk::Pipeline convert_d32f_to_abgr8_pipeline;
vk::Pipeline convert_d24s8_to_abgr8_pipeline;
vk::Pipeline convert_s8d24_to_abgr8_pipeline;
};

View File

@ -214,8 +214,9 @@ struct FormatTuple {
{VK_FORMAT_E5B9G9R9_UFLOAT_PACK32}, // E5B9G9R9_FLOAT
// Depth formats
{VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
{VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
{VK_FORMAT_D32_SFLOAT, Attachable}, // D32_FLOAT
{VK_FORMAT_D16_UNORM, Attachable}, // D16_UNORM
{VK_FORMAT_X8_D24_UNORM_PACK32, Attachable}, // X8_D24_UNORM
// Stencil formats
{VK_FORMAT_S8_UINT, Attachable}, // S8_UINT

View File

@ -56,10 +56,6 @@ public:
return device.GetDriverName();
}
void NotifySurfaceChanged() override {
present_manager.NotifySurfaceChanged();
}
private:
void Report() const;

View File

@ -96,6 +96,7 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) {
VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
switch (framebuffer.pixel_format) {
case Service::android::PixelFormat::Rgba8888:
case Service::android::PixelFormat::Rgbx8888:
return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
case Service::android::PixelFormat::Rgb565:
return VK_FORMAT_R5G6B5_UNORM_PACK16;

View File

@ -103,8 +103,7 @@ PresentManager::PresentManager(const vk::Instance& instance_,
surface{surface_}, blit_supported{CanBlitToSwapchain(device.GetPhysical(),
swapchain.GetImageViewFormat())},
use_present_thread{Settings::values.async_presentation.GetValue()},
image_count{swapchain.GetImageCount()}, last_render_surface{
render_window_.GetWindowInfo().render_surface} {
image_count{swapchain.GetImageCount()} {
auto& dld = device.GetLogical();
cmdpool = dld.CreateCommandPool({
@ -289,44 +288,36 @@ void PresentManager::PresentThread(std::stop_token token) {
}
}
void PresentManager::NotifySurfaceChanged() {
#ifdef ANDROID
std::scoped_lock lock{recreate_surface_mutex};
recreate_surface_cv.notify_one();
#endif
void PresentManager::RecreateSwapchain(Frame* frame) {
swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb);
image_count = swapchain.GetImageCount();
}
void PresentManager::CopyToSwapchain(Frame* frame) {
MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
bool requires_recreation = false;
const auto recreate_swapchain = [&] {
swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb);
image_count = swapchain.GetImageCount();
};
while (true) {
try {
// Recreate surface and swapchain if needed.
if (requires_recreation) {
surface = CreateSurface(instance, render_window.GetWindowInfo());
RecreateSwapchain(frame);
}
#ifdef ANDROID
std::unique_lock lock{recreate_surface_mutex};
// Draw to swapchain.
return CopyToSwapchainImpl(frame);
} catch (const vk::Exception& except) {
if (except.GetResult() != VK_ERROR_SURFACE_LOST_KHR) {
throw;
}
const auto needs_recreation = [&] {
if (last_render_surface != render_window.GetWindowInfo().render_surface) {
return true;
requires_recreation = true;
}
if (swapchain.NeedsRecreation(frame->is_srgb)) {
return true;
}
return false;
};
recreate_surface_cv.wait_for(lock, std::chrono::milliseconds(400),
[&]() { return !needs_recreation(); });
// If the frontend recreated the surface, recreate the renderer surface and swapchain.
if (last_render_surface != render_window.GetWindowInfo().render_surface) {
last_render_surface = render_window.GetWindowInfo().render_surface;
surface = CreateSurface(instance, render_window.GetWindowInfo());
recreate_swapchain();
}
#endif
}
void PresentManager::CopyToSwapchainImpl(Frame* frame) {
MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
// If the size or colorspace of the incoming frames has changed, recreate the swapchain
// to account for that.
@ -334,11 +325,11 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
const bool size_changed =
swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
if (srgb_changed || size_changed) {
recreate_swapchain();
RecreateSwapchain(frame);
}
while (swapchain.AcquireNextImage()) {
recreate_swapchain();
RecreateSwapchain(frame);
}
const vk::CommandBuffer cmdbuf{frame->cmdbuf};
@ -488,4 +479,4 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
swapchain.Present(render_semaphore);
}
} // namespace Vulkan
} // namespace Vulkan

View File

@ -54,14 +54,15 @@ public:
/// Waits for the present thread to finish presenting all queued frames.
void WaitPresent();
/// This is called to notify the rendering backend of a surface change
void NotifySurfaceChanged();
private:
void PresentThread(std::stop_token token);
void CopyToSwapchain(Frame* frame);
void CopyToSwapchainImpl(Frame* frame);
void RecreateSwapchain(Frame* frame);
private:
const vk::Instance& instance;
Core::Frontend::EmuWindow& render_window;
@ -76,16 +77,13 @@ private:
std::queue<Frame*> free_queue;
std::condition_variable_any frame_cv;
std::condition_variable free_cv;
std::condition_variable recreate_surface_cv;
std::mutex swapchain_mutex;
std::mutex recreate_surface_mutex;
std::mutex queue_mutex;
std::mutex free_mutex;
std::jthread present_thread;
bool blit_supported;
bool use_present_thread;
std::size_t image_count{};
void* last_render_surface{};
};
} // namespace Vulkan

View File

@ -422,7 +422,8 @@ void RasterizerVulkan::Clear(u32 layer_count) {
return;
}
if (use_stencil && regs.stencil_front_mask != 0xFF && regs.stencil_front_mask != 0) {
if (use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF &&
regs.stencil_front_mask != 0) {
Region2D dst_region = {
Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y},
Offset2D{.x = clear_rect.rect.offset.x + static_cast<s32>(clear_rect.rect.extent.width),

View File

@ -24,25 +24,38 @@ using namespace Common::Literals;
// Maximum potential alignment of a Vulkan buffer
constexpr VkDeviceSize MAX_ALIGNMENT = 256;
// Maximum size to put elements in the stream buffer
constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
// Stream buffer size in bytes
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
size_t Region(size_t iterator) noexcept {
return iterator / REGION_SIZE;
size_t GetStreamBufferSize(const Device& device) {
VkDeviceSize size{0};
if (device.HasDebuggingToolAttached()) {
ForEachDeviceLocalHostVisibleHeap(device, [&size](size_t index, VkMemoryHeap& heap) {
size = std::max(size, heap.size);
});
// If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be
// loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue
// as the heap will be much larger.
if (size <= 256_MiB) {
size = size * 40 / 100;
}
} else {
size = MAX_STREAM_BUFFER_SIZE;
}
return std::min(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
}
} // Anonymous namespace
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
stream_buffer_size{GetStreamBufferSize(device)}, region_size{stream_buffer_size /
StagingBufferPool::NUM_SYNCS} {
VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = STREAM_BUFFER_SIZE,
.size = stream_buffer_size,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
@ -63,7 +76,7 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
StagingBufferPool::~StagingBufferPool() = default;
StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage, bool deferred) {
if (!deferred && usage == MemoryUsage::Upload && size <= MAX_STREAM_BUFFER_REQUEST_SIZE) {
if (!deferred && usage == MemoryUsage::Upload && size <= region_size) {
return GetStreamBuffer(size);
}
return GetStagingBuffer(size, usage, deferred);
@ -101,7 +114,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
used_iterator = iterator;
free_iterator = std::max(free_iterator, iterator + size);
if (iterator + size >= STREAM_BUFFER_SIZE) {
if (iterator + size >= stream_buffer_size) {
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS,
current_tick);
used_iterator = 0;

View File

@ -90,6 +90,9 @@ private:
void ReleaseCache(MemoryUsage usage);
void ReleaseLevel(StagingBuffersCache& cache, size_t log2);
size_t Region(size_t iter) const noexcept {
return iter / region_size;
}
const Device& device;
MemoryAllocator& memory_allocator;
@ -97,6 +100,8 @@ private:
vk::Buffer stream_buffer;
std::span<u8> stream_pointer;
VkDeviceSize stream_buffer_size;
VkDeviceSize region_size;
size_t iterator = 0;
size_t used_iterator = 0;

View File

@ -238,6 +238,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
return any_r ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
case PixelFormat::D16_UNORM:
case PixelFormat::D32_FLOAT:
case PixelFormat::X8_D24_UNORM:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case PixelFormat::S8_UINT:
return VK_IMAGE_ASPECT_STENCIL_BIT;
@ -1200,6 +1201,9 @@ void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, Im
if (src_view.format == PixelFormat::D24_UNORM_S8_UINT) {
return blit_image_helper.ConvertS8D24ToABGR8(dst, src_view);
}
if (src_view.format == PixelFormat::D32_FLOAT) {
return blit_image_helper.ConvertD32FToABGR8(dst, src_view);
}
break;
case PixelFormat::R32_FLOAT:
if (src_view.format == PixelFormat::D32_FLOAT) {
@ -1526,15 +1530,15 @@ bool Image::IsRescaled() const noexcept {
}
bool Image::ScaleUp(bool ignore) {
const auto& resolution = runtime->resolution;
if (!resolution.active) {
return false;
}
if (True(flags & ImageFlagBits::Rescaled)) {
return false;
}
ASSERT(info.type != ImageType::Linear);
flags |= ImageFlagBits::Rescaled;
const auto& resolution = runtime->resolution;
if (!resolution.active) {
return false;
}
has_scaled = true;
if (!scaled_image) {
const bool is_2d = info.type == ImageType::e2D;
@ -1563,15 +1567,15 @@ bool Image::ScaleUp(bool ignore) {
}
bool Image::ScaleDown(bool ignore) {
const auto& resolution = runtime->resolution;
if (!resolution.active) {
return false;
}
if (False(flags & ImageFlagBits::Rescaled)) {
return false;
}
ASSERT(info.type != ImageType::Linear);
flags &= ~ImageFlagBits::Rescaled;
const auto& resolution = runtime->resolution;
if (!resolution.active) {
return false;
}
current_image = *original_image;
if (ignore) {
return true;

View File

@ -85,6 +85,8 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
return PixelFormat::S8_UINT;
case Tegra::DepthFormat::Z32_FLOAT_X24S8_UINT:
return PixelFormat::D32_FLOAT_S8_UINT;
case Tegra::DepthFormat::X8Z24_UNORM:
return PixelFormat::X8_D24_UNORM;
default:
UNIMPLEMENTED_MSG("Unimplemented format={}", format);
return PixelFormat::S8_UINT_D24_UNORM;
@ -202,6 +204,7 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format)
PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) {
switch (format) {
case Service::android::PixelFormat::Rgba8888:
case Service::android::PixelFormat::Rgbx8888:
return PixelFormat::A8B8G8R8_UNORM;
case Service::android::PixelFormat::Rgb565:
return PixelFormat::R5G6B5_UNORM;

View File

@ -115,6 +115,7 @@ enum class PixelFormat {
// Depth formats
D32_FLOAT = MaxColorFormat,
D16_UNORM,
X8_D24_UNORM,
MaxDepthFormat,
@ -251,6 +252,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_WIDTH_TABLE = {{
1, // E5B9G9R9_FLOAT
1, // D32_FLOAT
1, // D16_UNORM
1, // X8_D24_UNORM
1, // S8_UINT
1, // D24_UNORM_S8_UINT
1, // S8_UINT_D24_UNORM
@ -360,6 +362,7 @@ constexpr std::array<u8, MaxPixelFormat> BLOCK_HEIGHT_TABLE = {{
1, // E5B9G9R9_FLOAT
1, // D32_FLOAT
1, // D16_UNORM
1, // X8_D24_UNORM
1, // S8_UINT
1, // D24_UNORM_S8_UINT
1, // S8_UINT_D24_UNORM
@ -469,6 +472,7 @@ constexpr std::array<u8, MaxPixelFormat> BITS_PER_BLOCK_TABLE = {{
32, // E5B9G9R9_FLOAT
32, // D32_FLOAT
16, // D16_UNORM
32, // X8_D24_UNORM
8, // S8_UINT
32, // D24_UNORM_S8_UINT
32, // S8_UINT_D24_UNORM

View File

@ -138,10 +138,16 @@ PixelFormat PixelFormatFromTextureInfo(TextureFormat format, ComponentType red,
return PixelFormat::E5B9G9R9_FLOAT;
case Hash(TextureFormat::Z32, FLOAT):
return PixelFormat::D32_FLOAT;
case Hash(TextureFormat::Z32, FLOAT, UINT, UINT, UINT, LINEAR):
return PixelFormat::D32_FLOAT;
case Hash(TextureFormat::Z16, UNORM):
return PixelFormat::D16_UNORM;
case Hash(TextureFormat::Z16, UNORM, UINT, UINT, UINT, LINEAR):
return PixelFormat::D16_UNORM;
case Hash(TextureFormat::X8Z24, UNORM):
return PixelFormat::X8_D24_UNORM;
case Hash(TextureFormat::X8Z24, UNORM, UINT, UINT, UINT, LINEAR):
return PixelFormat::X8_D24_UNORM;
case Hash(TextureFormat::Z24S8, UINT, UNORM, UNORM, UNORM, LINEAR):
return PixelFormat::S8_UINT_D24_UNORM;
case Hash(TextureFormat::Z24S8, UINT, UNORM, UINT, UINT, LINEAR):

View File

@ -211,6 +211,8 @@ struct fmt::formatter<VideoCore::Surface::PixelFormat> : fmt::formatter<fmt::str
return "D32_FLOAT";
case PixelFormat::D16_UNORM:
return "D16_UNORM";
case PixelFormat::X8_D24_UNORM:
return "X8_D24_UNORM";
case PixelFormat::S8_UINT:
return "S8_UINT";
case PixelFormat::D24_UNORM_S8_UINT:

View File

@ -85,6 +85,7 @@ bool ImageViewBase::SupportsAnisotropy() const noexcept {
// Depth formats
case PixelFormat::D32_FLOAT:
case PixelFormat::D16_UNORM:
case PixelFormat::X8_D24_UNORM:
// Stencil formats
case PixelFormat::S8_UINT:
// DepthStencil formats

View File

@ -68,6 +68,7 @@ struct LevelInfo {
Extent2D tile_size;
u32 bpp_log2;
u32 tile_width_spacing;
u32 num_levels;
};
[[nodiscard]] constexpr u32 AdjustTileSize(u32 shift, u32 unit_factor, u32 dimension) {
@ -118,11 +119,11 @@ template <u32 GOB_EXTENT>
}
[[nodiscard]] constexpr Extent3D AdjustMipBlockSize(Extent3D num_tiles, Extent3D block_size,
u32 level) {
u32 level, u32 num_levels) {
return {
.width = AdjustMipBlockSize<GOB_SIZE_X>(num_tiles.width, block_size.width, level),
.height = AdjustMipBlockSize<GOB_SIZE_Y>(num_tiles.height, block_size.height, level),
.depth = level == 0
.depth = level == 0 && num_levels == 1
? block_size.depth
: AdjustMipBlockSize<GOB_SIZE_Z>(num_tiles.depth, block_size.depth, level),
};
@ -166,13 +167,6 @@ template <u32 GOB_EXTENT>
}
[[nodiscard]] constexpr Extent3D TileShift(const LevelInfo& info, u32 level) {
if (level == 0) {
return Extent3D{
.width = info.block.width,
.height = info.block.height,
.depth = info.block.depth,
};
}
const Extent3D blocks = NumLevelBlocks(info, level);
return Extent3D{
.width = AdjustTileSize(info.block.width, GOB_SIZE_X, blocks.width),
@ -257,7 +251,7 @@ template <u32 GOB_EXTENT>
}
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
u32 tile_width_spacing) {
u32 tile_width_spacing, u32 num_levels) {
const u32 bytes_per_block = BytesPerBlock(format);
return {
.size =
@ -270,16 +264,18 @@ template <u32 GOB_EXTENT>
.tile_size = DefaultBlockSize(format),
.bpp_log2 = BytesPerBlockLog2(bytes_per_block),
.tile_width_spacing = tile_width_spacing,
.num_levels = num_levels,
};
}
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) {
return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing);
return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing,
info.resources.levels);
}
[[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block,
u32 tile_width_spacing, u32 level) {
const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing);
const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing, level);
u32 offset = 0;
for (u32 current_level = 0; current_level < level; ++current_level) {
offset += CalculateLevelSize(info, current_level);
@ -466,7 +462,7 @@ template <u32 GOB_EXTENT>
};
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing);
const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0);
const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0, info.resources.levels);
return Extent3D{
.width = Common::AlignUpLog2(num_tiles.width, alignment),
.height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
@ -533,7 +529,8 @@ void SwizzleBlockLinearImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr
UNIMPLEMENTED_IF(copy.image_extent != level_size);
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level);
const Extent3D block =
AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
size_t host_offset = copy.buffer_offset;
@ -698,7 +695,7 @@ u32 CalculateLevelStrideAlignment(const ImageInfo& info, u32 level) {
const Extent2D tile_size = DefaultBlockSize(info.format);
const Extent3D level_size = AdjustMipSize(info.size, level);
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
const Extent3D block = AdjustMipBlockSize(num_tiles, info.block, level);
const Extent3D block = AdjustMipBlockSize(num_tiles, info.block, level, info.resources.levels);
const u32 bpp_log2 = BytesPerBlockLog2(info.format);
return StrideAlignment(num_tiles, block, bpp_log2, info.tile_width_spacing);
}
@ -887,7 +884,8 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
.image_extent = level_size,
};
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level);
const Extent3D block =
AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
const u32 stride_alignment = StrideAlignment(num_tiles, info.block, gob, bpp_log2);
size_t guest_layer_offset = 0;
@ -1041,7 +1039,7 @@ Extent3D MipBlockSize(const ImageInfo& info, u32 level) {
const Extent2D tile_size = DefaultBlockSize(info.format);
const Extent3D level_size = AdjustMipSize(info.size, level);
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
return AdjustMipBlockSize(num_tiles, level_info.block, level);
return AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
}
boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const ImageInfo& info) {
@ -1063,7 +1061,8 @@ boost::container::small_vector<SwizzleParameters, 16> FullUploadSwizzles(const I
for (s32 level = 0; level < num_levels; ++level) {
const Extent3D level_size = AdjustMipSize(size, level);
const Extent3D num_tiles = AdjustTileSize(level_size, tile_size);
const Extent3D block = AdjustMipBlockSize(num_tiles, level_info.block, level);
const Extent3D block =
AdjustMipBlockSize(num_tiles, level_info.block, level, level_info.num_levels);
params[level] = SwizzleParameters{
.num_tiles = num_tiles,
.block = block,
@ -1292,11 +1291,11 @@ u32 MapSizeBytes(const ImageBase& image) {
}
}
static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0}, 0) ==
static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2, 0, 1}, 0) ==
0x7f8000);
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x40000);
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0}, 0) == 0x40000);
static_assert(CalculateLevelSize(LevelInfo{{128, 8, 1}, {0, 4, 0}, {1, 1}, 4, 0, 1}, 0) == 0x4000);
static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
0x2afc00);

View File

@ -84,9 +84,12 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{
} // namespace Alternatives
enum class NvidiaArchitecture {
AmpereOrNewer,
KeplerOrOlder,
Maxwell,
Pascal,
Volta,
Turing,
VoltaOrOlder,
AmpereOrNewer,
};
template <typename T>
@ -200,6 +203,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
VK_FORMAT_BC7_UNORM_BLOCK,
VK_FORMAT_D16_UNORM,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_X8_D24_UNORM_PACK32,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D32_SFLOAT_S8_UINT,
@ -321,13 +325,38 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
physical.GetProperties2(physical_properties);
if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
// Only Ampere and newer support this feature
// TODO: Find a way to differentiate Ampere and Ada
return NvidiaArchitecture::AmpereOrNewer;
}
}
if (exts.contains(VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME)) {
return NvidiaArchitecture::Turing;
}
return NvidiaArchitecture::VoltaOrOlder;
if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) {
VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT advanced_blending_props{};
advanced_blending_props.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
VkPhysicalDeviceProperties2 physical_properties{};
physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physical_properties.pNext = &advanced_blending_props;
physical.GetProperties2(physical_properties);
if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) {
return NvidiaArchitecture::Maxwell;
}
if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) {
VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_raster_props{};
conservative_raster_props.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
physical_properties.pNext = &conservative_raster_props;
physical.GetProperties2(physical_properties);
if (conservative_raster_props.degenerateLinesRasterized) {
return NvidiaArchitecture::Volta;
}
return NvidiaArchitecture::Pascal;
}
}
return NvidiaArchitecture::KeplerOrOlder;
}
std::vector<const char*> ExtensionListForVulkan(
@ -504,19 +533,14 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
if (is_nvidia) {
const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
switch (arch) {
case NvidiaArchitecture::AmpereOrNewer:
if (arch >= NvidiaArchitecture::AmpereOrNewer) {
LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
features.shader_float16_int8.shaderFloat16 = false;
break;
case NvidiaArchitecture::Turing:
break;
case NvidiaArchitecture::VoltaOrOlder:
} else if (arch <= NvidiaArchitecture::Volta) {
if (nv_major_version < 527) {
LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
}
break;
}
if (nv_major_version >= 510) {
LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits");
@ -661,7 +685,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
"ANV drivers 22.3.0 to 23.1.0 have broken VK_KHR_push_descriptor");
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
}
} else if (extensions.push_descriptor && is_nvidia) {
const auto arch = GetNvidiaArchitecture(physical, supported_extensions);
if (arch <= NvidiaArchitecture::Pascal) {
LOG_WARNING(Render_Vulkan,
"Pascal and older architectures have broken VK_KHR_push_descriptor");
RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
}
}
if (is_mvk) {
LOG_WARNING(Render_Vulkan,
"MVK driver breaks when using more than 16 vertex attributes/bindings");

View File

@ -9,6 +9,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/polyfill_ranges.h"
#include "video_core/vulkan_common/vma.h"
@ -65,12 +66,12 @@ struct Range {
switch (usage) {
case MemoryUsage::Upload:
case MemoryUsage::Stream:
return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
return VMA_ALLOCATION_CREATE_MAPPED_BIT |
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
case MemoryUsage::Download:
return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
return VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
case MemoryUsage::DeviceLocal:
return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
return {};
}
return {};
}
@ -212,7 +213,20 @@ MemoryAllocator::MemoryAllocator(const Device& device_)
: device{device_}, allocator{device.GetAllocator()},
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
buffer_image_granularity{
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {
// GPUs not supporting rebar may only have a region with less than 256MB host visible/device
// local memory. In that case, opening 2 RenderDoc captures side-by-side is not possible due to
// the heap running out of memory. With RenderDoc attached and only a small host/device region,
// only allow the stream buffer in this memory heap.
if (device.HasDebuggingToolAttached()) {
using namespace Common::Literals;
ForEachDeviceLocalHostVisibleHeap(device, [this](size_t index, VkMemoryHeap& heap) {
if (heap.size <= 256_MiB) {
valid_memory_types &= ~(1u << index);
}
});
}
}
MemoryAllocator::~MemoryAllocator() = default;
@ -239,12 +253,11 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const {
const VmaAllocationCreateInfo alloc_ci = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT |
MemoryUsageVmaFlags(usage),
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage),
.usage = MemoryUsageVma(usage),
.requiredFlags = 0,
.preferredFlags = MemoryUsagePreferedVmaFlags(usage),
.memoryTypeBits = 0,
.memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types,
.pool = VK_NULL_HANDLE,
.pUserData = nullptr,
.priority = 0.f,

View File

@ -7,6 +7,7 @@
#include <span>
#include <vector>
#include "common/common_types.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
VK_DEFINE_HANDLE(VmaAllocator)
@ -26,6 +27,18 @@ enum class MemoryUsage {
Stream, ///< Requests device local host visible buffer, falling back host memory.
};
template <typename F>
void ForEachDeviceLocalHostVisibleHeap(const Device& device, F&& f) {
auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties;
for (size_t i = 0; i < memory_props.memoryTypeCount; i++) {
auto& memory_type = memory_props.memoryTypes[i];
if ((memory_type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
(memory_type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
f(memory_type.heapIndex, memory_props.memoryHeaps[memory_type.heapIndex]);
}
}
}
/// Ownership handle of a memory commitment.
/// Points to a subregion of a memory allocation.
class MemoryCommit {
@ -124,6 +137,7 @@ private:
std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
// and optimal images
u32 valid_memory_types{~0u};
};
} // namespace Vulkan

View File

@ -117,6 +117,9 @@ public:
virtual ~Exception() = default;
const char* what() const noexcept override;
VkResult GetResult() const noexcept {
return result;
}
private:
VkResult result;

View File

@ -195,6 +195,8 @@ add_executable(yuzu
multiplayer/state.cpp
multiplayer/state.h
multiplayer/validation.h
play_time_manager.cpp
play_time_manager.h
precompiled_headers.h
qt_common.cpp
qt_common.h

View File

@ -23,6 +23,7 @@
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
#include "yuzu/main.h"
#include "yuzu/util/controller_navigation.h"
namespace {
@ -132,6 +133,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
};
ui->labelError->setVisible(false);
// Setup/load everything prior to setting up connections.
// This avoids unintentionally changing the states of elements while loading them in.
SetSupportedControllers();
@ -143,6 +146,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
LoadConfiguration();
controller_navigation = new ControllerNavigation(system.HIDCore(), this);
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
SetExplainText(i);
UpdateControllerIcon(i);
@ -151,6 +156,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
if (checked) {
// Hide eventual error message about number of controllers
ui->labelError->setVisible(false);
for (std::size_t index = 0; index <= i; ++index) {
connected_controller_checkboxes[index]->setChecked(checked);
}
@ -199,6 +206,12 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
&QtControllerSelectorDialog::ApplyConfiguration);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
[this](Qt::Key key) {
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::postEvent(this, event);
});
// Enhancement: Check if the parameters have already been met before disconnecting controllers.
// If all the parameters are met AND only allows a single player,
// stop the constructor here as we do not need to continue.
@ -217,6 +230,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
}
QtControllerSelectorDialog::~QtControllerSelectorDialog() {
controller_navigation->UnloadController();
system.HIDCore().DisableAllControllerConfiguration();
}
@ -291,6 +305,31 @@ void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
dialog.exec();
}
void QtControllerSelectorDialog::keyPressEvent(QKeyEvent* evt) {
const auto num_connected_players = static_cast<int>(
std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
[](const QGroupBox* player) { return player->isChecked(); }));
const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
if ((evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) && !parameters_met) {
// Display error message when trying to validate using "Enter" and "OK" button is disabled
ui->labelError->setVisible(true);
return;
} else if (evt->key() == Qt::Key_Left && num_connected_players > min_supported_players) {
// Remove a player if possible
connected_controller_checkboxes[num_connected_players - 1]->setChecked(false);
return;
} else if (evt->key() == Qt::Key_Right && num_connected_players < max_supported_players) {
// Add a player, if possible
ui->labelError->setVisible(false);
connected_controller_checkboxes[num_connected_players]->setChecked(true);
return;
}
QDialog::keyPressEvent(evt);
}
bool QtControllerSelectorDialog::CheckIfParametersMet() {
// Here, we check and validate the current configuration against all applicable parameters.
const auto num_connected_players = static_cast<int>(

View File

@ -34,6 +34,8 @@ class HIDCore;
enum class NpadStyleIndex : u8;
} // namespace Core::HID
class ControllerNavigation;
class QtControllerSelectorDialog final : public QDialog {
Q_OBJECT
@ -46,6 +48,8 @@ public:
int exec() override;
void keyPressEvent(QKeyEvent* evt) override;
private:
// Applies the current configuration.
void ApplyConfiguration();
@ -110,6 +114,8 @@ private:
Core::System& system;
ControllerNavigation* controller_navigation = nullptr;
// This is true if and only if all parameters are met. Otherwise, this is false.
// This determines whether the "OK" button can be clicked to exit the applet.
bool parameters_met{false};

View File

@ -2624,13 +2624,53 @@
</spacer>
</item>
<item alignment="Qt::AlignBottom">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<widget class="QWidget" name="closeButtons" native="true">
<layout class="QVBoxLayout" name="verticalLayout_46">
<property name="spacing">
<number>7</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelError">
<property name="enabled">
<bool>true</bool>
</property>
<property name="styleSheet">
<string notr="true">QLabel { color : red; }</string>
</property>
<property name="text">
<string>Not enough controllers</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="margin">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>

View File

@ -42,6 +42,9 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
for (auto* setting : Settings::values.linkage.by_category[category]) {
settings.push_back(setting);
}
for (auto* setting : UISettings::values.linkage.by_category[category]) {
settings.push_back(setting);
}
};
push(Settings::Category::Audio);

View File

@ -123,6 +123,8 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
connect(ui->show_compat, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
connect(ui->show_size, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
connect(ui->show_types, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
connect(ui->show_play_time, &QCheckBox::stateChanged, this,
&ConfigureUi::RequestGameListUpdate);
connect(ui->game_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureUi::RequestGameListUpdate);
connect(ui->folder_icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
@ -167,6 +169,7 @@ void ConfigureUi::ApplyConfiguration() {
UISettings::values.show_compat = ui->show_compat->isChecked();
UISettings::values.show_size = ui->show_size->isChecked();
UISettings::values.show_types = ui->show_types->isChecked();
UISettings::values.show_play_time = ui->show_play_time->isChecked();
UISettings::values.game_icon_size = ui->game_icon_size_combobox->currentData().toUInt();
UISettings::values.folder_icon_size = ui->folder_icon_size_combobox->currentData().toUInt();
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
@ -179,6 +182,7 @@ void ConfigureUi::ApplyConfiguration() {
const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
UISettings::values.screenshot_height.SetValue(height);
RequestGameListUpdate();
system.ApplySettings();
}
@ -194,6 +198,7 @@ void ConfigureUi::SetConfiguration() {
ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
ui->show_size->setChecked(UISettings::values.show_size.GetValue());
ui->show_types->setChecked(UISettings::values.show_types.GetValue());
ui->show_play_time->setChecked(UISettings::values.show_play_time.GetValue());
ui->game_icon_size_combobox->setCurrentIndex(
ui->game_icon_size_combobox->findData(UISettings::values.game_icon_size.GetValue()));
ui->folder_icon_size_combobox->setCurrentIndex(

View File

@ -104,6 +104,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="show_play_time">
<property name="text">
<string>Show Play Time Column</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="game_icon_size_qhbox_layout_2">
<item>

View File

@ -29,9 +29,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
INSERT(Settings, sink_id, "Output Engine:", "");
INSERT(Settings, audio_output_device_id, "Output Device:", "");
INSERT(Settings, audio_input_device_id, "Input Device:", "");
INSERT(Settings, audio_muted, "Mute audio when in background", "");
INSERT(Settings, audio_muted, "Mute audio", "");
INSERT(Settings, volume, "Volume:", "");
INSERT(Settings, dump_audio_commands, "", "");
INSERT(UISettings, mute_when_in_background, "Mute audio when in background", "");
// Core
INSERT(Settings, use_multi_core, "Multicore CPU Emulation", "");

View File

@ -312,8 +312,10 @@ void GameList::OnFilterCloseClicked() {
}
GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvider* provider_,
Core::System& system_, GMainWindow* parent)
: QWidget{parent}, vfs{std::move(vfs_)}, provider{provider_}, system{system_} {
PlayTime::PlayTimeManager& play_time_manager_, Core::System& system_,
GMainWindow* parent)
: QWidget{parent}, vfs{std::move(vfs_)}, provider{provider_},
play_time_manager{play_time_manager_}, system{system_} {
watcher = new QFileSystemWatcher(this);
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory);
@ -340,6 +342,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat);
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
item_model->setSortRole(GameListItemPath::SortRole);
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
@ -548,6 +551,7 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
QAction* remove_update = remove_menu->addAction(tr("Remove Installed Update"));
QAction* remove_dlc = remove_menu->addAction(tr("Remove All Installed DLC"));
QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration"));
QAction* remove_play_time_data = remove_menu->addAction(tr("Remove Play Time Data"));
QAction* remove_cache_storage = remove_menu->addAction(tr("Remove Cache Storage"));
QAction* remove_gl_shader_cache = remove_menu->addAction(tr("Remove OpenGL Pipeline Cache"));
QAction* remove_vk_shader_cache = remove_menu->addAction(tr("Remove Vulkan Pipeline Cache"));
@ -560,9 +564,9 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
#ifndef WIN32
QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut"));
QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop"));
#ifndef WIN32
QAction* create_applications_menu_shortcut =
shortcut_menu->addAction(tr("Add to Applications Menu"));
#endif
@ -622,6 +626,8 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path);
});
connect(remove_play_time_data, &QAction::triggered,
[this, program_id]() { emit RemovePlayTimeRequested(program_id); });
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path);
});
@ -638,10 +644,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
});
#ifndef WIN32
connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop);
});
#ifndef WIN32
connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications);
});
@ -790,6 +796,7 @@ void GameList::RetranslateUI() {
item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
item_model->setHeaderData(COLUMN_PLAY_TIME, Qt::Horizontal, tr("Play time"));
}
void GameListSearchField::changeEvent(QEvent* event) {
@ -817,6 +824,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
tree_view->setColumnHidden(COLUMN_COMPATIBILITY, !UISettings::values.show_compat);
tree_view->setColumnHidden(COLUMN_FILE_TYPE, !UISettings::values.show_types);
tree_view->setColumnHidden(COLUMN_SIZE, !UISettings::values.show_size);
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
// Delete any rows that might already exist if we're repopulating
item_model->removeRows(0, item_model->rowCount());
@ -825,7 +833,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
emit ShouldCancelWorker();
GameListWorker* worker =
new GameListWorker(vfs, provider, game_dirs, compatibility_list, system);
new GameListWorker(vfs, provider, game_dirs, compatibility_list, play_time_manager, system);
connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
connect(worker, &GameListWorker::DirEntryReady, this, &GameList::AddDirEntry,

View File

@ -18,6 +18,7 @@
#include "core/core.h"
#include "uisettings.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/play_time_manager.h"
namespace Core {
class System;
@ -75,11 +76,13 @@ public:
COLUMN_ADD_ONS,
COLUMN_FILE_TYPE,
COLUMN_SIZE,
COLUMN_PLAY_TIME,
COLUMN_COUNT, // Number of columns
};
explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs_,
FileSys::ManualContentProvider* provider_, Core::System& system_,
FileSys::ManualContentProvider* provider_,
PlayTime::PlayTimeManager& play_time_manager_, Core::System& system_,
GMainWindow* parent = nullptr);
~GameList() override;
@ -113,6 +116,7 @@ signals:
void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type);
void RemoveFileRequested(u64 program_id, GameListRemoveTarget target,
const std::string& game_path);
void RemovePlayTimeRequested(u64 program_id);
void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
void VerifyIntegrityRequested(const std::string& game_path);
void CopyTIDRequested(u64 program_id);
@ -168,6 +172,7 @@ private:
friend class GameListSearchField;
const PlayTime::PlayTimeManager& play_time_manager;
Core::System& system;
};

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