Compare commits

...

25 Commits

Author SHA1 Message Date
808e285985 Android #50 2023-08-25 00:57:16 +00:00
7d89f2c146 Merge pull request #11327 from liamwhite/skyline-2
sockets: avoid locking around socket session calls
2023-08-24 10:33:53 -04:00
51ffc2c66c Merge pull request #11367 from FearlessTobi/fix-filesize
game_list_worker: Display correct size for NAX games
2023-08-24 10:33:42 -04:00
e41655960e game_list_worker: Display correct size for NAX games
This was a regression from https://github.com/yuzu-emu/yuzu/pull/1837.

Fixes https://github.com/yuzu-emu/yuzu/issues/1938.
2023-08-24 01:16:19 +02:00
ccd163ab2c Merge pull request #11352 from t895/recurse-subfolders
android: Search game directory recursively
2023-08-23 10:20:02 -04:00
182fb83556 android: Set default build variant to mainlineRelWithDebInfo (#11358) 2023-08-23 16:12:39 +02:00
35b77b9599 android: Search game directory recursively 2023-08-22 15:16:20 -04:00
bc4ad5e62d Merge pull request #11302 from vonchenplus/vulkan_macos
Add macos moltenvk bundle, Add copy moltevk dylib script
2023-08-22 13:10:26 -04:00
ef61d129d3 Merge pull request #11303 from lat9nq/screenshots-configurable
yuzu-qt: Add configuration for screenshot resolution
2023-08-22 11:30:25 -04:00
b8bab551a4 Merge pull request #11316 from FernandoS27/stop-premature-christmas-decorating
Shader Recompiler: implement textureGrad 3D
2023-08-22 11:30:08 -04:00
a9f223cd9f Merge pull request #11346 from t895/ktlint-fix
android: lint: Delete generated ktlint folder between builds
2023-08-22 11:30:01 -04:00
87022a4833 Add macos moltenvk bundle, Add copy moltevk dylib script 2023-08-22 10:22:28 +08:00
1bc832c9b1 android: lint: Delete generated ktlint folder between builds
There's a bug in ktlint where it will run into an error if you build the project, delete a source file, and then build again. It will be unable to find the file you deleted and can't recover until these files are deleted. This just deletes those files before every run.
2023-08-21 17:31:13 -04:00
0cd9d51e06 sockets: avoid locking around socket session calls 2023-08-19 23:09:35 -04:00
c03f0b3c89 Shader Recomnpiler: implement textuzreGrad 3D emulation constant propagation 2023-08-18 22:17:02 -04:00
6af8cca2c1 uisettings: Add TODO for stretched aspect being ignored 2023-08-16 22:57:19 -04:00
e28b936950 configure_ui: Silence MSVC warning 2023-08-16 16:28:44 -04:00
6fe51b48e9 yuzu-qt: Screenshots depend more on the graphics settings 2023-08-16 16:12:42 -04:00
96c98d09cb yuzu-qt: Implement unspecified screenshot ratio 2023-08-16 00:18:47 -04:00
76a03e99b6 bootmanager: Remove old path
Causes issues with different selected aspect ratios in graphics.
2023-08-16 00:18:16 -04:00
95409c6859 configure_ui: Update the screenshots data 2023-08-15 23:08:02 -04:00
227950ac99 config: Read the entire screenshots category 2023-08-15 23:07:49 -04:00
bc5ec10498 bootmanager: Consider the default resolution 2023-08-15 22:57:38 -04:00
d9275b7757 yuzu-qt: Enable specifying screenshot resolution 2023-08-15 22:42:28 -04:00
3e28e85468 settings: Add AspectRatio enum, split res scale function 2023-08-15 22:41:50 -04:00
34 changed files with 616 additions and 71 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,6 +63,8 @@ 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,3 +36,21 @@ 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

@ -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

@ -95,6 +95,7 @@ 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
@ -122,6 +123,7 @@ android {
flavorDimensions.add("version")
productFlavors {
create("mainline") {
isDefault = true
dimension = "version"
buildConfigField("Boolean", "PREMIUM", "false")
}
@ -160,6 +162,11 @@ 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

@ -11,6 +11,7 @@ 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"
@ -29,15 +30,7 @@ object GameHelper {
// Ensure keys are loaded so that ROM metadata can be decrypted.
NativeLibrary.reloadKeys()
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))
}
}
}
addGamesRecursive(games, FileUtil.listFiles(context, gamesUri), 3)
// Cache list of games found on disk
val serializedGames = mutableSetOf<String>()
@ -52,6 +45,30 @@ 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

@ -207,9 +207,7 @@ const char* TranslateCategory(Category category) {
return "Miscellaneous";
}
void UpdateRescalingInfo() {
const auto setup = values.resolution_setup.GetValue();
auto& info = values.resolution_info;
void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info) {
info.downscale = false;
switch (setup) {
case ResolutionSetup::Res1_2X:
@ -269,6 +267,12 @@ void UpdateRescalingInfo() {
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,6 +525,7 @@ 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

@ -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]] std::scoped_lock<std::mutex> LockService() {
return std::scoped_lock{lock_service};
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() {
return std::unique_lock{lock_service};
}
/// System context that the service operates under.

View File

@ -1029,6 +1029,11 @@ 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,6 +186,9 @@ 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

@ -558,12 +558,15 @@ 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;
ScopedRegister dpdx, dpdy, coords;
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" : ""};
@ -580,15 +583,27 @@ 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, coord_vec, dpdx.reg, dpdy.reg,
dpdy.reg, lod_clamp_value, sparse_mod, ret, final_coord, dpdx.reg, dpdy.reg,
texture, type, offset_vec);
} else {
ctx.Add("TXD.F{} {},{},{},{},{},{}{};", sparse_mod, ret, coord_vec, dpdx.reg, dpdy.reg,
texture, type, offset_vec);
ctx.Add("TXD.F{} {},{},{},{},{},{}{};", sparse_mod, ret, final_coord, 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()) {
if (!offset.IsEmpty() && info.num_derivates <= 2) {
throw NotImplementedException("EmitImageGradient offset");
}
const auto texture{Texture(ctx, info, index)};
@ -556,6 +556,12 @@ 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,6 +42,7 @@ 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) {
throw NotImplementedException("FSWZADD NDV");
LOG_WARNING(Shader, "(STUBBED) FSWZADD - NDV mode");
}
const IR::F32 src_a{GetFloatReg8(insn)};

View File

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

View File

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

View File

@ -172,6 +172,7 @@ 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,6 +10,7 @@
#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"
@ -410,7 +411,49 @@ 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;
@ -421,6 +464,9 @@ 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 ||
@ -622,7 +668,12 @@ 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) {
return;
if (!value_2.IsImmediate() || !value_3.IsImmediate()) {
return;
}
if (Common::BitCast<u32>(value_2.F32()) != value_3.U32()) {
return;
}
}
const IR::Value index{inst2->Arg(1)};
const IR::Value clamp{inst2->Arg(2)};
@ -648,6 +699,169 @@ 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)};
@ -743,6 +957,12 @@ 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:
@ -858,6 +1078,11 @@ 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,9 +41,6 @@ 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;
@ -74,6 +71,11 @@ 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,13 +19,17 @@ 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.
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()));
for (const auto& library_path : library_paths) {
if (library_path && library->Open(library_path)) {
break;
}
}
#else
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);

View File

@ -313,6 +313,18 @@ 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,6 +11,8 @@
#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>
@ -916,7 +918,6 @@ 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,
@ -924,7 +925,18 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) {
return;
}
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
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);
}()};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
renderer.RequestScreenshot(
screenshot_image.bits(),

View File

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

View File

@ -4,6 +4,7 @@
#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"
@ -41,16 +42,19 @@ 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)},
ui_tab{std::make_unique<ConfigureUi>(system_, this)}, web_tab{std::make_unique<ConfigureWeb>(
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,6 +24,7 @@
#include <QtCore/qobjectdefs.h>
#include <qabstractbutton.h>
#include <qboxlayout.h>
#include <qcombobox.h>
#include <qcoreevent.h>
#include <qglobal.h>
#include <qgridlayout.h>
@ -77,13 +78,16 @@ 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_,
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_,
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)
: ConfigurationShared::Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
records{records_}, expose_compute_option{expose_compute_option_}, system{system_},
records{records_}, expose_compute_option{expose_compute_option_},
update_aspect_ratio{update_aspect_ratio_}, system{system_},
combobox_translations{builder.ComboboxTranslations()},
shader_mapping{
combobox_translations.at(Settings::EnumMetadata<Settings::ShaderBackend>::Index())} {
@ -140,6 +144,26 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
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()) &&
@ -280,6 +304,14 @@ 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,6 +14,7 @@
#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"
@ -43,12 +44,13 @@ 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_,
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,
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);
~ConfigureGraphics() override;
void ApplyConfiguration() override;
@ -91,6 +93,7 @@ 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;
@ -104,4 +107,6 @@ private:
QWidget* vulkan_device_widget;
QWidget* api_widget;
QWidget* shader_backend_widget;
QComboBox* aspect_ratio_combobox;
QComboBox* resolution_combobox;
};

View File

@ -17,6 +17,7 @@
#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"
@ -57,7 +58,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(); },
tab_group, *builder, this);
[](Settings::AspectRatio, Settings::ResolutionSetup) {}, 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,18 +1,31 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <utility>
#include <QFileDialog>
#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 "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 {
@ -54,8 +67,44 @@ 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>()}, system{system_} {
: QWidget(parent), ui{std::make_unique<Ui::ConfigureUi>()},
ratio{Settings::values.aspect_ratio.GetValue()},
resolution_setting{Settings::values.resolution_setup.GetValue()}, system{system_} {
ui->setupUi(this);
InitializeLanguageComboBox();
@ -68,6 +117,8 @@ 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.
@ -104,6 +155,10 @@ 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;
@ -123,6 +178,10 @@ 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();
}
@ -147,6 +206,13 @@ 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) {
@ -317,3 +383,29 @@ 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,6 +5,7 @@
#include <memory>
#include <QWidget>
#include "common/settings_enums.h"
namespace Core {
class System;
@ -23,6 +24,9 @@ public:
void ApplyConfiguration();
void UpdateScreenshotInfo(Settings::AspectRatio ratio,
Settings::ResolutionSetup resolution_info);
private slots:
void OnLanguageChanged(int index);
@ -44,7 +48,11 @@ 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>562</height>
<height>603</height>
</rect>
</property>
<property name="windowTitle">
@ -201,6 +201,41 @@
</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

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

View File

@ -36,4 +36,20 @@ 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,6 +13,7 @@
#include <QVector>
#include "common/common_types.h"
#include "common/settings.h"
#include "common/settings_enums.h"
using Settings::Category;
using Settings::Setting;
@ -127,8 +128,10 @@ 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;
@ -187,6 +190,8 @@ struct Values {
extern Values values;
u32 CalculateWidth(u32 height, Settings::AspectRatio ratio);
} // namespace UISettings
Q_DECLARE_METATYPE(UISettings::GameDir*);