Compare commits
21 Commits
android-47
...
android-49
Author | SHA1 | Date | |
---|---|---|---|
a2114ece93 | |||
ccd163ab2c | |||
182fb83556 | |||
35b77b9599 | |||
bc4ad5e62d | |||
ef61d129d3 | |||
b8bab551a4 | |||
a9f223cd9f | |||
87022a4833 | |||
1bc832c9b1 | |||
c03f0b3c89 | |||
6af8cca2c1 | |||
e28b936950 | |||
6fe51b48e9 | |||
96c98d09cb | |||
76a03e99b6 | |||
95409c6859 | |||
227950ac99 | |||
bc5ec10498 | |||
d9275b7757 | |||
3e28e85468 |
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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});
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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*);
|
||||
|
Reference in New Issue
Block a user