mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-17 00:52:50 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f529fb880 | |||
| 8d10c788c4 | |||
| e0d47f2790 |
@@ -24,7 +24,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (lz4_FOUND AND NOT TARGET lz4::lz4)
|
if (lz4_FOUND AND NOT TARGET lz4::lz4)
|
||||||
if (TARGET LZ4::lz4_shared)
|
if (TARGET LZ4::lz4_shared AND NOT YUZU_STATIC_BUILD)
|
||||||
add_library(lz4::lz4 ALIAS LZ4::lz4_shared)
|
add_library(lz4::lz4 ALIAS LZ4::lz4_shared)
|
||||||
elseif (TARGET LZ4::lz4_static)
|
elseif (TARGET LZ4::lz4_static)
|
||||||
add_library(lz4::lz4 ALIAS LZ4::lz4_static)
|
add_library(lz4::lz4 ALIAS LZ4::lz4_static)
|
||||||
|
|||||||
-1
@@ -16,7 +16,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
||||||
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
||||||
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
||||||
NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"),
|
|
||||||
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
|
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
|
||||||
EMULATE_BGR565("emulate_bgr565"),
|
EMULATE_BGR565("emulate_bgr565"),
|
||||||
RESCALE_HACK("rescale_hack"),
|
RESCALE_HACK("rescale_hack"),
|
||||||
|
|||||||
-7
@@ -859,13 +859,6 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.skip_cpu_inner_invalidation_description
|
descriptionId = R.string.skip_cpu_inner_invalidation_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SwitchSetting(
|
|
||||||
BooleanSetting.NCE_INVALIDATION_GPU_READBACK,
|
|
||||||
titleId = R.string.nce_invalidation_gpu_readback,
|
|
||||||
descriptionId = R.string.nce_invalidation_gpu_readback_description
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.FIX_BLOOM_EFFECTS,
|
BooleanSetting.FIX_BLOOM_EFFECTS,
|
||||||
|
|||||||
-1
@@ -554,7 +554,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(HeaderSetting(R.string.hacks))
|
add(HeaderSetting(R.string.hacks))
|
||||||
|
|
||||||
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
||||||
add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key)
|
|
||||||
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
||||||
add(BooleanSetting.EMULATE_BGR565.key)
|
add(BooleanSetting.EMULATE_BGR565.key)
|
||||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||||
|
|||||||
@@ -587,8 +587,6 @@
|
|||||||
<string name="fast_gpu_time_description">يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch.</string>
|
<string name="fast_gpu_time_description">يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
|
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
|
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
|
||||||
<string name="nce_invalidation_gpu_readback">إعادة قراءة وحدة معالجة الرسومات قبل إبطال صلاحية NCE</string>
|
|
||||||
<string name="nce_invalidation_gpu_readback_description">إصلاح مؤقت. يعالج مشكلة تعطل لعبة Ender Magnolia (وغيرها من ألعاب UE). قد يؤدي إلى انخفاض في الأداء. يجري العمل على تحسينه.</string>
|
|
||||||
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
|
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
|
||||||
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
|
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
|
||||||
<string name="emulate_bgr565">محاكاة BGR565</string>
|
<string name="emulate_bgr565">محاكاة BGR565</string>
|
||||||
|
|||||||
@@ -577,8 +577,6 @@
|
|||||||
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
|
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
|
||||||
<string name="skip_cpu_inner_invalidation">跳過 CPU 內部失效處理</string>
|
<string name="skip_cpu_inner_invalidation">跳過 CPU 內部失效處理</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
|
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
|
||||||
<string name="nce_invalidation_gpu_readback">在 NCE 無效化前進行 GPU 回讀</string>
|
|
||||||
<string name="nce_invalidation_gpu_readback_description">(暫時性功能)修復 \"終結者瑪格諾莉亞:霧中綻放\" 及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中</string>
|
|
||||||
<string name="fix_bloom_effects">修正光暈特效</string>
|
<string name="fix_bloom_effects">修正光暈特效</string>
|
||||||
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
||||||
<string name="emulate_bgr565">模擬 BGR565</string>
|
<string name="emulate_bgr565">模擬 BGR565</string>
|
||||||
|
|||||||
@@ -593,8 +593,6 @@
|
|||||||
<string name="fast_gpu_time_description">Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks.</string>
|
<string name="fast_gpu_time_description">Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
||||||
<string name="nce_invalidation_gpu_readback">GPU Readback Before NCE Invalidation</string>
|
|
||||||
<string name="nce_invalidation_gpu_readback_description">Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress.</string>
|
|
||||||
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
||||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||||
<string name="emulate_bgr565">Emulate BGR565</string>
|
<string name="emulate_bgr565">Emulate BGR565</string>
|
||||||
|
|||||||
@@ -639,8 +639,6 @@ struct Values {
|
|||||||
Specialization::Default,
|
Specialization::Default,
|
||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
SwitchableSetting<bool> nce_invalidation_gpu_readback{
|
|
||||||
linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks};
|
|
||||||
SwitchableSetting<bool> async_presentation{linkage,
|
SwitchableSetting<bool> async_presentation{linkage,
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -40,12 +40,6 @@ bool IsConnectionBased(Type type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size of a real BSD sockaddr_in. The guest SockAddrIn struct is padded to 0x100 so that longer
|
|
||||||
// input addresses can be read, but an address handed back to the game is always this long.
|
|
||||||
// Reporting 0x100 lets a game that trusts the length copy 240 bytes past its 16-byte sockaddr
|
|
||||||
// (suspected cause of Crysis Remastered crashing ~30 s after its getsockname() call).
|
|
||||||
constexpr size_t GuestSockAddrInSize = 16;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetValue(std::span<const u8> buffer) {
|
T GetValue(std::span<const u8> buffer) {
|
||||||
T t{};
|
T t{};
|
||||||
@@ -661,9 +655,6 @@ std::pair<s32, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer)
|
|||||||
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
||||||
|
|
||||||
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
||||||
if (write_buffer.size() > GuestSockAddrInSize) {
|
|
||||||
write_buffer.resize(GuestSockAddrInSize);
|
|
||||||
}
|
|
||||||
PutValue(write_buffer, guest_addr_in);
|
PutValue(write_buffer, guest_addr_in);
|
||||||
|
|
||||||
return {new_fd, Errno::SUCCESS};
|
return {new_fd, Errno::SUCCESS};
|
||||||
@@ -723,8 +714,8 @@ Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
}
|
}
|
||||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||||
|
|
||||||
// The reported length must be that of a real sockaddr_in, not of the padded guest struct.
|
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||||
write_buffer.resize(GuestSockAddrInSize);
|
write_buffer.resize(sizeof(guest_addrin));
|
||||||
PutValue(write_buffer, guest_addrin);
|
PutValue(write_buffer, guest_addrin);
|
||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
@@ -745,8 +736,8 @@ Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
}
|
}
|
||||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||||
|
|
||||||
// The reported length must be that of a real sockaddr_in, not of the padded guest struct.
|
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||||
write_buffer.resize(GuestSockAddrInSize);
|
write_buffer.resize(sizeof(guest_addrin));
|
||||||
PutValue(write_buffer, guest_addrin);
|
PutValue(write_buffer, guest_addrin);
|
||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
@@ -958,9 +949,8 @@ std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>&
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
addr.clear();
|
addr.clear();
|
||||||
} else {
|
} else {
|
||||||
ASSERT(addr.size() >= GuestSockAddrInSize);
|
ASSERT(addr.size() >= 16);
|
||||||
const SockAddrIn result = Translate(addr_in);
|
const SockAddrIn result = Translate(addr_in);
|
||||||
addr.resize(GuestSockAddrInSize);
|
|
||||||
PutValue(addr, result);
|
PutValue(addr, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,10 +194,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
|||||||
INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"),
|
INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"),
|
||||||
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
|
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
|
||||||
"improving latency. This may cause soft-crashes."));
|
"improving latency. This may cause soft-crashes."));
|
||||||
INSERT(Settings, nce_invalidation_gpu_readback,
|
|
||||||
tr("GPU Readback Before NCE Invalidation"),
|
|
||||||
tr("Flushes GPU buffer data back to guest memory before NCE invalidates the whole "
|
|
||||||
"guest page, preserving it while the CPU store proceeds."));
|
|
||||||
INSERT(Settings, vsync_mode, tr("VSync Mode:"),
|
INSERT(Settings, vsync_mode, tr("VSync Mode:"),
|
||||||
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||||
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
|
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
|
||||||
|
|||||||
@@ -227,17 +227,17 @@ struct GPU::Impl {
|
|||||||
|
|
||||||
/// Notify rasterizer that any caches of the specified region should be invalidated
|
/// Notify rasterizer that any caches of the specified region should be invalidated
|
||||||
void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
|
void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) {
|
||||||
if (Settings::values.nce_invalidation_gpu_readback.GetValue()) {
|
if (preserve_gpu_writes) {
|
||||||
VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer();
|
VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer();
|
||||||
if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) {
|
if (!rasterizer->TryCacheInvalidation(addr, size)) {
|
||||||
const u64 fence = RequestSyncOperation([rasterizer, addr, size] {
|
const u64 fence = RequestSyncOperation([rasterizer, addr, size] {
|
||||||
rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache);
|
rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache);
|
||||||
rasterizer->OnCacheInvalidation(addr, size);
|
rasterizer->OnCacheInvalidation(addr, size);
|
||||||
});
|
});
|
||||||
gpu_thread.TickGPU(is_async);
|
gpu_thread.TickGPU(is_async);
|
||||||
WaitForSyncOperation(fence);
|
WaitForSyncOperation(fence);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
gpu_thread.InvalidateRegion(addr, size);
|
gpu_thread.InvalidateRegion(addr, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -111,6 +114,12 @@ public:
|
|||||||
/// Notify rasterizer that any caches of the specified region are desync with guest
|
/// Notify rasterizer that any caches of the specified region are desync with guest
|
||||||
virtual void OnCacheInvalidation(PAddr addr, u64 size) = 0;
|
virtual void OnCacheInvalidation(PAddr addr, u64 size) = 0;
|
||||||
|
|
||||||
|
virtual bool TryCacheInvalidation(DAddr addr, u64 size) {
|
||||||
|
if (MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) return false;
|
||||||
|
OnCacheInvalidation(addr, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool OnCPUWrite(PAddr addr, u64 size) = 0;
|
virtual bool OnCPUWrite(PAddr addr, u64 size) = 0;
|
||||||
|
|
||||||
/// Sync memory between guest and host.
|
/// Sync memory between guest and host.
|
||||||
|
|||||||
@@ -563,8 +563,10 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass,
|
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||||
VkFramebuffer framebuffer_handle, VkExtent2D render_area) {
|
const VkRenderPass render_pass = framebuffer->RenderPass();
|
||||||
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
const VkRenderPassBeginInfo renderpass_bi{
|
const VkRenderPassBeginInfo renderpass_bi{
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
@@ -677,67 +679,27 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
|||||||
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
||||||
VkImage src_image, VkSampler src_sampler,
|
VkImage src_image, VkSampler src_sampler,
|
||||||
const Region2D& dst_region, const Region2D& src_region,
|
const Region2D& dst_region, const Region2D& src_region,
|
||||||
const Extent3D& src_size,
|
const Extent3D& src_size) {
|
||||||
const std::optional<VkRect2D>& scissor) {
|
|
||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
||||||
|
|
||||||
// Clip the destination rectangle to the scissor; the viewport keeps the full rectangle so
|
|
||||||
// the texture coordinates are unchanged.
|
|
||||||
std::optional<VkRect2D> clip;
|
|
||||||
if (scissor) {
|
|
||||||
const s64 x0 = (std::max)(s64{(std::min)(dst_region.start.x, dst_region.end.x)},
|
|
||||||
s64{scissor->offset.x});
|
|
||||||
const s64 y0 = (std::max)(s64{(std::min)(dst_region.start.y, dst_region.end.y)},
|
|
||||||
s64{scissor->offset.y});
|
|
||||||
const s64 x1 = (std::min)(s64{(std::max)(dst_region.start.x, dst_region.end.x)},
|
|
||||||
s64{scissor->offset.x} + scissor->extent.width);
|
|
||||||
const s64 y1 = (std::min)(s64{(std::max)(dst_region.start.y, dst_region.end.y)},
|
|
||||||
s64{scissor->offset.y} + scissor->extent.height);
|
|
||||||
if (x1 <= x0 || y1 <= y0) {
|
|
||||||
return; // Fully scissored out.
|
|
||||||
}
|
|
||||||
clip = VkRect2D{
|
|
||||||
.offset = {static_cast<s32>(x0), static_cast<s32>(y0)},
|
|
||||||
.extent = {static_cast<u32>(x1 - x0), static_cast<u32>(y1 - y0)},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the framebuffer now: by the time the worker runs this, the texture cache may have
|
|
||||||
// retired it (moved into its delayed-destruction ring), leaving a null handle behind - Turnip
|
|
||||||
// then crashed in vkCmdBeginRenderPass (Crysis Remastered, DrawTexture).
|
|
||||||
const VkRenderPass render_pass = dst_framebuffer->RenderPass();
|
|
||||||
const VkFramebuffer framebuffer_handle = dst_framebuffer->Handle();
|
|
||||||
const VkExtent2D render_area = dst_framebuffer->RenderArea();
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([this, render_pass, framebuffer_handle, render_area, src_image_view,
|
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
|
||||||
src_image, src_sampler, dst_region, src_region, src_size, pipeline, layout,
|
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
|
||||||
clip](vk::CommandBuffer cmdbuf) {
|
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
// Images stay in GENERAL everywhere (the descriptor below says so too): only make the
|
BeginRenderPass(cmdbuf, dst_framebuffer);
|
||||||
// earlier writes visible. Moving the source to SHADER_READ_ONLY_OPTIMAL left it there
|
|
||||||
// for good, so every later render pass used it in the wrong layout.
|
|
||||||
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
BeginRenderPass(cmdbuf, render_pass, framebuffer_handle, render_area);
|
|
||||||
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||||
UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);
|
UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
nullptr);
|
nullptr);
|
||||||
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
||||||
if (clip) {
|
|
||||||
cmdbuf.SetScissor(0, *clip);
|
|
||||||
}
|
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
cmdbuf.EndRenderPass();
|
cmdbuf.EndRenderPass();
|
||||||
});
|
});
|
||||||
// The blit set its own pipeline, viewport and scissor: make the next draw set its own again,
|
|
||||||
// as every other helper here does. Without this the next draw kept the blit's viewport and
|
|
||||||
// scissor: Crysis Remastered drew its 256x256 minimap map over the whole screen.
|
|
||||||
scheduler.InvalidateState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::BlitImpl(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::BlitImpl(const Framebuffer* dst_framebuffer,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <optional>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
#include "video_core/engines/fermi_2d.h"
|
#include "video_core/engines/fermi_2d.h"
|
||||||
@@ -79,12 +78,9 @@ public:
|
|||||||
Tegra::Engines::Fermi2D::Filter filter,
|
Tegra::Engines::Fermi2D::Filter filter,
|
||||||
Tegra::Engines::Fermi2D::Operation operation);
|
Tegra::Engines::Fermi2D::Operation operation);
|
||||||
|
|
||||||
/// @param scissor Optional clip rectangle in framebuffer pixels (DrawTexture honours the
|
|
||||||
/// guest scissor like any other draw).
|
|
||||||
void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
||||||
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
||||||
const Region2D& src_region, const Extent3D& src_size,
|
const Region2D& src_region, const Extent3D& src_size);
|
||||||
const std::optional<VkRect2D>& scissor = std::nullopt);
|
|
||||||
|
|
||||||
void BlitColorMSAA(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
void BlitColorMSAA(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||||
const Region2D& dst_region, const Region2D& src_region);
|
const Region2D& dst_region, const Region2D& src_region);
|
||||||
|
|||||||
@@ -393,35 +393,8 @@ void RasterizerVulkan::DrawTexture() {
|
|||||||
.y = ScaleSrc(draw_texture_state.src_y1)}};
|
.y = ScaleSrc(draw_texture_state.src_y1)}};
|
||||||
Extent3D src_size = {static_cast<u32>(ScaleSrc(texture.size.width)),
|
Extent3D src_size = {static_cast<u32>(ScaleSrc(texture.size.width)),
|
||||||
static_cast<u32>(ScaleSrc(texture.size.height)), texture.size.depth};
|
static_cast<u32>(ScaleSrc(texture.size.height)), texture.size.depth};
|
||||||
// DrawTexture rectangles go through the fragment pipeline, scissor included.
|
|
||||||
std::optional<VkRect2D> scissor;
|
|
||||||
if (maxwell3d->regs.scissor_test[0].enable) {
|
|
||||||
u32 up_scale = 1;
|
|
||||||
u32 down_shift = 0;
|
|
||||||
if (dst_rescaling) {
|
|
||||||
up_scale = Settings::values.resolution_info.up_scale;
|
|
||||||
down_shift = Settings::values.resolution_info.down_shift;
|
|
||||||
}
|
|
||||||
scissor = GetScissorState(maxwell3d->regs, 0, up_scale, down_shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drawing a texture 1:1 onto itself without blending changes nothing on hardware, but here
|
|
||||||
// it samples the image the render pass is writing to: undefined in Vulkan, and on tiled GPUs
|
|
||||||
// it reads whatever the image memory last held. Crysis Remastered does this every frame for
|
|
||||||
// its post-processing buffers (suspected cause of its map covering the whole screen).
|
|
||||||
const auto& fb_images = framebuffer->Images();
|
|
||||||
const bool src_is_target =
|
|
||||||
std::find(fb_images.begin(), fb_images.begin() + framebuffer->NumImages(),
|
|
||||||
texture.ImageHandle()) != fb_images.begin() + framebuffer->NumImages();
|
|
||||||
if (src_is_target && src_rescaling == dst_rescaling &&
|
|
||||||
src_region.start.x == dst_region.start.x && src_region.start.y == dst_region.start.y &&
|
|
||||||
src_region.end.x == dst_region.end.x && src_region.end.y == dst_region.end.y &&
|
|
||||||
maxwell3d->regs.blend.enable[0] == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
blit_image.BlitColor(framebuffer, texture.RenderTarget(), texture.ImageHandle(),
|
blit_image.BlitColor(framebuffer, texture.RenderTarget(), texture.ImageHandle(),
|
||||||
sampler->Handle(), dst_region, src_region, src_size, scissor);
|
sampler->Handle(), dst_region, src_region, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::Clear(u32 layer_count) {
|
void RasterizerVulkan::Clear(u32 layer_count) {
|
||||||
@@ -825,6 +798,18 @@ void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
|
|||||||
pipeline_cache.InvalidateRegion(addr, size);
|
pipeline_cache.InvalidateRegion(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RasterizerVulkan::TryCacheInvalidation(DAddr addr, u64 size) {
|
||||||
|
if (addr == 0 || size == 0) return true;
|
||||||
|
{
|
||||||
|
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||||
|
if (buffer_cache.IsRegionGpuModified(addr, size)) return false;
|
||||||
|
texture_cache.WriteMemory(addr, size);
|
||||||
|
buffer_cache.WriteMemory(addr, size);
|
||||||
|
}
|
||||||
|
pipeline_cache.InvalidateRegion(addr, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::InvalidateGPUCache() {
|
void RasterizerVulkan::InvalidateGPUCache() {
|
||||||
gpu.InvalidateGPUCache();
|
gpu.InvalidateGPUCache();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ public:
|
|||||||
VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
|
VideoCommon::CacheType which = VideoCommon::CacheType::All) override;
|
||||||
void InnerInvalidation(std::span<const std::pair<DAddr, std::size_t>> sequences) override;
|
void InnerInvalidation(std::span<const std::pair<DAddr, std::size_t>> sequences) override;
|
||||||
void OnCacheInvalidation(DAddr addr, u64 size) override;
|
void OnCacheInvalidation(DAddr addr, u64 size) override;
|
||||||
|
bool TryCacheInvalidation(DAddr addr, u64 size) override;
|
||||||
bool OnCPUWrite(DAddr addr, u64 size) override;
|
bool OnCPUWrite(DAddr addr, u64 size) override;
|
||||||
void InvalidateGPUCache() override;
|
void InvalidateGPUCache() override;
|
||||||
void UnmapMemory(DAddr addr, u64 size) override;
|
void UnmapMemory(DAddr addr, u64 size) override;
|
||||||
|
|||||||
Reference in New Issue
Block a user