mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-03 21:17:46 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a7486b12cb | |||
| c9acc2fbf4 | |||
| 7a0190956e | |||
| 3c520528dd | |||
| f65160e141 | |||
| c41c64d6c7 | |||
| d16735f5b6 | |||
| d3550c4571 | |||
| 963119e7cc | |||
| 2a7e9b53b1 | |||
| 8e2d26c272 |
+1
-1
@@ -79,7 +79,7 @@
|
||||
"name": "ffmpeg",
|
||||
"package": "FFmpeg",
|
||||
"repo": "crueter-ci/FFmpeg",
|
||||
"version": "9.0.1-1788120736-bf1b838f2a"
|
||||
"version": "9.0.2-1790726865-946fcce07b"
|
||||
},
|
||||
"fmt": {
|
||||
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import java.io.File
|
||||
|
||||
@@ -146,11 +147,11 @@ class DriverViewModel : ViewModel() {
|
||||
private fun wipeGameShaders(game: Game) {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val externalFilesDir = YuzuApplication.appContext.getExternalFilesDir(null)
|
||||
val userDirectory = DirectoryInitialization.userDirectory
|
||||
?: return@withContext
|
||||
val shaderDir = File(
|
||||
externalFilesDir.absolutePath +
|
||||
"/shader/" + game.settingsName.lowercase()
|
||||
userDirectory +
|
||||
"/cache/shader/" + game.settingsName.lowercase()
|
||||
)
|
||||
if (shaderDir.exists()) {
|
||||
shaderDir.deleteRecursively()
|
||||
|
||||
@@ -653,9 +653,6 @@ struct Values {
|
||||
SwitchableSetting<bool> emulate_bgr565{linkage, false, "emulate_bgr565",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||
Category::RendererHacks};
|
||||
|
||||
|
||||
@@ -250,9 +250,10 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
|
||||
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
|
||||
case AppletId::NetConnect:
|
||||
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
|
||||
case AppletId::None:
|
||||
return nullptr;
|
||||
default:
|
||||
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X} program_id={:016X}"
|
||||
"Falling back to stub applet", static_cast<u8>(id), applet->program_id);
|
||||
UNIMPLEMENTED_MSG("No frontend implementation exists for applet_id={:02X} program_id={:016X}! Using stub applet.", static_cast<u8>(id), applet->program_id);
|
||||
return std::make_shared<StubApplet>(system, applet, id, mode);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -757,7 +757,7 @@ struct Memory::Impl {
|
||||
};
|
||||
auto& gpu = system.GPU();
|
||||
gpu_device_memory->ApplyOpOnPointer(
|
||||
p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
|
||||
p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size, true); });
|
||||
}
|
||||
|
||||
Core::System& system;
|
||||
|
||||
@@ -271,12 +271,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
||||
"quality and performance consistency in some games."));
|
||||
INSERT(Settings, fix_bloom_effects, tr("Fix bloom effects"), tr("Removes bloom in Burnout."));
|
||||
|
||||
INSERT(Settings, rescale_hack, tr("Enable Legacy Rescale Pass"),
|
||||
tr("May fix rescale issues in some games by relying on behavior from the previous "
|
||||
"implementation.\n"
|
||||
"Legacy behavior workaround that fixes line artifacts on AMD and Intel GPUs, and "
|
||||
"grey texture flicker on Nvidia GPUs in Luigis Mansion 3."));
|
||||
|
||||
// Renderer (Extensions)
|
||||
INSERT(Settings, dyna_state, tr("Extended Dynamic State"),
|
||||
tr("Controls the number of features that can be used in Extended Dynamic State.\n"
|
||||
|
||||
@@ -301,7 +301,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
Optimization::GlobalMemoryToStorageBufferPass(program, normalized_host_info);
|
||||
Optimization::TexturePass(env, program, normalized_host_info);
|
||||
|
||||
if (Settings::values.resolution_info.active || Settings::values.rescale_hack.GetValue()) {
|
||||
if (Settings::values.resolution_info.active) {
|
||||
Optimization::RescalingPass(program);
|
||||
}
|
||||
Optimization::DeadCodeEliminationPass(program);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -28,6 +31,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
||||
void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);
|
||||
void VendorWorkaroundPass(IR::Program& program);
|
||||
void VerificationPass(const IR::Program& program);
|
||||
bool HasBrokenPattern(const IR::Program& program);
|
||||
|
||||
// Dual Vertex
|
||||
void VertexATransformPass(IR::Program& program);
|
||||
|
||||
@@ -67,18 +67,11 @@ void VisitMark(IR::Block& block, IR::Inst& inst) {
|
||||
if (must_patch_outside) {
|
||||
const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
IR::IREmitter ir{block, it};
|
||||
if (Settings::values.rescale_hack.GetValue()) {
|
||||
const IR::F32 new_inst{&*block.PrependNewInst(it, inst)};
|
||||
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
|
||||
const IR::Value converted{ir.FPMul(new_inst, up_factor)};
|
||||
inst.ReplaceUsesWith(converted);
|
||||
} else {
|
||||
IR::Inst* const new_inst{&*block.PrependNewInst(it, inst)};
|
||||
const IR::F32 new_bitcast{ir.ConvertUToF(32, 32, IR::Value{new_inst})};
|
||||
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
|
||||
const IR::Value converted{ir.FPMul(new_bitcast, up_factor)};
|
||||
inst.ReplaceUsesWith(converted);
|
||||
}
|
||||
IR::Inst* const new_inst{&*block.PrependNewInst(it, inst)};
|
||||
const IR::F32 new_bitcast{ir.ConvertUToF(32, 32, IR::Value{new_inst})};
|
||||
const IR::F32 up_factor{ir.FPRecip(ir.ResolutionDownFactor())};
|
||||
const IR::Value converted{ir.FPMul(new_bitcast, up_factor)};
|
||||
inst.ReplaceUsesWith(converted);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -76,4 +79,44 @@ void VendorWorkaroundPass(IR::Program& program) {
|
||||
}
|
||||
}
|
||||
|
||||
bool HasBrokenPattern(const IR::Program& program) {
|
||||
if (program.stage != Stage::Fragment) {
|
||||
return false;
|
||||
}
|
||||
for (const IR::Block* block : program.post_order_blocks) {
|
||||
for (const IR::Inst& inst : block->Instructions()) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::ShuffleIndex:
|
||||
case IR::Opcode::ShuffleUp:
|
||||
case IR::Opcode::ShuffleDown:
|
||||
case IR::Opcode::ShuffleButterfly:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
const IR::Value shuffle_arg{inst.Arg(0)};
|
||||
if (shuffle_arg.IsImmediate()) {
|
||||
continue;
|
||||
}
|
||||
const IR::Inst* bitcast{shuffle_arg.InstRecursive()};
|
||||
if (!bitcast || bitcast->GetOpcode() != IR::Opcode::BitCastU32F32) {
|
||||
continue;
|
||||
}
|
||||
const IR::Value bitcast_arg{bitcast->Arg(0)};
|
||||
if (bitcast_arg.IsImmediate()) {
|
||||
continue;
|
||||
}
|
||||
const IR::Inst* attribute{bitcast_arg.InstRecursive()};
|
||||
if (!attribute || attribute->GetOpcode() != IR::Opcode::GetAttribute) {
|
||||
continue;
|
||||
}
|
||||
const IR::Attribute attr{attribute->Arg(0).Attribute()};
|
||||
if (attr == IR::Attribute::PositionX || attr == IR::Attribute::PositionY) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Shader::Optimization
|
||||
|
||||
+13
-3
@@ -226,7 +226,17 @@ struct GPU::Impl {
|
||||
}
|
||||
|
||||
/// Notify rasterizer that any caches of the specified region should be invalidated
|
||||
void InvalidateRegion(DAddr addr, u64 size) {
|
||||
void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
|
||||
VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer();
|
||||
if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) {
|
||||
const u64 fence = RequestSyncOperation([rasterizer, addr, size] {
|
||||
rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache);
|
||||
rasterizer->OnCacheInvalidation(addr, size);
|
||||
});
|
||||
gpu_thread.TickGPU(is_async);
|
||||
WaitForSyncOperation(fence);
|
||||
return;
|
||||
}
|
||||
gpu_thread.InvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
@@ -518,8 +528,8 @@ void GPU::FlushRegion(DAddr addr, u64 size) {
|
||||
impl->FlushRegion(addr, size);
|
||||
}
|
||||
|
||||
void GPU::InvalidateRegion(DAddr addr, u64 size) {
|
||||
impl->InvalidateRegion(addr, size);
|
||||
void GPU::InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
|
||||
impl->InvalidateRegion(addr, size, preserve_gpu_writes);
|
||||
}
|
||||
|
||||
bool GPU::OnCPUWrite(DAddr addr, u64 size) {
|
||||
|
||||
@@ -248,7 +248,7 @@ public:
|
||||
void FlushRegion(DAddr addr, u64 size);
|
||||
|
||||
/// Notify rasterizer that any caches of the specified region should be invalidated
|
||||
void InvalidateRegion(DAddr addr, u64 size);
|
||||
void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes = false);
|
||||
|
||||
/// Notify rasterizer that CPU is trying to write this area. It returns true if the area is
|
||||
/// sensible, false otherwise, addr and size must be a valid combination
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "shader_recompiler/environment.h"
|
||||
#include "shader_recompiler/frontend/maxwell/control_flow.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate_program.h"
|
||||
#include "shader_recompiler/ir_opt/passes.h"
|
||||
#include "shader_recompiler/program_header.h"
|
||||
#include "video_core/engines/kepler_compute.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
@@ -826,6 +827,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
||||
}
|
||||
|
||||
if (device.GetDriverID() != VK_DRIVER_ID_NVIDIA_PROPRIETARY && Shader::Optimization::HasBrokenPattern(programs[index])) {
|
||||
LOG_WARNING(Render_Vulkan, "0x{:016x}: Skipping shader with known issues", key.unique_hashes[index]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (Settings::values.dump_guest_shaders) {
|
||||
env.Dump(hash, key.unique_hashes[index]);
|
||||
}
|
||||
|
||||
+15
-11
@@ -12,25 +12,29 @@ namespace Yuzu {
|
||||
|
||||
inline bool ContainsAllWords(const QString& haystack, const QString& userinput) {
|
||||
const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
|
||||
return std::all_of(userinput_split.begin(), userinput_split.end(),
|
||||
[&haystack](const QString& s) { return haystack.contains(s); });
|
||||
return std::all_of(userinput_split.begin(), userinput_split.end(), [&haystack](const QString& s) {
|
||||
return haystack.contains(s);
|
||||
});
|
||||
}
|
||||
|
||||
inline bool FilterMatches(const QString& filter, const QStandardItem* item) {
|
||||
if (filter.isEmpty())
|
||||
return true;
|
||||
|
||||
auto const sluggify = [](const QString& s) {
|
||||
QString o(s.normalized(QString::NormalizationForm_D).toLower());
|
||||
return o.replace(QRegularExpression(QStringLiteral("[^a-z\\s]")), QStringLiteral(""));
|
||||
};
|
||||
|
||||
const auto norm_filter = sluggify(filter);
|
||||
const auto program_id = item->data(GameListItemPath::ProgramIdRole).toULongLong();
|
||||
|
||||
const QString file_path = item->data(GameListItemPath::FullPathRole).toString().toLower();
|
||||
const QString file_title = item->data(GameListItemPath::TitleRole).toString().toLower();
|
||||
const QString file_path = sluggify(item->data(GameListItemPath::FullPathRole).toString());
|
||||
const QString file_title = sluggify(item->data(GameListItemPath::TitleRole).toString());
|
||||
const QString file_program_id = QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'});
|
||||
|
||||
const QString file_name =
|
||||
file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title;
|
||||
|
||||
return Yuzu::ContainsAllWords(file_name, filter) ||
|
||||
(file_program_id.size() == 16 && file_program_id.contains(filter));
|
||||
const QString file_name = sluggify(file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title);
|
||||
return (ContainsAllWords(file_name, norm_filter)
|
||||
|| ContainsAllWords(file_title, norm_filter))
|
||||
|| (file_program_id.size() == 16 && file_program_id.contains(norm_filter));
|
||||
}
|
||||
|
||||
} // namespace Yuzu
|
||||
|
||||
Reference in New Issue
Block a user