Compare commits

..

1 Commits

Author SHA1 Message Date
yuzubot
c5ab5f7772 Android #47 2023-08-22 00:57:13 +00:00
51 changed files with 115 additions and 779 deletions

View File

@@ -49,7 +49,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
cmake_dependent_option(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
@@ -63,8 +63,6 @@ option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
set(DEFAULT_ENABLE_OPENSSL ON)
if (ANDROID OR WIN32 OR APPLE)
# - Windows defaults to the Schannel backend.

View File

@@ -36,21 +36,3 @@ endif()
message(STATUS "Using bundled binaries at ${prefix}")
set(${prefix_var} "${prefix}" PARENT_SCOPE)
endfunction()
function(download_moltenvk_external platform version)
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
if (NOT EXISTS ${MOLTENVK_DIR})
if (NOT EXISTS ${MOLTENVK_TAR})
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar
${MOLTENVK_TAR} SHOW_PROGRESS)
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
endif()
# Add the MoltenVK library path to the prefix so find_library can locate it.
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
endfunction()

View File

@@ -95,7 +95,6 @@ android {
// builds a release build that doesn't need signing
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
register("relWithDebInfo") {
isDefault = true
resValue("string", "app_name_suffixed", "yuzu Debug Release")
signingConfig = signingConfigs.getByName("debug")
isMinifyEnabled = true
@@ -123,7 +122,6 @@ android {
flavorDimensions.add("version")
productFlavors {
create("mainline") {
isDefault = true
dimension = "version"
buildConfigField("Boolean", "PREMIUM", "false")
}
@@ -162,11 +160,6 @@ android {
}
}
tasks.create<Delete>("ktlintReset") {
delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
}
tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset")
tasks.getByPath("preBuild").dependsOn("ktlintCheck")
ktlint {

View File

@@ -25,7 +25,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:hasFragileUserData="false"
android:supportsRtl="true"
android:isGame="true"
android:appCategory="game"
android:localeConfig="@xml/locales_config"
android:banner="@drawable/tv_banner"
android:extractNativeLibs="true"

View File

@@ -11,7 +11,6 @@ import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
object GameHelper {
const val KEY_GAME_PATH = "game_path"
@@ -30,7 +29,15 @@ object GameHelper {
// Ensure keys are loaded so that ROM metadata can be decrypted.
NativeLibrary.reloadKeys()
addGamesRecursive(games, FileUtil.listFiles(context, gamesUri), 3)
val children = FileUtil.listFiles(context, gamesUri)
for (file in children) {
if (!file.isDirectory) {
// Check that the file has an extension we care about before trying to read out of it.
if (Game.extensions.contains(FileUtil.getExtension(file.uri))) {
games.add(getGame(file.uri))
}
}
}
// Cache list of games found on disk
val serializedGames = mutableSetOf<String>()
@@ -45,30 +52,6 @@ object GameHelper {
return games.toList()
}
private fun addGamesRecursive(
games: MutableList<Game>,
files: Array<MinimalDocumentFile>,
depth: Int
) {
if (depth <= 0) {
return
}
files.forEach {
if (it.isDirectory) {
addGamesRecursive(
games,
FileUtil.listFiles(YuzuApplication.appContext, it.uri),
depth - 1
)
} else {
if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
games.add(getGame(it.uri))
}
}
}
}
private fun getGame(uri: Uri): Game {
val filePath = uri.toString()
var name = NativeLibrary.getTitle(filePath)

View File

@@ -30,7 +30,6 @@
#include "core/cpu_manager.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs.h"
@@ -225,42 +224,6 @@ public:
m_system.Renderer().NotifySurfaceChanged();
}
void ConfigureFilesystemProvider(const std::string& filepath) {
const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read);
if (!file) {
return;
}
auto loader = Loader::GetLoader(m_system, file);
if (!loader) {
return;
}
const auto file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
return;
}
u64 program_id = 0;
const auto res2 = loader->ReadProgramId(program_id);
if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
m_manual_provider->AddEntry(FileSys::TitleType::Application,
FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()),
program_id, file);
} else if (res2 == Loader::ResultStatus::Success &&
(file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
const auto nsp = file_type == Loader::FileType::NSP
? std::make_shared<FileSys::NSP>(file)
: FileSys::XCI{file}.GetSecurePartitionNSP();
for (const auto& title : nsp->GetNCAs()) {
for (const auto& entry : title.second) {
m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first,
entry.second->GetBaseFile());
}
}
}
}
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
std::scoped_lock lock(m_mutex);
@@ -291,14 +254,8 @@ public:
std::move(android_keyboard), // Software Keyboard
nullptr, // Web Browser
});
// Initialize filesystem.
m_manual_provider = std::make_unique<FileSys::ManualContentProvider>();
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
m_manual_provider.get());
m_system.GetFileSystemController().CreateFactories(*m_vfs);
ConfigureFilesystemProvider(filepath);
// Initialize account manager
m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
@@ -532,7 +489,6 @@ private:
bool m_is_paused{};
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;

View File

@@ -207,7 +207,9 @@ const char* TranslateCategory(Category category) {
return "Miscellaneous";
}
void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info) {
void UpdateRescalingInfo() {
const auto setup = values.resolution_setup.GetValue();
auto& info = values.resolution_info;
info.downscale = false;
switch (setup) {
case ResolutionSetup::Res1_2X:
@@ -267,12 +269,6 @@ void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info)
info.active = info.up_scale != 1 || info.down_shift != 0;
}
void UpdateRescalingInfo() {
const auto setup = values.resolution_setup.GetValue();
auto& info = values.resolution_info;
TranslateResolutionInfo(setup, info);
}
void RestoreGlobalState(bool is_powered_on) {
// If a game is running, DO NOT restore the global settings state
if (is_powered_on) {

View File

@@ -525,7 +525,6 @@ std::string GetTimeZoneString(TimeZone time_zone);
void LogSettings();
void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info);
void UpdateRescalingInfo();
// Restore the global state of all applicable settings in the Values struct

View File

@@ -606,9 +606,9 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
const auto result = RemoveExistingEntry(title_id);
// Install Metadata File
const auto meta_result = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data);
if (meta_result != InstallResult::Success) {
return meta_result;
const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data);
if (res != InstallResult::Success) {
return res;
}
// Install all the other NCAs
@@ -621,19 +621,9 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
if (nca == nullptr) {
return InstallResult::ErrorCopyFailed;
}
if (nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
nca->GetTitleId() != title_id) {
// Create fake cnmt for patch to multiprogram application
const auto sub_nca_result =
InstallEntry(*nca, TitleType::Update, overwrite_if_exists, copy);
if (sub_nca_result != InstallResult::Success) {
return sub_nca_result;
}
continue;
}
const auto nca_result = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
if (nca_result != InstallResult::Success) {
return nca_result;
const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
if (res2 != InstallResult::Success) {
return res2;
}
}
@@ -673,8 +663,6 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
}
bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
bool removed_data = false;
const auto delete_nca = [this](const NcaID& id) {
const auto path = GetRelativePathFromNcaID(id, false, true, false);
@@ -718,18 +706,11 @@ bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
const auto deleted_html = delete_nca(html_id);
const auto deleted_legal = delete_nca(legal_id);
removed_data |= (deleted_meta || deleted_program || deleted_data || deleted_control ||
deleted_html || deleted_legal);
return deleted_meta && (deleted_meta || deleted_program || deleted_data ||
deleted_control || deleted_html || deleted_legal);
}
// If patch entries for any program exist in yuzu meta, remove them
for (u8 i = 0; i < 0x10; i++) {
const auto meta_dir = dir->CreateDirectoryRelative("yuzu_meta");
const auto filename = GetCNMTName(TitleType::Update, title_id + i);
removed_data |= meta_dir->DeleteFile(filename);
}
return removed_data;
return false;
}
InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,

View File

@@ -38,7 +38,7 @@ namespace {
*/
void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority,
KProcessAddress stack_top) {
const KProcessAddress entry_point = owner_process.GetEntryPoint();
const KProcessAddress entry_point = owner_process.GetPageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
KThread* thread = KThread::Create(system.Kernel());
@@ -358,21 +358,6 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
m_system_resource_size = metadata.GetSystemResourceSize();
m_image_size = code_size;
if (metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit) {
// For 39-bit processes, the ASLR region starts at 0x800'0000 and is ~512GiB large.
// However, some (buggy) programs/libraries like skyline incorrectly depend on the
// existence of ASLR pages before the entry point, so we will adjust the load address
// to point to about 2GiB into the ASLR region.
m_code_address = 0x8000'0000;
} else {
// All other processes can be mapped at the beginning of the code region.
if (metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is36Bit) {
m_code_address = 0x800'0000;
} else {
m_code_address = 0x20'0000;
}
}
KScopedResourceReservation memory_reservation(
m_resource_limit, LimitableResource::PhysicalMemoryMax, code_size + m_system_resource_size);
if (!memory_reservation.Succeeded()) {
@@ -383,15 +368,15 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// Initialize process address space
if (const Result result{m_page_table.InitializeForProcess(
metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application,
this->GetEntryPoint(), code_size, std::addressof(m_kernel.GetAppSystemResource()),
m_resource_limit, m_kernel.System().ApplicationMemory())};
0x8000000, code_size, std::addressof(m_kernel.GetAppSystemResource()), m_resource_limit,
m_kernel.System().ApplicationMemory())};
result.IsError()) {
R_RETURN(result);
}
// Map process code region
if (const Result result{m_page_table.MapProcessCode(this->GetEntryPoint(), code_size / PageSize,
KMemoryState::Code,
if (const Result result{m_page_table.MapProcessCode(m_page_table.GetCodeRegionStart(),
code_size / PageSize, KMemoryState::Code,
KMemoryPermission::None)};
result.IsError()) {
R_RETURN(result);

View File

@@ -177,10 +177,6 @@ public:
return m_program_id;
}
KProcessAddress GetEntryPoint() const {
return m_code_address;
}
/// Gets the resource limit descriptor for this process
KResourceLimit* GetResourceLimit() const;
@@ -489,9 +485,6 @@ private:
/// Address indicating the location of the process' dedicated TLS region.
KProcessAddress m_plr_address = 0;
/// Address indicating the location of the process's entry point.
KProcessAddress m_code_address = 0;
/// Random values for svcGetInfo RandomEntropy
std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{};

View File

@@ -4,7 +4,6 @@
#include <utility>
#include "common/assert.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/settings.h"
#include "core/core.h"
@@ -155,18 +154,10 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
std::string src_path(Common::FS::SanitizePath(src_path_));
std::string dest_path(Common::FS::SanitizePath(dest_path_));
auto src = backing->GetFileRelative(src_path);
auto dst = backing->GetFileRelative(dest_path);
if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
// Use more-optimized vfs implementation rename.
if (src == nullptr) {
if (src == nullptr)
return FileSys::ERROR_PATH_NOT_FOUND;
}
if (dst && Common::FS::Exists(dst->GetFullPath())) {
LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath());
return FileSys::ERROR_PATH_ALREADY_EXISTS;
}
if (!src->Rename(Common::FS::GetFilename(dest_path))) {
// TODO(DarkLordZach): Find a better error code for this
return ResultUnknown;

View File

@@ -204,11 +204,9 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
if (!mapping->fixed) {
auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
u32 page_size{mapping->big_page ? vm.big_page_size : VM::YUZU_PAGESIZE};
u64 aligned_size{Common::AlignUp(mapping->size, page_size)};
allocator.Free(static_cast<u32>(mapping->offset >> page_size_bits),
static_cast<u32>(aligned_size >> page_size_bits));
static_cast<u32>(mapping->size >> page_size_bits));
}
// Sparse mappings shouldn't be fully unmapped, just returned to their sparse state

View File

@@ -79,8 +79,8 @@ protected:
using HandlerFnP = void (Self::*)(HLERequestContext&);
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() {
return std::unique_lock{lock_service};
[[nodiscard]] std::scoped_lock<std::mutex> LockService() {
return std::scoped_lock{lock_service};
}
/// System context that the service operates under.

View File

@@ -1029,11 +1029,6 @@ BSD::~BSD() {
}
}
std::unique_lock<std::mutex> BSD::LockService() {
// Do not lock socket IClient instances.
return {};
}
BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
// clang-format off
static const FunctionInfo functions[] = {

View File

@@ -186,9 +186,6 @@ private:
// Callback identifier for the OnProxyPacketReceived event.
Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
protected:
virtual std::unique_lock<std::mutex> LockService() override;
};
class BSDCFG final : public ServiceFramework<BSDCFG> {

View File

@@ -139,6 +139,7 @@ private:
bool do_not_close_socket = false;
bool get_server_cert_chain = false;
std::shared_ptr<Network::SocketBase> socket;
bool did_set_host_name = false;
bool did_handshake = false;
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
@@ -173,7 +174,11 @@ private:
Result SetHostNameImpl(const std::string& hostname) {
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
ASSERT(!did_handshake);
return backend->SetHostName(hostname);
Result res = backend->SetHostName(hostname);
if (res == ResultSuccess) {
did_set_host_name = true;
}
return res;
}
Result SetVerifyOptionImpl(u32 option) {
@@ -203,6 +208,9 @@ private:
Result DoHandshakeImpl() {
ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
ASSERT_OR_EXECUTE_MSG(
did_set_host_name, { return ResultInternalError; },
"Expected SetHostName before DoHandshake");
Result res = backend->DoHandshake();
did_handshake = res.IsSuccess();
return res;

View File

@@ -167,8 +167,9 @@ public:
}
~SSLConnectionBackendOpenSSL() {
// this is null-tolerant:
// these are null-tolerant:
SSL_free(ssl);
BIO_free(bio);
}
static void KeyLogCallback(const SSL* ssl, const char* line) {

View File

@@ -31,9 +31,9 @@ CredHandle cred_handle;
static void OneTimeInit() {
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
schannel_cred.dwFlags =
SCH_USE_STRONG_CRYPTO | // don't allow insecure protocols
SCH_CRED_NO_SERVERNAME_CHECK | // don't validate server names
SCH_CRED_NO_DEFAULT_CREDS; // don't automatically present a client certificate
SCH_USE_STRONG_CRYPTO | // don't allow insecure protocols
SCH_CRED_AUTO_CRED_VALIDATION | // validate certs
SCH_CRED_NO_DEFAULT_CREDS; // don't automatically present a client certificate
// ^ I'm assuming that nobody would want to connect Yuzu to a
// service that requires some OS-provided corporate client
// certificate, and presenting one to some arbitrary server
@@ -227,15 +227,16 @@ public:
ciphertext_read_buf.size());
}
char* hostname_ptr = hostname ? const_cast<char*>(hostname->c_str()) : nullptr;
const SECURITY_STATUS ret = InitializeSecurityContextA(
&cred_handle, initial_call_done ? &ctxt : nullptr, hostname_ptr, req,
0, // Reserved1
0, // TargetDataRep not used with Schannel
initial_call_done ? &input_desc : nullptr,
0, // Reserved2
initial_call_done ? nullptr : &ctxt, &output_desc, &attr,
nullptr); // ptsExpiry
const SECURITY_STATUS ret =
InitializeSecurityContextA(&cred_handle, initial_call_done ? &ctxt : nullptr,
// Caller ensured we have set a hostname:
const_cast<char*>(hostname.value().c_str()), req,
0, // Reserved1
0, // TargetDataRep not used with Schannel
initial_call_done ? &input_desc : nullptr,
0, // Reserved2
initial_call_done ? nullptr : &ctxt, &output_desc, &attr,
nullptr); // ptsExpiry
if (output_buffers[0].pvBuffer) {
const std::span span(static_cast<u8*>(output_buffers[0].pvBuffer),

View File

@@ -153,7 +153,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Load NSO modules
modules.clear();
const VAddr base_address{GetInteger(process.GetEntryPoint())};
const VAddr base_address{GetInteger(process.GetPageTable().GetCodeRegionStart())};
VAddr next_load_addr{base_address};
const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
system.GetContentProvider()};

View File

@@ -96,7 +96,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
}
codeset.memory = std::move(program_image);
const VAddr base_address = GetInteger(process.GetEntryPoint());
const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart());
process.LoadModule(std::move(codeset), base_address);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);

View File

@@ -203,7 +203,7 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
// Load codeset for current process
codeset.memory = std::move(program_image);
process.LoadModule(std::move(codeset), process.GetEntryPoint());
process.LoadModule(std::move(codeset), process.GetPageTable().GetCodeRegionStart());
return true;
}

View File

@@ -167,7 +167,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
modules.clear();
// Load module
const VAddr base_address = GetInteger(process.GetEntryPoint());
const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart());
if (!LoadModule(process, system, *file, base_address, true, true)) {
return {ResultStatus::ErrorLoadingNSO, {}};
}

View File

@@ -117,8 +117,8 @@ json GetProcessorStateDataAuto(Core::System& system) {
arm.SaveContext(context);
return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32",
GetInteger(process->GetEntryPoint()), context.sp, context.pc,
context.pstate, context.cpu_registers);
GetInteger(process->GetPageTable().GetCodeRegionStart()),
context.sp, context.pc, context.pstate, context.cpu_registers);
}
json GetBacktraceData(Core::System& system) {

View File

@@ -558,15 +558,12 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& derivatives,
const IR::Value& offset, const IR::Value& lod_clamp) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
ScopedRegister dpdx, dpdy, coords;
ScopedRegister dpdx, dpdy;
const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
if (multi_component) {
// Allocate this early to avoid aliasing other registers
dpdx = ScopedRegister{ctx.reg_alloc};
dpdy = ScopedRegister{ctx.reg_alloc};
if (info.num_derivates >= 3) {
coords = ScopedRegister{ctx.reg_alloc};
}
}
const auto sparse_inst{PrepareSparse(inst)};
const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
@@ -583,27 +580,15 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
"MOV.F {}.y,{}.w;",
dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec,
dpdy.reg, derivatives_vec);
Register final_coord;
if (info.num_derivates >= 3) {
ctx.Add("MOV.F {}.z,{}.x;"
"MOV.F {}.z,{}.y;",
dpdx.reg, coord_vec, dpdy.reg, coord_vec);
ctx.Add("MOV.F {}.x,0;"
"MOV.F {}.y,0;",
"MOV.F {}.z,0;", coords.reg, coords.reg, coords.reg);
final_coord = coords.reg;
} else {
final_coord = coord_vec;
}
if (info.has_lod_clamp) {
const ScalarF32 lod_clamp_value{ctx.reg_alloc.Consume(lod_clamp)};
ctx.Add("MOV.F {}.w,{};"
"TXD.F.LODCLAMP{} {},{},{},{},{},{}{};",
dpdy.reg, lod_clamp_value, sparse_mod, ret, final_coord, dpdx.reg, dpdy.reg,
dpdy.reg, lod_clamp_value, sparse_mod, ret, coord_vec, dpdx.reg, dpdy.reg,
texture, type, offset_vec);
} else {
ctx.Add("TXD.F{} {},{},{},{},{},{}{};", sparse_mod, ret, final_coord, dpdx.reg,
dpdy.reg, texture, type, offset_vec);
ctx.Add("TXD.F{} {},{},{},{},{},{}{};", sparse_mod, ret, coord_vec, dpdx.reg, dpdy.reg,
texture, type, offset_vec);
}
} else {
ctx.Add("TXD.F{} {},{},{}.x,{}.y,{},{}{};", sparse_mod, ret, coord_vec, derivatives_vec,

View File

@@ -548,7 +548,7 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
if (sparse_inst) {
throw NotImplementedException("EmitImageGradient Sparse");
}
if (!offset.IsEmpty() && info.num_derivates <= 2) {
if (!offset.IsEmpty()) {
throw NotImplementedException("EmitImageGradient offset");
}
const auto texture{Texture(ctx, info, index)};
@@ -556,12 +556,6 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)};
if (multi_component) {
if (info.num_derivates >= 3) {
const auto offset_vec{ctx.var_alloc.Consume(offset)};
ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yz, {}.y));", texel, texture,
coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec);
return;
}
ctx.Add("{}=textureGrad({},{},vec2({}.xz),vec2({}.yz));", texel, texture, coords,
derivatives_vec, derivatives_vec);
} else {

View File

@@ -42,7 +42,6 @@ union TextureInstInfo {
BitField<23, 2, u32> gather_component;
BitField<25, 2, u32> num_derivates;
BitField<27, 3, ImageFormat> image_format;
BitField<30, 1, u32> ndv_is_active;
};
static_assert(sizeof(TextureInstInfo) <= sizeof(u32));

View File

@@ -19,7 +19,7 @@ void TranslatorVisitor::FSWZADD(u64 insn) {
} const fswzadd{insn};
if (fswzadd.ndv != 0) {
LOG_WARNING(Shader, "(STUBBED) FSWZADD - NDV mode");
throw NotImplementedException("FSWZADD NDV");
}
const IR::F32 src_a{GetFloatReg8(insn)};

View File

@@ -16,10 +16,8 @@ void MOV(TranslatorVisitor& v, u64 insn, const IR::U32& src, bool is_mov32i = fa
BitField<12, 4, u64> mov32i_mask;
} const mov{insn};
u64 mask = is_mov32i ? mov.mov32i_mask : mov.mask;
if (mask != 0xf && mask != 0x1) {
LOG_WARNING(Shader, "(STUBBED) Masked Mov");
return;
if ((is_mov32i ? mov.mov32i_mask : mov.mask) != 0xf) {
throw NotImplementedException("Non-full move mask");
}
v.X(mov.dest_reg, src);
}

View File

@@ -209,7 +209,7 @@ void TranslatorVisitor::R2B(u64) {
}
void TranslatorVisitor::RAM(u64) {
LOG_WARNING(Shader, "(STUBBED) RAM Instruction");
ThrowNotImplemented(Opcode::RAM);
}
void TranslatorVisitor::RET(u64) {
@@ -221,7 +221,7 @@ void TranslatorVisitor::RTT(u64) {
}
void TranslatorVisitor::SAM(u64) {
LOG_WARNING(Shader, "(STUBBED) SAM Instruction");
ThrowNotImplemented(Opcode::SAM);
}
void TranslatorVisitor::SETCRSPTR(u64) {

View File

@@ -172,7 +172,6 @@ void Impl(TranslatorVisitor& v, u64 insn, bool aoffi, Blod blod, bool lc,
info.is_depth.Assign(tex.dc != 0 ? 1 : 0);
info.has_bias.Assign(blod == Blod::LB || blod == Blod::LBA ? 1 : 0);
info.has_lod_clamp.Assign(lc ? 1 : 0);
info.ndv_is_active.Assign(tex.ndv != 0 ? 1 : 0);
const IR::Value sample{[&]() -> IR::Value {
if (tex.dc == 0) {

View File

@@ -10,7 +10,6 @@
#include "shader_recompiler/environment.h"
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/frontend/ir/modifiers.h"
#include "shader_recompiler/frontend/ir/value.h"
#include "shader_recompiler/ir_opt/passes.h"
@@ -411,49 +410,7 @@ void FoldSelect(IR::Inst& inst) {
}
}
void FoldFPAdd32(IR::Inst& inst) {
if (FoldWhenAllImmediates(inst, [](f32 a, f32 b) { return a + b; })) {
return;
}
const IR::Value lhs_value{inst.Arg(0)};
const IR::Value rhs_value{inst.Arg(1)};
const auto check_neutral = [](const IR::Value& one_operand) {
return one_operand.IsImmediate() && std::abs(one_operand.F32()) == 0.0f;
};
if (check_neutral(lhs_value)) {
inst.ReplaceUsesWith(rhs_value);
}
if (check_neutral(rhs_value)) {
inst.ReplaceUsesWith(lhs_value);
}
}
bool FoldDerivateYFromCorrection(IR::Inst& inst) {
const IR::Value lhs_value{inst.Arg(0)};
const IR::Value rhs_value{inst.Arg(1)};
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
IR::Inst* const rhs_op{rhs_value.InstRecursive()};
if (lhs_op->GetOpcode() == IR::Opcode::YDirection) {
if (rhs_op->GetOpcode() != IR::Opcode::DPdyFine) {
return false;
}
inst.ReplaceUsesWith(rhs_value);
return true;
}
if (rhs_op->GetOpcode() != IR::Opcode::YDirection) {
return false;
}
if (lhs_op->GetOpcode() != IR::Opcode::DPdyFine) {
return false;
}
inst.ReplaceUsesWith(lhs_value);
return true;
}
void FoldFPMul32(IR::Inst& inst) {
if (FoldWhenAllImmediates(inst, [](f32 a, f32 b) { return a * b; })) {
return;
}
const auto control{inst.Flags<IR::FpControl>()};
if (control.no_contraction) {
return;
@@ -464,9 +421,6 @@ void FoldFPMul32(IR::Inst& inst) {
if (lhs_value.IsImmediate() || rhs_value.IsImmediate()) {
return;
}
if (FoldDerivateYFromCorrection(inst)) {
return;
}
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
IR::Inst* const rhs_op{rhs_value.InstRecursive()};
if (lhs_op->GetOpcode() != IR::Opcode::FPMul32 ||
@@ -668,12 +622,7 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
}
const IR::Value value_3{GetThroughCast(inst2->Arg(0).Resolve(), IR::Opcode::BitCastU32F32)};
if (value_2 != value_3) {
if (!value_2.IsImmediate() || !value_3.IsImmediate()) {
return;
}
if (Common::BitCast<u32>(value_2.F32()) != value_3.U32()) {
return;
}
return;
}
const IR::Value index{inst2->Arg(1)};
const IR::Value clamp{inst2->Arg(2)};
@@ -699,169 +648,6 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
}
}
bool FindGradient3DDerivates(std::array<IR::Value, 3>& results, IR::Value coord) {
if (coord.IsImmediate()) {
return false;
}
const auto check_through_shuffle = [](IR::Value input, IR::Value& result) {
const IR::Value value_1{GetThroughCast(input.Resolve(), IR::Opcode::BitCastF32U32)};
IR::Inst* const inst2{value_1.InstRecursive()};
if (inst2->GetOpcode() != IR::Opcode::ShuffleIndex) {
return false;
}
const IR::Value index{inst2->Arg(1).Resolve()};
const IR::Value clamp{inst2->Arg(2).Resolve()};
const IR::Value segmentation_mask{inst2->Arg(3).Resolve()};
if (!index.IsImmediate() || !clamp.IsImmediate() || !segmentation_mask.IsImmediate()) {
return false;
}
if (index.U32() != 3 && clamp.U32() != 3) {
return false;
}
result = GetThroughCast(inst2->Arg(0).Resolve(), IR::Opcode::BitCastU32F32);
return true;
};
IR::Inst* const inst = coord.InstRecursive();
if (inst->GetOpcode() != IR::Opcode::FSwizzleAdd) {
return false;
}
std::array<IR::Value, 3> temporary_values;
IR::Value value_1 = inst->Arg(0).Resolve();
IR::Value value_2 = inst->Arg(1).Resolve();
IR::Value value_3 = inst->Arg(2).Resolve();
std::array<u32, 4> swizzles_mask_a{};
std::array<u32, 4> swizzles_mask_b{};
const auto resolve_mask = [](std::array<u32, 4>& mask_results, IR::Value mask) {
u32 value = mask.U32();
for (size_t i = 0; i < 4; i++) {
mask_results[i] = (value >> (i * 2)) & 0x3;
}
};
resolve_mask(swizzles_mask_a, value_3);
size_t coordinate_index = 0;
const auto resolve_pending = [&](IR::Value resolve_v) {
IR::Inst* const inst_r = resolve_v.InstRecursive();
if (inst_r->GetOpcode() != IR::Opcode::FSwizzleAdd) {
return false;
}
if (!check_through_shuffle(inst_r->Arg(0).Resolve(), temporary_values[1])) {
return false;
}
if (!check_through_shuffle(inst_r->Arg(1).Resolve(), temporary_values[2])) {
return false;
}
resolve_mask(swizzles_mask_b, inst_r->Arg(2).Resolve());
return true;
};
if (value_1.IsImmediate() || value_2.IsImmediate()) {
return false;
}
bool should_continue = false;
if (resolve_pending(value_1)) {
should_continue = check_through_shuffle(value_2, temporary_values[0]);
coordinate_index = 0;
}
if (resolve_pending(value_2)) {
should_continue = check_through_shuffle(value_1, temporary_values[0]);
coordinate_index = 2;
}
if (!should_continue) {
return false;
}
// figure which is which
size_t zero_mask_a = 0;
size_t zero_mask_b = 0;
for (size_t i = 0; i < 4; i++) {
if (swizzles_mask_a[i] == 2 || swizzles_mask_b[i] == 2) {
// last operand can be inversed, we cannot determine a result.
return false;
}
zero_mask_a |= static_cast<size_t>(swizzles_mask_a[i] == 3 ? 1 : 0) << i;
zero_mask_b |= static_cast<size_t>(swizzles_mask_b[i] == 3 ? 1 : 0) << i;
}
static constexpr size_t ddx_pattern = 0b1010;
static constexpr size_t ddx_pattern_inv = ~ddx_pattern & 0b00001111;
if (std::popcount(zero_mask_a) != 2) {
return false;
}
if (std::popcount(zero_mask_b) != 2) {
return false;
}
if (zero_mask_a == zero_mask_b) {
return false;
}
results[0] = temporary_values[coordinate_index];
if (coordinate_index == 0) {
if (zero_mask_b == ddx_pattern || zero_mask_b == ddx_pattern_inv) {
results[1] = temporary_values[1];
results[2] = temporary_values[2];
return true;
}
results[2] = temporary_values[1];
results[1] = temporary_values[2];
} else {
const auto assign_result = [&results](IR::Value temporary_value, size_t mask) {
if (mask == ddx_pattern || mask == ddx_pattern_inv) {
results[1] = temporary_value;
return;
}
results[2] = temporary_value;
};
assign_result(temporary_values[1], zero_mask_b);
assign_result(temporary_values[0], zero_mask_a);
}
return true;
}
void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>();
auto orig_opcode = inst.GetOpcode();
if (info.ndv_is_active == 0) {
return;
}
if (info.type != TextureType::Color3D) {
return;
}
const IR::Value handle{inst.Arg(0)};
const IR::Value coords{inst.Arg(1)};
const IR::Value bias_lc{inst.Arg(2)};
const IR::Value offset{inst.Arg(3)};
if (!offset.IsImmediate()) {
return;
}
IR::Inst* const inst2 = coords.InstRecursive();
std::array<std::array<IR::Value, 3>, 3> results_matrix;
for (size_t i = 0; i < 3; i++) {
if (!FindGradient3DDerivates(results_matrix[i], inst2->Arg(i).Resolve())) {
return;
}
}
IR::F32 lod_clamp{};
if (info.has_lod_clamp != 0) {
if (!bias_lc.IsImmediate()) {
lod_clamp = IR::F32{bias_lc.InstRecursive()->Arg(1).Resolve()};
} else {
lod_clamp = IR::F32{bias_lc};
}
}
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
IR::Value new_coords =
ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]);
IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],
results_matrix[1][1], results_matrix[1][2]);
IR::Value derivatives_2 = ir.CompositeConstruct(results_matrix[2][1], results_matrix[2][2]);
info.num_derivates.Assign(3);
IR::Value new_gradient_instruction =
ir.ImageGradient(handle, new_coords, derivatives_1, derivatives_2, lod_clamp, info);
IR::Inst* const new_inst = new_gradient_instruction.InstRecursive();
if (orig_opcode == IR::Opcode::ImageSampleImplicitLod) {
new_inst->ReplaceOpcode(IR::Opcode::ImageGradient);
}
inst.ReplaceUsesWith(new_gradient_instruction);
}
void FoldConstBuffer(Environment& env, IR::Block& block, IR::Inst& inst) {
const IR::Value bank{inst.Arg(0)};
const IR::Value offset{inst.Arg(1)};
@@ -957,12 +743,6 @@ void ConstantPropagation(Environment& env, IR::Block& block, IR::Inst& inst) {
case IR::Opcode::SelectF32:
case IR::Opcode::SelectF64:
return FoldSelect(inst);
case IR::Opcode::FPNeg32:
FoldWhenAllImmediates(inst, [](f32 a) { return -a; });
return;
case IR::Opcode::FPAdd32:
FoldFPAdd32(inst);
return;
case IR::Opcode::FPMul32:
return FoldFPMul32(inst);
case IR::Opcode::LogicalAnd:
@@ -1078,11 +858,6 @@ void ConstantPropagation(Environment& env, IR::Block& block, IR::Inst& inst) {
FoldDriverConstBuffer(env, block, inst, 1);
}
break;
case IR::Opcode::BindlessImageSampleImplicitLod:
case IR::Opcode::BoundImageSampleImplicitLod:
case IR::Opcode::ImageSampleImplicitLod:
FoldImageSampleImplicitLod(block, inst);
break;
default:
break;
}

View File

@@ -41,6 +41,9 @@ namespace {
bool enable_validation) {
std::vector<const char*> extensions;
extensions.reserve(6);
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
switch (window_type) {
case Core::Frontend::WindowSystemType::Headless:
break;
@@ -71,11 +74,6 @@ namespace {
if (window_type != Core::Frontend::WindowSystemType::Headless) {
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
}
#ifdef __APPLE__
if (AreExtensionsSupported(dld, std::array{VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME})) {
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
}
#endif
if (enable_validation) {
const bool debug_utils =
AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});

View File

@@ -19,17 +19,13 @@ std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
#else
auto library = std::make_shared<Common::DynamicLibrary>();
#ifdef __APPLE__
const auto libvulkan_filename =
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.1.dylib";
const auto libmoltenvk_filename =
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libMoltenVK.dylib";
const char* library_paths[] = {std::getenv("LIBVULKAN_PATH"), libvulkan_filename.c_str(),
libmoltenvk_filename.c_str()};
// Check if a path to a specific Vulkan library has been specified.
for (const auto& library_path : library_paths) {
if (library_path && library->Open(library_path)) {
break;
}
char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
if (!libvulkan_env || !library->Open(libvulkan_env)) {
// Use the libvulkan.dylib from the application bundle.
const auto filename =
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.dylib";
void(library->Open(Common::FS::PathToUTF8String(filename).c_str()));
}
#else
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);

View File

@@ -313,18 +313,6 @@ if (APPLE)
target_sources(yuzu PRIVATE ${MACOSX_ICON})
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
if (NOT USE_SYSTEM_MOLTENVK)
set(MOLTENVK_PLATFORM "macOS")
set(MOLTENVK_VERSION "v1.2.5")
download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
endif()
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
elseif(WIN32)
# compile as a win32 gui application instead of a console application
if (QT_VERSION VERSION_GREATER_EQUAL 6)

View File

@@ -11,8 +11,6 @@
#include <glad/glad.h>
#include <QtCore/qglobal.h>
#include "common/settings_enums.h"
#include "uisettings.h"
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
#include <QCamera>
#include <QCameraImageCapture>
@@ -918,6 +916,7 @@ void GRenderWindow::ReleaseRenderTarget() {
void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) {
auto& renderer = system.Renderer();
const f32 res_scale = Settings::values.resolution_info.up_factor;
if (renderer.IsScreenshotPending()) {
LOG_WARNING(Render,
@@ -925,18 +924,7 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) {
return;
}
const Layout::FramebufferLayout layout{[]() {
u32 height = UISettings::values.screenshot_height.GetValue();
if (height == 0) {
height = Settings::values.use_docked_mode.GetValue() ? Layout::ScreenDocked::Height
: Layout::ScreenUndocked::Height;
height *= Settings::values.resolution_info.up_factor;
}
const u32 width =
UISettings::CalculateWidth(height, Settings::values.aspect_ratio.GetValue());
return Layout::DefaultFrameLayout(width, height);
}()};
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
renderer.RequestScreenshot(
screenshot_image.bits(),

View File

@@ -592,7 +592,8 @@ void Config::ReadRendererValues() {
void Config::ReadScreenshotValues() {
qt_config->beginGroup(QStringLiteral("Screenshots"));
ReadCategory(Settings::Category::Screenshots);
UISettings::values.enable_screenshot_save_as =
ReadSetting(QStringLiteral("enable_screenshot_save_as"), true).toBool();
FS::SetYuzuPath(
FS::YuzuPath::ScreenshotsDir,
qt_config

View File

@@ -4,7 +4,6 @@
#include <memory>
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "core/core.h"
#include "ui_configure.h"
#include "vk_device_info.h"
@@ -42,19 +41,16 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
general_tab{std::make_unique<ConfigureGeneral>(system_, nullptr, *builder, this)},
graphics_advanced_tab{
std::make_unique<ConfigureGraphicsAdvanced>(system_, nullptr, *builder, this)},
ui_tab{std::make_unique<ConfigureUi>(system_, this)},
graphics_tab{std::make_unique<ConfigureGraphics>(
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
[this](Settings::AspectRatio ratio, Settings::ResolutionSetup setup) {
ui_tab->UpdateScreenshotInfo(ratio, setup);
},
nullptr, *builder, this)},
hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
input_tab{std::make_unique<ConfigureInput>(system_, this)},
network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *builder, this)},
web_tab{std::make_unique<ConfigureWeb>(this)} {
ui_tab{std::make_unique<ConfigureUi>(system_, this)}, web_tab{std::make_unique<ConfigureWeb>(
this)} {
Settings::SetConfiguringGlobal(true);
ui->setupUi(this);

View File

@@ -81,12 +81,12 @@ private:
std::unique_ptr<ConfigureFilesystem> filesystem_tab;
std::unique_ptr<ConfigureGeneral> general_tab;
std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
std::unique_ptr<ConfigureUi> ui_tab;
std::unique_ptr<ConfigureGraphics> graphics_tab;
std::unique_ptr<ConfigureHotkeys> hotkeys_tab;
std::unique_ptr<ConfigureInput> input_tab;
std::unique_ptr<ConfigureNetwork> network_tab;
std::unique_ptr<ConfigureProfileManager> profile_tab;
std::unique_ptr<ConfigureSystem> system_tab;
std::unique_ptr<ConfigureUi> ui_tab;
std::unique_ptr<ConfigureWeb> web_tab;
};

View File

@@ -24,7 +24,6 @@
#include <QtCore/qobjectdefs.h>
#include <qabstractbutton.h>
#include <qboxlayout.h>
#include <qcombobox.h>
#include <qcoreevent.h>
#include <qglobal.h>
#include <qgridlayout.h>
@@ -78,16 +77,13 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode)
}
}
ConfigureGraphics::ConfigureGraphics(
const Core::System& system_, std::vector<VkDeviceInfo::Record>& records_,
const std::function<void()>& expose_compute_option_,
const std::function<void(Settings::AspectRatio, Settings::ResolutionSetup)>&
update_aspect_ratio_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
std::vector<VkDeviceInfo::Record>& records_,
const std::function<void()>& expose_compute_option_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
const ConfigurationShared::Builder& builder, QWidget* parent)
: ConfigurationShared::Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
records{records_}, expose_compute_option{expose_compute_option_},
update_aspect_ratio{update_aspect_ratio_}, system{system_},
records{records_}, expose_compute_option{expose_compute_option_}, system{system_},
combobox_translations{builder.ComboboxTranslations()},
shader_mapping{
combobox_translations.at(Settings::EnumMetadata<Settings::ShaderBackend>::Index())} {
@@ -144,26 +140,6 @@ ConfigureGraphics::ConfigureGraphics(
UpdateBackgroundColorButton(new_bg_color);
});
const auto& update_screenshot_info = [this, &builder]() {
const auto& combobox_enumerations = builder.ComboboxTranslations().at(
Settings::EnumMetadata<Settings::AspectRatio>::Index());
const auto index = aspect_ratio_combobox->currentIndex();
const auto ratio = static_cast<Settings::AspectRatio>(combobox_enumerations[index].first);
const auto& combobox_enumerations_resolution = builder.ComboboxTranslations().at(
Settings::EnumMetadata<Settings::ResolutionSetup>::Index());
const auto res_index = resolution_combobox->currentIndex();
const auto setup = static_cast<Settings::ResolutionSetup>(
combobox_enumerations_resolution[res_index].first);
update_aspect_ratio(ratio, setup);
};
connect(aspect_ratio_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
update_screenshot_info);
connect(resolution_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged),
update_screenshot_info);
api_combobox->setEnabled(!UISettings::values.has_broken_vulkan && api_combobox->isEnabled());
ui->api_widget->setEnabled(
(!UISettings::values.has_broken_vulkan || Settings::IsConfiguringGlobal()) &&
@@ -304,14 +280,6 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) {
// Keep track of vsync_mode's combobox so we can populate it
vsync_mode_combobox = widget->combobox;
hold_graphics.emplace(setting->Id(), widget);
} else if (setting->Id() == Settings::values.aspect_ratio.Id()) {
// Keep track of the aspect ratio combobox to update other UI tabs that need it
aspect_ratio_combobox = widget->combobox;
hold_graphics.emplace(setting->Id(), widget);
} else if (setting->Id() == Settings::values.resolution_setup.Id()) {
// Keep track of the resolution combobox to update other UI tabs that need it
resolution_combobox = widget->combobox;
hold_graphics.emplace(setting->Id(), widget);
} else {
hold_graphics.emplace(setting->Id(), widget);
}

View File

@@ -14,7 +14,6 @@
#include <qobjectdefs.h>
#include <vulkan/vulkan_core.h>
#include "common/common_types.h"
#include "common/settings_enums.h"
#include "configuration/shared_translation.h"
#include "vk_device_info.h"
#include "yuzu/configuration/configuration_shared.h"
@@ -44,13 +43,12 @@ class Builder;
class ConfigureGraphics : public ConfigurationShared::Tab {
public:
explicit ConfigureGraphics(
const Core::System& system_, std::vector<VkDeviceInfo::Record>& records,
const std::function<void()>& expose_compute_option,
const std::function<void(Settings::AspectRatio, Settings::ResolutionSetup)>&
update_aspect_ratio,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
explicit ConfigureGraphics(const Core::System& system_,
std::vector<VkDeviceInfo::Record>& records,
const std::function<void()>& expose_compute_option_,
std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
const ConfigurationShared::Builder& builder,
QWidget* parent = nullptr);
~ConfigureGraphics() override;
void ApplyConfiguration() override;
@@ -93,7 +91,6 @@ private:
u32 vulkan_device{};
Settings::ShaderBackend shader_backend{};
const std::function<void()>& expose_compute_option;
const std::function<void(Settings::AspectRatio, Settings::ResolutionSetup)> update_aspect_ratio;
const Core::System& system;
const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
@@ -107,6 +104,4 @@ private:
QWidget* vulkan_device_widget;
QWidget* api_widget;
QWidget* shader_backend_widget;
QComboBox* aspect_ratio_combobox;
QComboBox* resolution_combobox;
};

View File

@@ -17,7 +17,6 @@
#include <QTimer>
#include "common/fs/fs_util.h"
#include "common/settings_enums.h"
#include "configuration/shared_widget.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
@@ -58,7 +57,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
std::make_unique<ConfigureGraphicsAdvanced>(system_, tab_group, *builder, this);
graphics_tab = std::make_unique<ConfigureGraphics>(
system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
[](Settings::AspectRatio, Settings::ResolutionSetup) {}, tab_group, *builder, this);
tab_group, *builder, this);
input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
system_tab = std::make_unique<ConfigureSystem>(system_, tab_group, *builder, this);

View File

@@ -1,31 +1,18 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "yuzu/configuration/configure_ui.h"
#include <array>
#include <set>
#include <stdexcept>
#include <string>
#include <utility>
#include <QCheckBox>
#include <QComboBox>
#include <QCoreApplication>
#include <QDirIterator>
#include <QFileDialog>
#include <QString>
#include <QToolButton>
#include <QVariant>
#include <QDirIterator>
#include "common/common_types.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
#include "ui_configure_ui.h"
#include "yuzu/configuration/configure_ui.h"
#include "yuzu/uisettings.h"
namespace {
@@ -67,44 +54,8 @@ QString GetTranslatedRowTextName(size_t index) {
}
} // Anonymous namespace
static float GetUpFactor(Settings::ResolutionSetup res_setup) {
Settings::ResolutionScalingInfo info{};
Settings::TranslateResolutionInfo(res_setup, info);
return info.up_factor;
}
static void PopulateResolutionComboBox(QComboBox* screenshot_height, QWidget* parent) {
screenshot_height->clear();
const auto& enumeration =
Settings::EnumMetadata<Settings::ResolutionSetup>::Canonicalizations();
std::set<u32> resolutions{};
for (const auto& [name, value] : enumeration) {
const float up_factor = GetUpFactor(value);
u32 height_undocked = Layout::ScreenUndocked::Height * up_factor;
u32 height_docked = Layout::ScreenDocked::Height * up_factor;
resolutions.emplace(height_undocked);
resolutions.emplace(height_docked);
}
screenshot_height->addItem(parent->tr("Auto", "Screenshot height option"));
for (const auto res : resolutions) {
screenshot_height->addItem(QString::fromStdString(std::to_string(res)));
}
}
static u32 ScreenshotDimensionToInt(const QString& height) {
try {
return std::stoi(height.toStdString());
} catch (std::invalid_argument&) {
return 0;
}
}
ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
: QWidget(parent), ui{std::make_unique<Ui::ConfigureUi>()},
ratio{Settings::values.aspect_ratio.GetValue()},
resolution_setting{Settings::values.resolution_setup.GetValue()}, system{system_} {
: QWidget(parent), ui{std::make_unique<Ui::ConfigureUi>()}, system{system_} {
ui->setupUi(this);
InitializeLanguageComboBox();
@@ -117,8 +68,6 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
InitializeIconSizeComboBox();
InitializeRowComboBoxes();
PopulateResolutionComboBox(ui->screenshot_height, this);
SetConfiguration();
// Force game list reload if any of the relevant settings are changed.
@@ -155,10 +104,6 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent)
ui->screenshot_path_edit->setText(dir);
}
});
connect(ui->screenshot_height, &QComboBox::currentTextChanged, [this]() { UpdateWidthText(); });
UpdateWidthText();
}
ConfigureUi::~ConfigureUi() = default;
@@ -178,10 +123,6 @@ void ConfigureUi::ApplyConfiguration() {
UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
Common::FS::SetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir,
ui->screenshot_path_edit->text().toStdString());
const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
UISettings::values.screenshot_height.SetValue(height);
system.ApplySettings();
}
@@ -206,13 +147,6 @@ void ConfigureUi::SetConfiguration() {
UISettings::values.enable_screenshot_save_as.GetValue());
ui->screenshot_path_edit->setText(QString::fromStdString(
Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir)));
const auto height = UISettings::values.screenshot_height.GetValue();
if (height == 0) {
ui->screenshot_height->setCurrentIndex(0);
} else {
ui->screenshot_height->setCurrentText(QStringLiteral("%1").arg(height));
}
}
void ConfigureUi::changeEvent(QEvent* event) {
@@ -383,29 +317,3 @@ void ConfigureUi::OnLanguageChanged(int index) {
emit LanguageChanged(ui->language_combobox->itemData(index).toString());
}
void ConfigureUi::UpdateWidthText() {
const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText());
const u32 width = UISettings::CalculateWidth(height, ratio);
if (height == 0) {
const auto up_factor = GetUpFactor(resolution_setting);
const u32 height_docked = Layout::ScreenDocked::Height * up_factor;
const u32 width_docked = UISettings::CalculateWidth(height_docked, ratio);
const u32 height_undocked = Layout::ScreenUndocked::Height * up_factor;
const u32 width_undocked = UISettings::CalculateWidth(height_undocked, ratio);
ui->screenshot_width->setText(tr("Auto (%1 x %2, %3 x %4)", "Screenshot width value")
.arg(width_undocked)
.arg(height_undocked)
.arg(width_docked)
.arg(height_docked));
} else {
ui->screenshot_width->setText(QStringLiteral("%1 x").arg(width));
}
}
void ConfigureUi::UpdateScreenshotInfo(Settings::AspectRatio ratio_,
Settings::ResolutionSetup resolution_setting_) {
ratio = ratio_;
resolution_setting = resolution_setting_;
UpdateWidthText();
}

View File

@@ -5,7 +5,6 @@
#include <memory>
#include <QWidget>
#include "common/settings_enums.h"
namespace Core {
class System;
@@ -24,9 +23,6 @@ public:
void ApplyConfiguration();
void UpdateScreenshotInfo(Settings::AspectRatio ratio,
Settings::ResolutionSetup resolution_info);
private slots:
void OnLanguageChanged(int index);
@@ -48,11 +44,7 @@ private:
void UpdateFirstRowComboBox(bool init = false);
void UpdateSecondRowComboBox(bool init = false);
void UpdateWidthText();
std::unique_ptr<Ui::ConfigureUi> ui;
Settings::AspectRatio ratio;
Settings::ResolutionSetup resolution_setting;
Core::System& system;
};

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>363</width>
<height>603</height>
<height>562</height>
</rect>
</property>
<property name="windowTitle">
@@ -201,41 +201,6 @@
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="screenshot_width">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="screenshot_height">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Resolution:</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>

View File

@@ -235,7 +235,6 @@ QWidget* Widget::CreateSlider(bool reversed, float multiplier, const QString& gi
slider->setValue(std::stoi(setting.ToString()));
slider->setInvertedAppearance(reversed);
slider->setInvertedControls(reversed);
serializer = [this]() { return std::to_string(slider->value()); };
restore_func = [this]() { slider->setValue(std::stoi(RelevantDefault(setting))); };

View File

@@ -191,9 +191,8 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
}
QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
const std::size_t size, const std::vector<u8>& icon,
Loader::AppLoader& loader, u64 program_id,
const CompatibilityList& compatibility_list,
const std::vector<u8>& icon, Loader::AppLoader& loader,
u64 program_id, const CompatibilityList& compatibility_list,
const FileSys::PatchManager& patch) {
const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
@@ -211,7 +210,7 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
file_type_string, program_id),
new GameListItemCompat(compatibility),
new GameListItem(file_type_string),
new GameListItemSize(size),
new GameListItemSize(Common::FS::GetSize(path)),
};
const auto patch_versions = GetGameListCachedObject(
@@ -279,8 +278,8 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
GetMetadataFromControlNCA(patch, *control, icon, name);
}
emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader,
program_id, compatibility_list, patch),
emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id,
compatibility_list, patch),
parent_dir);
}
}
@@ -355,9 +354,8 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
const FileSys::PatchManager patch{id, system.GetFileSystemController(),
system.GetContentProvider()};
emit EntryReady(MakeGameListEntry(physical_name, name,
Common::FS::GetSize(physical_name), icon,
*loader, id, compatibility_list, patch),
emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, id,
compatibility_list, patch),
parent_dir);
}
} else {
@@ -370,10 +368,9 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
const FileSys::PatchManager patch{program_id, system.GetFileSystemController(),
system.GetContentProvider()};
emit EntryReady(
MakeGameListEntry(physical_name, name, Common::FS::GetSize(physical_name),
icon, *loader, program_id, compatibility_list, patch),
parent_dir);
emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader,
program_id, compatibility_list, patch),
parent_dir);
}
}
} else if (is_dir) {

View File

@@ -1811,43 +1811,6 @@ bool GMainWindow::SelectAndSetCurrentUser(
return true;
}
void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
// Ensure all NCAs are registered before launching the game
const auto file = vfs->OpenFile(filepath, FileSys::Mode::Read);
if (!file) {
return;
}
auto loader = Loader::GetLoader(*system, file);
if (!loader) {
return;
}
const auto file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
return;
}
u64 program_id = 0;
const auto res2 = loader->ReadProgramId(program_id);
if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
provider->AddEntry(FileSys::TitleType::Application,
FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id,
file);
} else if (res2 == Loader::ResultStatus::Success &&
(file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
const auto nsp = file_type == Loader::FileType::NSP
? std::make_shared<FileSys::NSP>(file)
: FileSys::XCI{file}.GetSecurePartitionNSP();
for (const auto& title : nsp->GetNCAs()) {
for (const auto& entry : title.second) {
provider->AddEntry(entry.first.first, entry.first.second, title.first,
entry.second->GetBaseFile());
}
}
}
}
void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index,
StartGameType type) {
LOG_INFO(Frontend, "yuzu starting...");
@@ -1862,7 +1825,6 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
last_filename_booted = filename;
ConfigureFilesystemProvider(filename.toStdString());
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index);

View File

@@ -399,7 +399,6 @@ private:
void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
bool CheckDarkMode();
bool CheckSystemArchiveDecryption();
void ConfigureFilesystemProvider(const std::string& filepath);
QString GetTasStateDescription() const;
bool CreateShortcut(const std::string& shortcut_path, const std::string& title,

View File

@@ -36,20 +36,4 @@ bool IsDarkTheme() {
Values values = {};
u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
switch (ratio) {
case Settings::AspectRatio::R4_3:
return height * 4 / 3;
case Settings::AspectRatio::R21_9:
return height * 21 / 9;
case Settings::AspectRatio::R16_10:
return height * 16 / 10;
case Settings::AspectRatio::R16_9:
case Settings::AspectRatio::Stretch:
// TODO: Move this function wherever appropriate to implement Stretched aspect
break;
}
return height * 16 / 9;
}
} // namespace UISettings

View File

@@ -13,7 +13,6 @@
#include <QVector>
#include "common/common_types.h"
#include "common/settings.h"
#include "common/settings_enums.h"
using Settings::Category;
using Settings::Setting;
@@ -128,10 +127,8 @@ struct Values {
// logging
Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
// Screenshots
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
Category::Screenshots};
Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots};
QString roms_path;
QString symbols_path;
@@ -190,8 +187,6 @@ struct Values {
extern Values values;
u32 CalculateWidth(u32 height, Settings::AspectRatio ratio);
} // namespace UISettings
Q_DECLARE_METATYPE(UISettings::GameDir*);