Compare commits

..

22 Commits

Author SHA1 Message Date
12101111
f78f82e08d input_common: rename PAGE_SIZE to avoid conflict
See also: https://github.com/yuzu-emu/yuzu/issues/8779
2023-05-30 16:59:06 +08:00
liamwhite
53fd08b360 Merge pull request #10484 from Morph1984/fmt10
externals: Update to fmt 10 and add format_as formatter for BitField
2023-05-28 16:33:42 -04:00
Morph
124dd86820 CMakeLists: Rollback minimum to fmt 9
The mingw fmt package https://aur.archlinux.org/packages/mingw-w64-fmt has not been updated yet.
2023-05-28 15:20:35 -04:00
Morph
9950a388d2 externals: Update to fmt 10 and add format_as formatter for BitField
Implicit conversions are now disallowed in fmt 10. Use format_as to convert to the underlying type.
2023-05-28 15:05:55 -04:00
liamwhite
b26018e2e6 Merge pull request #10475 from ameerj/microprofile-workaround
microprofile: Avoid crashing due to OOB stackPos
2023-05-28 13:18:54 -04:00
liamwhite
381caf4c00 Merge pull request #10483 from ameerj/gl-cpu-astc
gl_texture_cache: Fix ASTC CPU decoding with compression disabled
2023-05-28 13:18:31 -04:00
liamwhite
379d4b5e6a Merge pull request #10280 from danilaml/cmake-bin-dir
Use TARGET_FILE_DIR generator expression
2023-05-28 13:18:06 -04:00
liamwhite
bf3f450211 Merge pull request #10283 from danilaml/support-interlaced-videos
Add support for deinterlaced video playback
2023-05-28 13:17:58 -04:00
liamwhite
09743fa681 Merge pull request #10376 from abouvier/cmake-default
cmake: apply defaults to all externals
2023-05-28 13:17:50 -04:00
liamwhite
93c17ee4da Merge pull request #10463 from liamwhite/this-is-why-we-need-g
vfs_concat: fix time complexity of read
2023-05-28 13:17:42 -04:00
liamwhite
18595738fd Merge pull request #10464 from liamwhite/clear-cache
qt: add menu item to remove cache storage
2023-05-28 13:17:33 -04:00
liamwhite
e994388b43 Merge pull request #10469 from Kelebek1/bc_state
Move buffer bindings to per-channel state
2023-05-28 13:17:26 -04:00
liamwhite
88ccc420b8 Merge pull request #10471 from Kelebek1/test2
Wait indefinitely when audio buffer queue is too big
2023-05-28 13:17:12 -04:00
ameerj
ea2e155b0b gl_texture_cache: Fix ASTC CPU decoding with compression disabled
gl_format was incorrectly being overwritten when compression was disabled
2023-05-28 13:14:51 -04:00
ameerj
fee91096ca microprofile: Avoid crashing due to OOB stack pos 2023-05-27 22:24:22 -04:00
Kelebek1
9c2b211f12 Audren wait as suggested by ByLaws 2023-05-27 17:38:07 +01:00
Liam
fcd48eb239 qt: add menu item to remove cache storage 2023-05-26 23:29:44 -04:00
Liam
0596a4afb1 vfs_concat: fix time complexity of read 2023-05-26 16:07:38 -04:00
Alexandre Bouvier
9c3c7ec009 cmake: apply defaults to all externals 2023-05-24 04:57:04 +02:00
Danila Malyutin
7701a00a02 Add support for deinterlaced videos playback
This is a follow up to #10254 to improve the playback of cut scenes in Layton's Mystery Journey.
It uses ffmpeg's yadif filter for deinterlacing.
2023-05-22 01:43:44 +04:00
Danila Malyutin
7325fb054d Fixup upload.ps1 for GHA
No extra folders are created with ninja generator after previous CMake fixes.
2023-05-14 01:23:07 +03:00
Danila Malyutin
c9c5d140b8 Use TARGET_FILE_DIR generator expression
Use $<TARGET_FILE_DIR:...> where appropriate instead of trying to guess where the binary will end up.
2023-05-13 23:58:17 +04:00
28 changed files with 321 additions and 118 deletions

View File

@@ -26,7 +26,11 @@ $env:BUILD_ZIP = $MSVC_BUILD_ZIP
$env:BUILD_SYMBOLS = $MSVC_BUILD_PDB
$env:BUILD_UPDATE = $MSVC_SEVENZIP
$BUILD_DIR = ".\build\bin\Release"
if (Test-Path -Path ".\build\bin\Release") {
$BUILD_DIR = ".\build\bin\Release"
} else {
$BUILD_DIR = ".\build\bin\"
}
# Cleanup unneeded data in submodules
git submodule foreach git clean -fxd

View File

@@ -453,6 +453,7 @@ endif()
# List of all FFmpeg components required
set(FFmpeg_COMPONENTS
avcodec
avfilter
avutil
swscale)

View File

@@ -3,7 +3,7 @@
function(copy_yuzu_FFmpeg_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
file(READ "${FFmpeg_PATH}/requirements.txt" FFmpeg_REQUIRED_DLLS)
string(STRIP "${FFmpeg_REQUIRED_DLLS}" FFmpeg_REQUIRED_DLLS)
windows_copy_files(${target_dir} ${FFmpeg_DLL_DIR} ${DLL_DEST} ${FFmpeg_REQUIRED_DLLS})

View File

@@ -4,7 +4,7 @@
function(copy_yuzu_Qt5_deps target_dir)
include(WindowsCopyFiles)
if (MSVC)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
else()
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/")

View File

@@ -3,6 +3,6 @@
function(copy_yuzu_SDL_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
windows_copy_files(${target_dir} ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll)
endfunction(copy_yuzu_SDL_deps)

View File

@@ -8,15 +8,21 @@ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
# Disable tests in all externals supporting the standard option name
set(BUILD_TESTING OFF)
# Build only static externals
set(BUILD_SHARED_LIBS OFF)
# Skip install rules for all externals
set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
# xbyak
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
add_subdirectory(xbyak EXCLUDE_FROM_ALL)
add_subdirectory(xbyak)
endif()
# Dynarmic
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
set(DYNARMIC_IGNORE_ASSERTS ON)
add_subdirectory(dynarmic EXCLUDE_FROM_ALL)
add_subdirectory(dynarmic)
add_library(dynarmic::dynarmic ALIAS dynarmic)
endif()
@@ -34,7 +40,7 @@ if (NOT TARGET inih::INIReader)
endif()
# mbedtls
add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
add_subdirectory(mbedtls)
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
# MicroProfile
@@ -48,7 +54,7 @@ endif()
# libusb
if (ENABLE_LIBUSB AND NOT TARGET libusb::usb)
add_subdirectory(libusb EXCLUDE_FROM_ALL)
add_subdirectory(libusb)
endif()
# SDL2
@@ -67,18 +73,16 @@ if (YUZU_USE_EXTERNAL_SDL2)
set(HIDAPI ON)
endif()
set(SDL_STATIC ON)
set(SDL_SHARED OFF)
if (APPLE)
set(SDL_FILE ON)
endif()
add_subdirectory(SDL EXCLUDE_FROM_ALL)
add_subdirectory(SDL)
endif()
# ENet
if (NOT TARGET enet::enet)
add_subdirectory(enet EXCLUDE_FROM_ALL)
add_subdirectory(enet)
target_include_directories(enet INTERFACE ./enet/include)
add_library(enet::enet ALIAS enet)
endif()
@@ -86,24 +90,26 @@ endif()
# Cubeb
if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
set(BUILD_TESTS OFF)
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
set(BUILD_TOOLS OFF)
add_subdirectory(cubeb)
add_library(cubeb::cubeb ALIAS cubeb)
endif()
# DiscordRPC
if (USE_DISCORD_PRESENCE AND NOT TARGET DiscordRPC::discord-rpc)
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
set(BUILD_EXAMPLES OFF)
add_subdirectory(discord-rpc)
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)
endif()
# Sirit
add_subdirectory(sirit EXCLUDE_FROM_ALL)
add_subdirectory(sirit)
# httplib
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
set(HTTPLIB_REQUIRE_OPENSSL ON)
add_subdirectory(cpp-httplib EXCLUDE_FROM_ALL)
add_subdirectory(cpp-httplib)
endif()
# cpp-jwt
@@ -111,12 +117,12 @@ if (ENABLE_WEB_SERVICE AND NOT TARGET cpp-jwt::cpp-jwt)
set(CPP_JWT_BUILD_EXAMPLES OFF)
set(CPP_JWT_BUILD_TESTS OFF)
set(CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF)
add_subdirectory(cpp-jwt EXCLUDE_FROM_ALL)
add_subdirectory(cpp-jwt)
endif()
# Opus
if (NOT TARGET Opus::opus)
add_subdirectory(opus EXCLUDE_FROM_ALL)
add_subdirectory(opus)
endif()
# FFMpeg
@@ -130,16 +136,14 @@ endif()
# Vulkan-Headers
if (YUZU_USE_EXTERNAL_VULKAN_HEADERS)
add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL)
add_subdirectory(Vulkan-Headers)
endif()
if (NOT TARGET LLVM::Demangle)
add_library(demangle STATIC)
add_library(demangle demangle/ItaniumDemangle.cpp)
target_include_directories(demangle PUBLIC ./demangle)
target_sources(demangle PRIVATE demangle/ItaniumDemangle.cpp)
add_library(LLVM::Demangle ALIAS demangle)
endif()
add_library(stb STATIC)
add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb)
target_sources(stb PRIVATE stb/stb_dxt.cpp)

View File

@@ -131,7 +131,6 @@ if (NOT WIN32)
COMMAND
/bin/bash ${FFmpeg_PREFIX}/configure
--disable-avdevice
--disable-avfilter
--disable-avformat
--disable-doc
--disable-everything
@@ -143,6 +142,7 @@ if (NOT WIN32)
--enable-decoder=h264
--enable-decoder=vp8
--enable-decoder=vp9
--enable-filter=yadif
--cc="${FFmpeg_CC}"
--cxx="${FFmpeg_CXX}"
${FFmpeg_HWACCEL_FLAGS}
@@ -199,7 +199,7 @@ if (NOT WIN32)
endif()
else(WIN32)
# Use yuzu FFmpeg binaries
set(FFmpeg_EXT_NAME "ffmpeg-4.4")
set(FFmpeg_EXT_NAME "ffmpeg-5.1.3")
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
set(FFmpeg_FOUND YES)
@@ -210,6 +210,7 @@ else(WIN32)
set(FFmpeg_LIBRARIES
${FFmpeg_LIBRARY_DIR}/swscale.lib
${FFmpeg_LIBRARY_DIR}/avcodec.lib
${FFmpeg_LIBRARY_DIR}/avfilter.lib
${FFmpeg_LIBRARY_DIR}/avutil.lib
CACHE PATH "Paths to FFmpeg libraries" FORCE)
# exported variables

View File

@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2015 Yuri Kunde Schlesner <yuriks@yuriks.net>
# SPDX-License-Identifier: GPL-2.0-or-later
add_library(glad STATIC
add_library(glad
src/glad.c
include/KHR/khrplatform.h
include/glad/glad.h

View File

@@ -122,7 +122,7 @@ else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_compile_options(/utf-8)
endif()
add_library(usb STATIC EXCLUDE_FROM_ALL
add_library(usb
libusb/libusb/core.c
libusb/libusb/core.c
libusb/libusb/descriptor.c

View File

@@ -1697,7 +1697,13 @@ void MicroProfileFlip()
{
int nTimer = MicroProfileLogTimerIndex(LE);
uint8_t nGroup = pTimerToGroup[nTimer];
MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);
// To avoid crashing due to OOB memory accesses/asserts
// simply skip this iteration
// MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);
if (nStackPos >= MICROPROFILE_STACK_MAX) {
break;
}
MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS);
pGroupStackPos[nGroup]++;
pStack[nStackPos++] = k;

View File

@@ -23,7 +23,7 @@ else()
endif()
endif()
add_library(opus STATIC
add_library(opus
# CELT sources
opus/celt/bands.c
opus/celt/celt.c

View File

@@ -273,6 +273,9 @@ void SinkStream::WaitFreeSpace() {
std::unique_lock lk{release_mutex};
release_cv.wait_for(lk, std::chrono::milliseconds(5),
[this]() { return queued_buffers < max_queue_size; });
if (queued_buffers > max_queue_size + 3) {
release_cv.wait(lk, [this]() { return queued_buffers < max_queue_size; });
}
}
} // namespace AudioCore::Sink

View File

@@ -188,3 +188,8 @@ private:
template <std::size_t Position, std::size_t Bits, typename T>
using BitFieldBE = BitField<Position, Bits, T, BETag>;
template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
inline auto format_as(BitField<Position, Bits, T, EndianTag> bitfield) {
return bitfield.Value();
}

View File

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

View File

@@ -140,7 +140,8 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
return nullptr;
RomFSBuildContext ctx{dir, ext};
return ConcatenatedVfsFile::MakeConcatenatedFile(0, ctx.Build(), dir->GetName());
auto file_map = ctx.Build();
return ConcatenatedVfsFile::MakeConcatenatedFile(0, file_map, dir->GetName());
}
} // namespace FileSys

View File

@@ -10,84 +10,105 @@
namespace FileSys {
static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFile>& map) {
const auto last_valid = --map.end();
for (auto iter = map.begin(); iter != last_valid;) {
const auto old = iter++;
if (old->first + old->second->GetSize() != iter->first) {
ConcatenatedVfsFile::ConcatenatedVfsFile(ConcatenationMap&& concatenation_map_, std::string&& name_)
: concatenation_map(std::move(concatenation_map_)), name(std::move(name_)) {
DEBUG_ASSERT(this->VerifyContinuity());
}
bool ConcatenatedVfsFile::VerifyContinuity() const {
u64 last_offset = 0;
for (auto& entry : concatenation_map) {
if (entry.offset != last_offset) {
return false;
}
last_offset = entry.offset + entry.file->GetSize();
}
return map.begin()->first == 0;
}
ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name_)
: name(std::move(name_)) {
std::size_t next_offset = 0;
for (const auto& file : files_) {
files.emplace(next_offset, file);
next_offset += file->GetSize();
}
}
ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name_)
: files(std::move(files_)), name(std::move(name_)) {
ASSERT(VerifyConcatenationMapContinuity(files));
return true;
}
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files,
std::string name) {
if (files.empty())
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualFile>& files,
std::string&& name) {
// Fold trivial cases.
if (files.empty()) {
return nullptr;
if (files.size() == 1)
return files[0];
}
if (files.size() == 1) {
return files.front();
}
return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
// Make the concatenation map from the input.
std::vector<ConcatenationEntry> concatenation_map;
concatenation_map.reserve(files.size());
u64 last_offset = 0;
for (auto& file : files) {
concatenation_map.emplace_back(ConcatenationEntry{
.offset = last_offset,
.file = file,
});
last_offset += file->GetSize();
}
return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
}
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
std::multimap<u64, VirtualFile> files,
std::string name) {
if (files.empty())
const std::multimap<u64, VirtualFile>& files,
std::string&& name) {
// Fold trivial cases.
if (files.empty()) {
return nullptr;
if (files.size() == 1)
}
if (files.size() == 1) {
return files.begin()->second;
const auto last_valid = --files.end();
for (auto iter = files.begin(); iter != last_valid;) {
const auto old = iter++;
if (old->first + old->second->GetSize() != iter->first) {
files.emplace(old->first + old->second->GetSize(),
std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first -
old->second->GetSize()));
}
}
// Ensure the map starts at offset 0 (start of file), otherwise pad to fill.
if (files.begin()->first != 0)
files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first));
// Make the concatenation map from the input.
std::vector<ConcatenationEntry> concatenation_map;
return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
concatenation_map.reserve(files.size());
u64 last_offset = 0;
// Iteration of a multimap is ordered, so offset will be strictly non-decreasing.
for (auto& [offset, file] : files) {
if (offset > last_offset) {
concatenation_map.emplace_back(ConcatenationEntry{
.offset = last_offset,
.file = std::make_shared<StaticVfsFile>(filler_byte, offset - last_offset),
});
}
concatenation_map.emplace_back(ConcatenationEntry{
.offset = offset,
.file = file,
});
last_offset = offset + file->GetSize();
}
return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
}
std::string ConcatenatedVfsFile::GetName() const {
if (files.empty()) {
if (concatenation_map.empty()) {
return "";
}
if (!name.empty()) {
return name;
}
return files.begin()->second->GetName();
return concatenation_map.front().file->GetName();
}
std::size_t ConcatenatedVfsFile::GetSize() const {
if (files.empty()) {
if (concatenation_map.empty()) {
return 0;
}
return files.rbegin()->first + files.rbegin()->second->GetSize();
return concatenation_map.back().offset + concatenation_map.back().file->GetSize();
}
bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
@@ -95,10 +116,10 @@ bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
}
VirtualDir ConcatenatedVfsFile::GetContainingDirectory() const {
if (files.empty()) {
if (concatenation_map.empty()) {
return nullptr;
}
return files.begin()->second->GetContainingDirectory();
return concatenation_map.front().file->GetContainingDirectory();
}
bool ConcatenatedVfsFile::IsWritable() const {
@@ -110,25 +131,45 @@ bool ConcatenatedVfsFile::IsReadable() const {
}
std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
auto entry = --files.end();
for (auto iter = files.begin(); iter != files.end(); ++iter) {
if (iter->first > offset) {
entry = --iter;
const ConcatenationEntry key{
.offset = offset,
.file = nullptr,
};
// Read nothing if the map is empty.
if (concatenation_map.empty()) {
return 0;
}
// Binary search to find the iterator to the first position we can check.
// It must exist, since we are not empty and are comparing unsigned integers.
auto it = std::prev(std::upper_bound(concatenation_map.begin(), concatenation_map.end(), key));
u64 cur_length = length;
u64 cur_offset = offset;
while (cur_length > 0 && it != concatenation_map.end()) {
// Check if we can read the file at this position.
const auto& file = it->file;
const u64 file_offset = it->offset;
const u64 file_size = file->GetSize();
if (cur_offset >= file_offset + file_size) {
// Entirely out of bounds read.
break;
}
// Read the file at this position.
const u64 intended_read_size = std::min<u64>(cur_length, file_size);
const u64 actual_read_size =
file->Read(data + (cur_offset - offset), intended_read_size, cur_offset - file_offset);
// Update tracking.
cur_offset += actual_read_size;
cur_length -= actual_read_size;
it++;
}
if (entry->first + entry->second->GetSize() <= offset)
return 0;
const auto read_in =
std::min<u64>(entry->first + entry->second->GetSize() - offset, entry->second->GetSize());
if (length > read_in) {
return entry->second->Read(data, read_in, offset - entry->first) +
Read(data + read_in, length - read_in, offset + read_in);
}
return entry->second->Read(data, std::min<u64>(read_in, length), offset - entry->first);
return cur_offset - offset;
}
std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {

View File

@@ -3,6 +3,7 @@
#pragma once
#include <compare>
#include <map>
#include <memory>
#include "core/file_sys/vfs.h"
@@ -12,19 +13,33 @@ namespace FileSys {
// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
// read-only.
class ConcatenatedVfsFile : public VfsFile {
explicit ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name_);
explicit ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name_);
private:
struct ConcatenationEntry {
u64 offset;
VirtualFile file;
auto operator<=>(const ConcatenationEntry& other) const {
return this->offset <=> other.offset;
}
};
using ConcatenationMap = std::vector<ConcatenationEntry>;
explicit ConcatenatedVfsFile(std::vector<ConcatenationEntry>&& concatenation_map,
std::string&& name);
bool VerifyContinuity() const;
public:
~ConcatenatedVfsFile() override;
/// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
static VirtualFile MakeConcatenatedFile(std::vector<VirtualFile> files, std::string name);
static VirtualFile MakeConcatenatedFile(const std::vector<VirtualFile>& files,
std::string&& name);
/// Convenience function that turns a map of offsets to files into a concatenated file, filling
/// gaps with a given filler byte.
static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::multimap<u64, VirtualFile> files,
std::string name);
static VirtualFile MakeConcatenatedFile(u8 filler_byte,
const std::multimap<u64, VirtualFile>& files,
std::string&& name);
std::string GetName() const override;
std::size_t GetSize() const override;
@@ -37,8 +52,7 @@ public:
bool Rename(std::string_view new_name) override;
private:
// Maps starting offset to file -- more efficient.
std::multimap<u64, VirtualFile> files;
ConcatenationMap concatenation_map;
std::string name;
};

View File

@@ -528,9 +528,9 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid,
}
NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const {
constexpr u8 PAGE_SIZE = 4;
constexpr u8 NFC_PAGE_SIZE = 4;
if (static_cast<std::size_t>(page * PAGE_SIZE) + size >= data.size()) {
if (static_cast<std::size_t>(page * NFC_PAGE_SIZE) + size >= data.size()) {
return {};
}
@@ -539,7 +539,7 @@ NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8>
.data_size = size,
.data = {},
};
std::memcpy(chunk.data.data(), data.data() + (page * PAGE_SIZE), size);
std::memcpy(chunk.data.data(), data.data() + (page * NFC_PAGE_SIZE), size);
return chunk;
}

View File

@@ -5,6 +5,7 @@
#include <fstream>
#include <vector>
#include "common/assert.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "video_core/host1x/codecs/codec.h"
#include "video_core/host1x/codecs/h264.h"
@@ -14,6 +15,8 @@
#include "video_core/memory_manager.h"
extern "C" {
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#ifdef LIBVA_FOUND
// for querying VAAPI driver information
@@ -85,6 +88,10 @@ Codec::~Codec() {
// Free libav memory
avcodec_free_context(&av_codec_ctx);
av_buffer_unref(&av_gpu_decoder);
if (filters_initialized) {
avfilter_graph_free(&av_filter_graph);
}
}
bool Codec::CreateGpuAvDevice() {
@@ -167,6 +174,62 @@ void Codec::InitializeGpuDecoder() {
av_codec_ctx->get_format = GetGpuFormat;
}
void Codec::InitializeAvFilters(AVFrame* frame) {
const AVFilter* buffer_src = avfilter_get_by_name("buffer");
const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
AVFilterInOut* inputs = avfilter_inout_alloc();
AVFilterInOut* outputs = avfilter_inout_alloc();
SCOPE_EXIT({
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
});
// Don't know how to get the accurate time_base but it doesn't matter for yadif filter
// so just use 1/1 to make buffer filter happy
std::string args = fmt::format("video_size={}x{}:pix_fmt={}:time_base=1/1", frame->width,
frame->height, frame->format);
av_filter_graph = avfilter_graph_alloc();
int ret = avfilter_graph_create_filter(&av_filter_src_ctx, buffer_src, "in", args.c_str(),
nullptr, av_filter_graph);
if (ret < 0) {
LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter source error: {}", ret);
return;
}
ret = avfilter_graph_create_filter(&av_filter_sink_ctx, buffer_sink, "out", nullptr, nullptr,
av_filter_graph);
if (ret < 0) {
LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter sink error: {}", ret);
return;
}
inputs->name = av_strdup("out");
inputs->filter_ctx = av_filter_sink_ctx;
inputs->pad_idx = 0;
inputs->next = nullptr;
outputs->name = av_strdup("in");
outputs->filter_ctx = av_filter_src_ctx;
outputs->pad_idx = 0;
outputs->next = nullptr;
const char* description = "yadif=1:-1:0";
ret = avfilter_graph_parse_ptr(av_filter_graph, description, &inputs, &outputs, nullptr);
if (ret < 0) {
LOG_ERROR(Service_NVDRV, "avfilter_graph_parse_ptr error: {}", ret);
return;
}
ret = avfilter_graph_config(av_filter_graph, nullptr);
if (ret < 0) {
LOG_ERROR(Service_NVDRV, "avfilter_graph_config error: {}", ret);
return;
}
filters_initialized = true;
}
void Codec::Initialize() {
const AVCodecID codec = [&] {
switch (current_codec) {
@@ -271,8 +334,34 @@ void Codec::Decode() {
UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
return;
}
av_frames.push(std::move(final_frame));
if (av_frames.size() > 10) {
if (!final_frame->interlaced_frame) {
av_frames.push(std::move(final_frame));
} else {
if (!filters_initialized) {
InitializeAvFilters(final_frame.get());
}
if (const int ret = av_buffersrc_add_frame_flags(av_filter_src_ctx, final_frame.get(),
AV_BUFFERSRC_FLAG_KEEP_REF);
ret) {
LOG_DEBUG(Service_NVDRV, "av_buffersrc_add_frame_flags error {}", ret);
return;
}
while (true) {
auto filter_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
int ret = av_buffersink_get_frame(av_filter_sink_ctx, filter_frame.get());
if (ret == AVERROR(EAGAIN) || ret == AVERROR(AVERROR_EOF))
break;
if (ret < 0) {
LOG_DEBUG(Service_NVDRV, "av_buffersink_get_frame error {}", ret);
return;
}
av_frames.push(std::move(filter_frame));
}
}
while (av_frames.size() > 10) {
LOG_TRACE(Service_NVDRV, "av_frames.push overflow dropped frame");
av_frames.pop();
}

View File

@@ -15,6 +15,7 @@ extern "C" {
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#include <libavcodec/avcodec.h>
#include <libavfilter/avfilter.h>
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
@@ -61,17 +62,24 @@ public:
private:
void InitializeAvCodecContext();
void InitializeAvFilters(AVFrame* frame);
void InitializeGpuDecoder();
bool CreateGpuAvDevice();
bool initialized{};
bool filters_initialized{};
Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None};
const AVCodec* av_codec{nullptr};
AVCodecContext* av_codec_ctx{nullptr};
AVBufferRef* av_gpu_decoder{nullptr};
AVFilterContext* av_filter_src_ctx{nullptr};
AVFilterContext* av_filter_sink_ctx{nullptr};
AVFilterGraph* av_filter_graph{nullptr};
Host1x::Host1x& host1x;
const Host1x::NvdecCommon::NvdecRegisters& state;
std::unique_ptr<Decoder::H264> h264_decoder;

View File

@@ -439,6 +439,11 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
return GL_R32UI;
}
[[nodiscard]] bool IsAstcRecompressionEnabled() {
return Settings::values.astc_recompression.GetValue() !=
Settings::AstcRecompression::Uncompressed;
}
[[nodiscard]] GLenum SelectAstcFormat(PixelFormat format, bool is_srgb) {
switch (Settings::values.astc_recompression.GetValue()) {
case Settings::AstcRecompression::Bc1:
@@ -760,7 +765,7 @@ Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_,
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
if (IsPixelFormatASTC(info.format)) {
if (IsPixelFormatASTC(info.format) && IsAstcRecompressionEnabled()) {
gl_internal_format = SelectAstcFormat(info.format, is_srgb);
gl_format = GL_NONE;
}
@@ -1155,7 +1160,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
const bool is_srgb = IsPixelFormatSRGB(info.format);
internal_format = is_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8;
if (IsPixelFormatASTC(info.format)) {
if (IsPixelFormatASTC(info.format) && IsAstcRecompressionEnabled()) {
internal_format = SelectAstcFormat(info.format, is_srgb);
}
} else {

View File

@@ -378,11 +378,7 @@ if(UNIX AND NOT APPLE)
endif()
if (WIN32 AND QT_VERSION VERSION_GREATER_EQUAL 6)
if (MSVC AND NOT ${CMAKE_GENERATOR} STREQUAL "Ninja")
set(YUZU_EXE_DIR "${CMAKE_BINARY_DIR}/bin/$<CONFIG>")
else()
set(YUZU_EXE_DIR "${CMAKE_BINARY_DIR}/bin")
endif()
set(YUZU_EXE_DIR "$<TARGET_FILE_DIR:yuzu>")
add_custom_command(TARGET yuzu POST_BUILD COMMAND ${WINDEPLOYQT_EXECUTABLE} "${YUZU_EXE_DIR}/yuzu.exe" --dir "${YUZU_EXE_DIR}" --libdir "${YUZU_EXE_DIR}" --plugindir "${YUZU_EXE_DIR}/plugins" --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler --no-translations --verbose 0)
endif()

View File

@@ -544,6 +544,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_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"));
remove_menu->addSeparator();
@@ -614,6 +615,9 @@ 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_cache_storage, &QAction::triggered, [this, program_id, path] {
emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path);
});
connect(dump_romfs, &QAction::triggered, [this, program_id, path]() {
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal);
});

View File

@@ -45,6 +45,7 @@ enum class GameListRemoveTarget {
VkShaderCache,
AllShaderCache,
CustomConfiguration,
CacheStorage,
};
enum class DumpRomFSTarget {

View File

@@ -2323,6 +2323,8 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
return tr("Delete All Transferable Shader Caches?");
case GameListRemoveTarget::CustomConfiguration:
return tr("Remove Custom Game Configuration?");
case GameListRemoveTarget::CacheStorage:
return tr("Remove Cache Storage?");
default:
return QString{};
}
@@ -2346,6 +2348,9 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
case GameListRemoveTarget::CustomConfiguration:
RemoveCustomConfiguration(program_id, game_path);
break;
case GameListRemoveTarget::CacheStorage:
RemoveCacheStorage(program_id);
break;
}
}
@@ -2435,6 +2440,21 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g
}
}
void GMainWindow::RemoveCacheStorage(u64 program_id) {
const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
auto vfs_nand_dir =
vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read);
const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
*system, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
FileSys::SaveDataType::CacheStorage, 0 /* program_id */, {}, 0);
const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
// Not an error if it wasn't cleared.
Common::FS::RemoveDirRecursively(path);
}
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path,
DumpRomFSTarget target) {
const auto failed = [this] {

View File

@@ -370,6 +370,7 @@ private:
void RemoveVulkanDriverPipelineCache(u64 program_id);
void RemoveAllTransferableShaderCaches(u64 program_id);
void RemoveCustomConfiguration(u64 program_id, const std::string& game_path);
void RemoveCacheStorage(u64 program_id);
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
InstallResult InstallNSPXCI(const QString& filename);
InstallResult InstallNCA(const QString& filename);

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "yuzu",
"builtin-baseline": "acc3bcf76b84ae5041c86ab55fe138ae7b8255c7",
"builtin-baseline": "656fcc6ab2b05c6d999b7eaca717027ac3738f71",
"version": "1.0",
"dependencies": [
"boost-algorithm",
@@ -53,7 +53,7 @@
},
{
"name": "fmt",
"version": "9.0.0"
"version": "10.0.0"
}
]
}