Compare commits

..

8 Commits

Author SHA1 Message Date
lizzie b3ff49aae4 fx 2026-07-21 11:29:59 +02:00
lizzie 71f0eec198 fixup 2026-07-21 11:29:59 +02:00
lizzie 9ee720ccb3 fix 2026-07-21 11:29:59 +02:00
lizzie e20b18fe2f wa 2026-07-21 11:29:59 +02:00
lizzie 8fca6bdf26 changed strings 2026-07-21 11:29:59 +02:00
lizzie 95da4d944d ts 2026-07-21 11:29:59 +02:00
lizzie c769cdc2ff [qt] Update FAQ links
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-07-21 11:29:59 +02:00
lizzie 89004124a5 [video_core] use bool params for read/writes and cascade them thru the calltree (#4001)
should make codegen a tad bit better and reduce icache pressure for what is otherwise a glorified memcpy

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4001
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-07-18 21:01:58 +02:00
32 changed files with 268 additions and 991 deletions
@@ -594,7 +594,7 @@ abstract class SettingsItem(
IntSetting.ANDROID_PIPELINE_WORKERS, IntSetting.ANDROID_PIPELINE_WORKERS,
titleId = R.string.pipeline_worker_cores, titleId = R.string.pipeline_worker_cores,
descriptionId = R.string.pipeline_worker_cores_description, descriptionId = R.string.pipeline_worker_cores_description,
min = 1, min = 4,
max = 8, max = 8,
units = "cores" units = "cores"
) )
@@ -147,7 +147,7 @@ namespace AndroidSettings {
&show_performance_overlay}; &show_performance_overlay};
Settings::Setting<s32> pipeline_worker_count{linkage, 2, "pipeline_worker_count", Settings::Setting<s32> pipeline_worker_count{linkage, 4, "pipeline_worker_count",
Settings::Category::Android, Settings::Category::Android,
Settings::Specialization::Default, Settings::Specialization::Default,
true, true,
@@ -3,7 +3,7 @@
<!-- General application strings --> <!-- General application strings -->
<string name="app_name" translatable="false">Eden</string> <string name="app_name" translatable="false">Eden</string>
<string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Learn more</a>]]></string> <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/QuickStart.md\">Learn more</a>]]></string>
<string name="notice_notification_channel_name">Notices and errors</string> <string name="notice_notification_channel_name">Notices and errors</string>
<string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string> <string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string>
<string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string> <string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string>
@@ -867,7 +867,7 @@
<string name="loader_error_file_not_found">ROM file does not exist</string> <string name="loader_error_file_not_found">ROM file does not exist</string>
<string name="loader_requires_firmware">Game Requires Firmware</string> <string name="loader_requires_firmware">Game Requires Firmware</string>
<string name="loader_requires_firmware_description"><![CDATA[The game you are trying to launch requires firmware to boot or to get past the opening menu. Please <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> dump and install firmware</a>, or press \"OK\" to launch anyways.]]></string> <string name="loader_requires_firmware_description"><![CDATA[This game may require firmware to function properly, and you don\'t have any installed. Please install firmware before launching, or press \"OK\" to launch anyways.]]></string>
<!-- Intent Launch strings --> <!-- Intent Launch strings -->
<string name="searching_for_game">Searching for game...</string> <string name="searching_for_game">Searching for game...</string>
+1 -3
View File
@@ -157,8 +157,6 @@ bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info,
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
} }
constexpr size_t NCE_WRITE_FAULT_CLUSTER_PAGES = 4;
bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
auto* info = static_cast<siginfo_t*>(raw_info); auto* info = static_cast<siginfo_t*>(raw_info);
@@ -167,7 +165,7 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi
const Common::ProcessAddress addr = const Common::ProcessAddress addr =
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK); (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory(); auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE * NCE_WRITE_FAULT_CLUSTER_PAGES)) { if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
// We handled the access successfully and are returning to guest code. // We handled the access successfully and are returning to guest code.
return true; return true;
} }
-5
View File
@@ -126,10 +126,6 @@ public:
// New batch API to update multiple ranges with a single lock acquisition. // New batch API to update multiple ranges with a single lock acquisition.
void UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta); void UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta);
void UpdateTexturePagesCount(DAddr addr, size_t size, s32 delta);
[[nodiscard]] bool IsRegionTextureCached(DAddr addr, size_t size) const noexcept;
private: private:
struct TranslationEntry { struct TranslationEntry {
DAddr guest_page{}; DAddr guest_page{};
@@ -238,7 +234,6 @@ private:
(1ULL << (device_virtual_bits - page_bits)) / subentries; (1ULL << (device_virtual_bits - page_bits)) / subentries;
using CachedPages = std::array<CounterEntry, num_counter_entries>; using CachedPages = std::array<CounterEntry, num_counter_entries>;
std::unique_ptr<CachedPages> cached_pages; std::unique_ptr<CachedPages> cached_pages;
std::unique_ptr<CachedPages> texture_cached_pages;
Common::RangeMutex counter_guard; Common::RangeMutex counter_guard;
std::mutex mapping_guard; std::mutex mapping_guard;
-23
View File
@@ -177,7 +177,6 @@ DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memo
{ {
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>(); impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
cached_pages = std::make_unique<CachedPages>(); cached_pages = std::make_unique<CachedPages>();
texture_cached_pages = std::make_unique<CachedPages>();
const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS; const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
for (size_t i = 0; i < total_virtual; i++) { for (size_t i = 0; i < total_virtual; i++) {
@@ -626,28 +625,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
UpdatePagesCachedCountNoLock(addr, size, delta); UpdatePagesCachedCountNoLock(addr, size, delta);
} }
template <typename Traits>
void DeviceMemoryManager<Traits>::UpdateTexturePagesCount(DAddr addr, size_t size, s32 delta) {
Common::ScopedRangeLock lk(counter_guard, addr, size);
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
for (size_t page = addr >> Memory::YUZU_PAGEBITS; page != page_end; ++page) {
CounterAtomicType& count = texture_cached_pages->at(page >> subentries_shift).Count(page);
count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);
}
}
template <typename Traits>
bool DeviceMemoryManager<Traits>::IsRegionTextureCached(DAddr addr, size_t size) const noexcept {
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
for (size_t page = addr >> Memory::YUZU_PAGEBITS; page != page_end; ++page) {
if (texture_cached_pages->at(page >> subentries_shift).Count(page).load(
std::memory_order_acquire) != 0) {
return true;
}
}
return false;
}
template <typename Traits> template <typename Traits>
void DeviceMemoryManager<Traits>::UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta) { void DeviceMemoryManager<Traits>::UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta) {
if (ranges.empty()) { if (ranges.empty()) {
+2 -3
View File
@@ -28,9 +28,8 @@ bool CheckGameFirmware(u64 program_id) {
!FirmwareManager::CheckFirmwarePresence(*system)) { !FirmwareManager::CheckFirmwarePresence(*system)) {
auto result = QtCommon::Frontend::Warning( auto result = QtCommon::Frontend::Warning(
tr("Game Requires Firmware"), tr("Game Requires Firmware"),
tr("The game you are trying to launch requires firmware to boot or to get past the " tr("This game may require firmware to function properly, and you don't have any installed. "
"opening menu. Please <a href='https://yuzu-mirror.github.io/help/quickstart'>" "Please install firmware before launching, or press \"OK\" to launch anyways."),
"dump and install firmware</a>, or press \"OK\" to launch anyways."),
QtCommon::Frontend::Ok | QtCommon::Frontend::Cancel); QtCommon::Frontend::Ok | QtCommon::Frontend::Cancel);
return result == QtCommon::Frontend::Ok; return result == QtCommon::Frontend::Ok;
+26 -100
View File
@@ -175,71 +175,9 @@ std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(DA
template <class P> template <class P>
void BufferCache<P>::DownloadMemory(DAddr device_addr, u64 size) { void BufferCache<P>::DownloadMemory(DAddr device_addr, u64 size) {
if constexpr (!USE_MEMORY_MAPS) { ForEachBufferInRange(device_addr, size, [&](BufferId, Buffer& buffer) {
std::scoped_lock lock{mutex}; DownloadBufferMemory(buffer, device_addr, size);
ForEachBufferInRange(device_addr, size, [&](BufferId, Buffer& buffer) {
DownloadBufferMemory(buffer, device_addr, size);
});
return;
}
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 8> downloads;
u64 total_size_bytes = 0;
u64 largest_copy = 0;
std::unique_lock lock{mutex};
ForEachBufferInRange(device_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
memory_tracker.ForEachDownloadRangeAndClear(
device_addr, size, [&](u64 device_addr_out, u64 range_size) {
const DAddr buffer_addr = buffer.CpuAddr();
const auto add_download = [&](DAddr start, DAddr end) {
const u64 new_offset = start - buffer_addr;
const u64 new_size = end - start;
downloads.push_back({
BufferCopy{
.src_offset = new_offset,
.dst_offset = total_size_bytes,
.size = new_size,
},
buffer_id,
});
constexpr u64 align = 64ULL;
constexpr u64 mask = ~(align - 1ULL);
total_size_bytes += (new_size + align - 1) & mask;
largest_copy = (std::max)(largest_copy, new_size);
};
gpu_modified_ranges.ForEachInRange(device_addr_out, range_size, add_download);
ClearDownload(device_addr_out, range_size);
gpu_modified_ranges.Subtract(device_addr_out, range_size);
});
}); });
if (total_size_bytes == 0) {
return;
}
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
boost::container::small_vector<BufferCopy, 8> writebacks;
runtime.PreCopyBarrier();
for (auto& [copy, buffer_id] : downloads) {
copy.dst_offset += download_staging.offset;
Buffer& buffer = slot_buffers[buffer_id];
buffer.MarkUsage(copy.src_offset, copy.size);
const std::array copies{copy};
runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
BufferCopy writeback{copy};
writeback.src_offset = static_cast<u64>(buffer.CpuAddr()) + copy.src_offset;
writebacks.push_back(writeback);
}
runtime.PostCopyBarrier();
lock.unlock();
runtime.Finish();
const u8* const base = download_staging.mapped_span.data();
for (const BufferCopy& writeback : writebacks) {
const u64 staging_offset = writeback.dst_offset - download_staging.offset;
device_memory.WriteBlockUnsafe(static_cast<DAddr>(writeback.src_offset),
base + staging_offset, writeback.size);
}
} }
template <class P> template <class P>
@@ -276,7 +214,7 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
auto& src_buffer = slot_buffers[buffer_a]; auto& src_buffer = slot_buffers[buffer_a];
auto& dest_buffer = slot_buffers[buffer_b]; auto& dest_buffer = slot_buffers[buffer_b];
SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount)); SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
memory_tracker.UnmarkRegionAsCpuModified(*cpu_dest_address, static_cast<u32>(amount)); SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount));
std::array copies{BufferCopy{ std::array copies{BufferCopy{
.src_offset = src_buffer.Offset(*cpu_src_address), .src_offset = src_buffer.Offset(*cpu_src_address),
.dst_offset = dest_buffer.Offset(*cpu_dest_address), .dst_offset = dest_buffer.Offset(*cpu_dest_address),
@@ -735,44 +673,32 @@ void BufferCache<P>::PopAsyncFlushes() {
template <class P> template <class P>
void BufferCache<P>::PopAsyncBuffers() { void BufferCache<P>::PopAsyncBuffers() {
struct Writeback { if (async_buffers.empty()) {
DAddr addr; return;
const u8* src; }
u64 size; if (!async_buffers.front().has_value()) {
};
boost::container::small_vector<Writeback, 8> writebacks;
{
std::scoped_lock lock{mutex};
if (async_buffers.empty()) {
return;
}
if (!async_buffers.front().has_value()) {
async_buffers.pop_front();
return;
}
auto& downloads = pending_downloads.front();
auto& async_buffer = async_buffers.front();
const u8* base = async_buffer->mapped_span.data();
const size_t base_offset = async_buffer->offset;
for (const auto& copy : downloads) {
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
const u64 dst_offset = copy.dst_offset - base_offset;
const u8* read_mapped_memory = base + dst_offset;
async_downloads.ForEachInRange(device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
writebacks.push_back(
{start, &read_mapped_memory[start - device_addr], end - start});
});
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
gpu_modified_ranges.Subtract(start, end - start);
});
}
async_buffers_death_ring.emplace_back(*async_buffer);
async_buffers.pop_front(); async_buffers.pop_front();
pending_downloads.pop_front(); return;
} }
for (const auto& wb : writebacks) { auto& downloads = pending_downloads.front();
device_memory.WriteBlockUnsafe(wb.addr, wb.src, wb.size); auto& async_buffer = async_buffers.front();
u8* base = async_buffer->mapped_span.data();
const size_t base_offset = async_buffer->offset;
for (const auto& copy : downloads) {
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
const u64 dst_offset = copy.dst_offset - base_offset;
const u8* read_mapped_memory = base + dst_offset;
async_downloads.ForEachInRange(device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
device_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - device_addr],
end - start);
});
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
gpu_modified_ranges.Subtract(start, end - start);
});
} }
async_buffers_death_ring.emplace_back(*async_buffer);
async_buffers.pop_front();
pending_downloads.pop_front();
} }
template <class P> template <class P>
+5 -2
View File
@@ -91,6 +91,9 @@ public:
func(); func();
} }
fences.push(std::move(new_fence)); fences.push(std::move(new_fence));
if (should_flush) {
rasterizer.FlushCommands();
}
if constexpr (can_async_check) { if constexpr (can_async_check) {
guard.unlock(); guard.unlock();
cv.notify_all(); cv.notify_all();
@@ -235,10 +238,10 @@ private:
void PopAsyncFlushes() { void PopAsyncFlushes() {
{ {
std::scoped_lock lock{texture_cache.mutex}; std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
texture_cache.PopAsyncFlushes(); texture_cache.PopAsyncFlushes();
buffer_cache.PopAsyncFlushes();
} }
buffer_cache.PopAsyncFlushes();
query_cache.PopAsyncFlushes(); query_cache.PopAsyncFlushes();
} }
+84 -127
View File
@@ -58,9 +58,8 @@ MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, GPU
MemoryManager::~MemoryManager() = default; MemoryManager::~MemoryManager() = default;
template <bool is_big_page> MemoryManager::EntryType MemoryManager::GetEntry(size_t position, bool is_big_page) const {
MemoryManager::EntryType MemoryManager::GetEntry(size_t position) const { if (is_big_page) {
if constexpr (is_big_page) {
position = position >> big_page_bits; position = position >> big_page_bits;
const u64 entry_mask = big_entries[position / 32]; const u64 entry_mask = big_entries[position / 32];
const size_t sub_index = position % 32; const size_t sub_index = position % 32;
@@ -73,9 +72,8 @@ MemoryManager::EntryType MemoryManager::GetEntry(size_t position) const {
} }
} }
template <bool is_big_page> void MemoryManager::SetEntry(size_t position, MemoryManager::EntryType entry, bool is_big_page) {
void MemoryManager::SetEntry(size_t position, MemoryManager::EntryType entry) { if (is_big_page) {
if constexpr (is_big_page) {
position = position >> big_page_bits; position = position >> big_page_bits;
const u64 entry_mask = big_entries[position / 32]; const u64 entry_mask = big_entries[position / 32];
const size_t sub_index = position % 32; const size_t sub_index = position % 32;
@@ -108,23 +106,21 @@ inline void MemoryManager::SetBigPageContinuous(size_t big_page_index, bool valu
(~(1ULL << sub_index) & continuous_mask) | (value ? 1ULL << sub_index : 0); (~(1ULL << sub_index) & continuous_mask) | (value ? 1ULL << sub_index : 0);
} }
template <MemoryManager::EntryType entry_type> GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, PTEKind kind, MemoryManager::EntryType entry_type) {
GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size,
PTEKind kind) {
[[maybe_unused]] u64 remaining_size{size}; [[maybe_unused]] u64 remaining_size{size};
if constexpr (entry_type == EntryType::Mapped) { if (entry_type == EntryType::Mapped) {
page_table.ReserveRange(gpu_addr, size); page_table.ReserveRange(gpu_addr, size);
} }
for (u64 offset{}; offset < size; offset += page_size) { for (u64 offset{}; offset < size; offset += page_size) {
const GPUVAddr current_gpu_addr = gpu_addr + offset; const GPUVAddr current_gpu_addr = gpu_addr + offset;
[[maybe_unused]] const auto current_entry_type = GetEntry<false>(current_gpu_addr); [[maybe_unused]] const auto current_entry_type = GetEntry(current_gpu_addr, false);
SetEntry<false>(current_gpu_addr, entry_type); SetEntry(current_gpu_addr, entry_type, false);
if (current_entry_type != entry_type) { if (current_entry_type != entry_type) {
rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size); rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, page_size);
} }
if constexpr (entry_type == EntryType::Mapped) { if (entry_type == EntryType::Mapped) {
const DAddr current_dev_addr = dev_addr + offset; const DAddr current_dev_addr = dev_addr + offset;
const auto index = PageEntryIndex<false>(current_gpu_addr); const auto index = PageEntryIndex(current_gpu_addr, false);
const u32 sub_value = static_cast<u32>(current_dev_addr >> cpu_page_bits); const u32 sub_value = static_cast<u32>(current_dev_addr >> cpu_page_bits);
page_table[index] = sub_value; page_table[index] = sub_value;
} }
@@ -134,20 +130,18 @@ GPUVAddr MemoryManager::PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr de
return gpu_addr; return gpu_addr;
} }
template <MemoryManager::EntryType entry_type> GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, PTEKind kind, MemoryManager::EntryType entry_type) {
GPUVAddr MemoryManager::BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr,
size_t size, PTEKind kind) {
[[maybe_unused]] u64 remaining_size{size}; [[maybe_unused]] u64 remaining_size{size};
for (u64 offset{}; offset < size; offset += big_page_size) { for (u64 offset{}; offset < size; offset += big_page_size) {
const GPUVAddr current_gpu_addr = gpu_addr + offset; const GPUVAddr current_gpu_addr = gpu_addr + offset;
[[maybe_unused]] const auto current_entry_type = GetEntry<true>(current_gpu_addr); [[maybe_unused]] const auto current_entry_type = GetEntry(current_gpu_addr, true);
SetEntry<true>(current_gpu_addr, entry_type); SetEntry(current_gpu_addr, entry_type, true);
if (current_entry_type != entry_type) { if (current_entry_type != entry_type) {
rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size); rasterizer->ModifyGPUMemory(unique_identifier, current_gpu_addr, big_page_size);
} }
if constexpr (entry_type == EntryType::Mapped) { if (entry_type == EntryType::Mapped) {
const DAddr current_dev_addr = dev_addr + offset; const DAddr current_dev_addr = dev_addr + offset;
const auto index = PageEntryIndex<true>(current_gpu_addr); const auto index = PageEntryIndex(current_gpu_addr, true);
const u32 sub_value = static_cast<u32>(current_dev_addr >> cpu_page_bits); const u32 sub_value = static_cast<u32>(current_dev_addr >> cpu_page_bits);
big_page_table_dev[index] = sub_value; big_page_table_dev[index] = sub_value;
const bool is_continuous = ([&] { const bool is_continuous = ([&] {
@@ -181,19 +175,16 @@ void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_)
rasterizer = rasterizer_; rasterizer = rasterizer_;
} }
GPUVAddr MemoryManager::Map(GPUVAddr gpu_addr, DAddr dev_addr, std::size_t size, PTEKind kind, GPUVAddr MemoryManager::Map(GPUVAddr gpu_addr, DAddr dev_addr, std::size_t size, PTEKind kind, bool is_big_pages) {
bool is_big_pages) { if (is_big_pages)
if (is_big_pages) [[likely]] { return BigPageTableOp(gpu_addr, dev_addr, size, kind, EntryType::Mapped);
return BigPageTableOp<EntryType::Mapped>(gpu_addr, dev_addr, size, kind); return PageTableOp(gpu_addr, dev_addr, size, kind, EntryType::Mapped);
}
return PageTableOp<EntryType::Mapped>(gpu_addr, dev_addr, size, kind);
} }
GPUVAddr MemoryManager::MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages) { GPUVAddr MemoryManager::MapSparse(GPUVAddr gpu_addr, std::size_t size, bool is_big_pages) {
if (is_big_pages) [[likely]] { if (is_big_pages)
return BigPageTableOp<EntryType::Reserved>(gpu_addr, 0, size, PTEKind::INVALID); return BigPageTableOp(gpu_addr, 0, size, PTEKind::INVALID, EntryType::Reserved);
} return PageTableOp(gpu_addr, 0, size, PTEKind::INVALID, EntryType::Reserved);
return PageTableOp<EntryType::Reserved>(gpu_addr, 0, size, PTEKind::INVALID);
} }
void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) { void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
@@ -207,26 +198,21 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
} }
page_stash.clear(); page_stash.clear();
BigPageTableOp<EntryType::Free>(gpu_addr, 0, size, PTEKind::INVALID); BigPageTableOp(gpu_addr, 0, size, PTEKind::INVALID, EntryType::Free);
PageTableOp<EntryType::Free>(gpu_addr, 0, size, PTEKind::INVALID); PageTableOp(gpu_addr, 0, size, PTEKind::INVALID, EntryType::Free);
} }
std::optional<DAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const { std::optional<DAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
if (!IsWithinGPUAddressRange(gpu_addr)) [[unlikely]] { if (!IsWithinGPUAddressRange(gpu_addr)) [[unlikely]] {
return std::nullopt; return std::nullopt;
} }
if (GetEntry<true>(gpu_addr) != EntryType::Mapped) [[unlikely]] { if (GetEntry(gpu_addr, true) != EntryType::Mapped) [[unlikely]] {
if (GetEntry<false>(gpu_addr) != EntryType::Mapped) { if (GetEntry(gpu_addr, false) != EntryType::Mapped)
return std::nullopt; return std::nullopt;
} const DAddr dev_addr_base = DAddr(page_table[PageEntryIndex(gpu_addr, false)]) << cpu_page_bits;
const DAddr dev_addr_base = static_cast<DAddr>(page_table[PageEntryIndex<false>(gpu_addr)])
<< cpu_page_bits;
return dev_addr_base + (gpu_addr & page_mask); return dev_addr_base + (gpu_addr & page_mask);
} }
const DAddr dev_addr_base = DAddr(big_page_table_dev[PageEntryIndex(gpu_addr, true)]) << cpu_page_bits;
const DAddr dev_addr_base =
static_cast<DAddr>(big_page_table_dev[PageEntryIndex<true>(gpu_addr)]) << cpu_page_bits;
return dev_addr_base + (gpu_addr & big_page_mask); return dev_addr_base + (gpu_addr & big_page_mask);
} }
@@ -299,10 +285,8 @@ const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const {
#pragma inline_recursion(on) #pragma inline_recursion(on)
#endif #endif
template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped> template <typename FuncMapped, typename FuncReserved, typename FuncUnmapped>
inline void MemoryManager::MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, inline void MemoryManager::MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, bool is_big_page, FuncMapped&& func_mapped, FuncReserved&& func_reserved, FuncUnmapped&& func_unmapped) const {
FuncMapped&& func_mapped, FuncReserved&& func_reserved,
FuncUnmapped&& func_unmapped) const {
using FuncMappedReturn = using FuncMappedReturn =
typename std::invoke_result<FuncMapped, std::size_t, std::size_t, std::size_t>::type; typename std::invoke_result<FuncMapped, std::size_t, std::size_t, std::size_t>::type;
using FuncReservedReturn = using FuncReservedReturn =
@@ -315,7 +299,7 @@ inline void MemoryManager::MemoryOperation(GPUVAddr gpu_src_addr, std::size_t si
u64 used_page_size; u64 used_page_size;
u64 used_page_mask; u64 used_page_mask;
u64 used_page_bits; u64 used_page_bits;
if constexpr (is_big_pages) { if (is_big_page) {
used_page_size = big_page_size; used_page_size = big_page_size;
used_page_mask = big_page_mask; used_page_mask = big_page_mask;
used_page_bits = big_page_bits; used_page_bits = big_page_bits;
@@ -332,7 +316,7 @@ inline void MemoryManager::MemoryOperation(GPUVAddr gpu_src_addr, std::size_t si
while (remaining_size > 0) { while (remaining_size > 0) {
const std::size_t copy_amount{ const std::size_t copy_amount{
(std::min)(static_cast<std::size_t>(used_page_size) - page_offset, remaining_size)}; (std::min)(static_cast<std::size_t>(used_page_size) - page_offset, remaining_size)};
auto entry = GetEntry<is_big_pages>(current_address); auto entry = GetEntry(current_address, is_big_page);
if (entry == EntryType::Mapped) [[likely]] { if (entry == EntryType::Mapped) [[likely]] {
if constexpr (BOOL_BREAK_MAPPED) { if constexpr (BOOL_BREAK_MAPPED) {
if (func_mapped(page_index, page_offset, copy_amount)) { if (func_mapped(page_index, page_offset, copy_amount)) {
@@ -367,18 +351,14 @@ inline void MemoryManager::MemoryOperation(GPUVAddr gpu_src_addr, std::size_t si
} }
} }
template <bool is_safe> void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, [[maybe_unused]] VideoCommon::CacheType which, bool unsafe) const {
void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, auto set_to_zero = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, std::size_t copy_amount) {
[[maybe_unused]] VideoCommon::CacheType which) const {
auto set_to_zero = [&]([[maybe_unused]] std::size_t page_index,
[[maybe_unused]] std::size_t offset, std::size_t copy_amount) {
std::memset(dest_buffer, 0, copy_amount); std::memset(dest_buffer, 0, copy_amount);
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
}; };
auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(page_table[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset; if (!unsafe) {
if constexpr (is_safe) {
rasterizer->FlushRegion(dev_addr_base, copy_amount, which); rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
} }
u8* physical = memory.GetPointer<u8>(dev_addr_base); u8* physical = memory.GetPointer<u8>(dev_addr_base);
@@ -386,9 +366,8 @@ void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std:
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
}; };
auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset; if (!unsafe) {
if constexpr (is_safe) {
rasterizer->FlushRegion(dev_addr_base, copy_amount, which); rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
} }
if (!IsBigPageContinuous(page_index)) [[unlikely]] { if (!IsBigPageContinuous(page_index)) [[unlikely]] {
@@ -399,35 +378,28 @@ void MemoryManager::ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std:
} }
dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
}; };
auto read_short_pages = [&](std::size_t page_index, std::size_t offset, auto read_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, mapped_normal, set_to_zero, set_to_zero); MemoryOperation(base, copy_amount, false, mapped_normal, set_to_zero, set_to_zero);
}; };
MemoryOperation<true>(gpu_src_addr, size, mapped_big, set_to_zero, read_short_pages); MemoryOperation(gpu_src_addr, size, true, mapped_big, set_to_zero, read_short_pages);
} }
void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, VideoCommon::CacheType which) const {
VideoCommon::CacheType which) const { ReadBlockImpl(gpu_src_addr, dest_buffer, size, which, false);
ReadBlockImpl<true>(gpu_src_addr, dest_buffer, size, which);
} }
void MemoryManager::ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, void MemoryManager::ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer, const std::size_t size) const {
const std::size_t size) const { ReadBlockImpl(gpu_src_addr, dest_buffer, size, VideoCommon::CacheType::None, true);
ReadBlockImpl<false>(gpu_src_addr, dest_buffer, size, VideoCommon::CacheType::None);
} }
template <bool is_safe> void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, [[maybe_unused]] VideoCommon::CacheType which, bool unsafe) {
void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, auto just_advance = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, std::size_t copy_amount) {
[[maybe_unused]] VideoCommon::CacheType which) {
auto just_advance = [&]([[maybe_unused]] std::size_t page_index,
[[maybe_unused]] std::size_t offset, std::size_t copy_amount) {
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
}; };
auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(page_table[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset; if (!unsafe) {
if constexpr (is_safe) {
rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which); rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
} }
u8* physical = memory.GetPointer<u8>(dev_addr_base); u8* physical = memory.GetPointer<u8>(dev_addr_base);
@@ -435,9 +407,8 @@ void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffe
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
}; };
auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset; if (!unsafe) {
if constexpr (is_safe) {
rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which); rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
} }
if (!IsBigPageContinuous(page_index)) [[unlikely]] { if (!IsBigPageContinuous(page_index)) [[unlikely]] {
@@ -448,26 +419,23 @@ void MemoryManager::WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffe
} }
src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
}; };
auto write_short_pages = [&](std::size_t page_index, std::size_t offset, auto write_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, mapped_normal, just_advance, just_advance); MemoryOperation(base, copy_amount, false, mapped_normal, just_advance, just_advance);
}; };
MemoryOperation<true>(gpu_dest_addr, size, mapped_big, just_advance, write_short_pages); MemoryOperation(gpu_dest_addr, size, true, mapped_big, just_advance, write_short_pages);
} }
void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, VideoCommon::CacheType which) {
VideoCommon::CacheType which) { WriteBlockImpl(gpu_dest_addr, src_buffer, size, which, false);
WriteBlockImpl<true>(gpu_dest_addr, src_buffer, size, which);
} }
void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size) {
std::size_t size) { WriteBlockImpl(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None, true);
WriteBlockImpl<false>(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None);
} }
void MemoryManager::WriteBlockCached(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size) { void MemoryManager::WriteBlockCached(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size) {
WriteBlockImpl<false>(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None); WriteBlockImpl(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None, true);
accumulator.Add(gpu_dest_addr, size); accumulator.Add(gpu_dest_addr, size);
} }
@@ -478,21 +446,18 @@ void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size,
[[maybe_unused]] std::size_t copy_amount) {}; [[maybe_unused]] std::size_t copy_amount) {};
auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(page_table[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
rasterizer->FlushRegion(dev_addr_base, copy_amount, which); rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
}; };
auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
rasterizer->FlushRegion(dev_addr_base, copy_amount, which); rasterizer->FlushRegion(dev_addr_base, copy_amount, which);
}; };
auto flush_short_pages = [&](std::size_t page_index, std::size_t offset, auto flush_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, mapped_normal, do_nothing, do_nothing); MemoryOperation(base, copy_amount, false, mapped_normal, do_nothing, do_nothing);
}; };
MemoryOperation<true>(gpu_addr, size, mapped_big, do_nothing, flush_short_pages); MemoryOperation(gpu_addr, size, true, mapped_big, do_nothing, flush_short_pages);
} }
bool MemoryManager::IsMemoryDirty(GPUVAddr gpu_addr, size_t size, bool MemoryManager::IsMemoryDirty(GPUVAddr gpu_addr, size_t size,
@@ -517,10 +482,10 @@ bool MemoryManager::IsMemoryDirty(GPUVAddr gpu_addr, size_t size,
auto check_short_pages = [&](std::size_t page_index, std::size_t offset, auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
std::size_t copy_amount) { std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, mapped_normal, do_nothing, do_nothing); MemoryOperation(base, copy_amount, false, mapped_normal, do_nothing, do_nothing);
return result; return result;
}; };
MemoryOperation<true>(gpu_addr, size, mapped_big, do_nothing, check_short_pages); MemoryOperation(gpu_addr, size, true, mapped_big, do_nothing, check_short_pages);
return result; return result;
} }
@@ -557,10 +522,10 @@ size_t MemoryManager::MaxContinuousRange(GPUVAddr gpu_addr, size_t size) const {
auto check_short_pages = [&](std::size_t page_index, std::size_t offset, auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
std::size_t copy_amount) { std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, short_check, fail, fail); MemoryOperation(base, copy_amount, false, short_check, fail, fail);
return result; return result;
}; };
MemoryOperation<true>(gpu_addr, size, big_check, fail, check_short_pages); MemoryOperation(gpu_addr, size, true, big_check, fail, check_short_pages);
return range_so_far; return range_so_far;
} }
@@ -576,21 +541,18 @@ void MemoryManager::InvalidateRegion(GPUVAddr gpu_addr, size_t size,
[[maybe_unused]] std::size_t copy_amount) {}; [[maybe_unused]] std::size_t copy_amount) {};
auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_normal = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(page_table[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(page_table[page_index]) << cpu_page_bits) + offset;
rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which); rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
}; };
auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto mapped_big = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
const DAddr dev_addr_base = const DAddr dev_addr_base = (DAddr(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
(static_cast<DAddr>(big_page_table_dev[page_index]) << cpu_page_bits) + offset;
rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which); rasterizer->InvalidateRegion(dev_addr_base, copy_amount, which);
}; };
auto invalidate_short_pages = [&](std::size_t page_index, std::size_t offset, auto invalidate_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, mapped_normal, do_nothing, do_nothing); MemoryOperation(base, copy_amount, false, mapped_normal, do_nothing, do_nothing);
}; };
MemoryOperation<true>(gpu_addr, size, mapped_big, do_nothing, invalidate_short_pages); MemoryOperation(gpu_addr, size, true, mapped_big, do_nothing, invalidate_short_pages);
} }
void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size,
@@ -602,7 +564,7 @@ void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std
} }
bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const { bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const {
if (GetEntry<true>(gpu_addr) == EntryType::Mapped) [[likely]] { if (GetEntry(gpu_addr, true) == EntryType::Mapped) [[likely]] {
size_t page_index = gpu_addr >> big_page_bits; size_t page_index = gpu_addr >> big_page_bits;
if (IsBigPageContinuous(page_index)) [[likely]] { if (IsBigPageContinuous(page_index)) [[likely]] {
const std::size_t page{(page_index & big_page_mask) + size}; const std::size_t page{(page_index & big_page_mask) + size};
@@ -611,7 +573,7 @@ bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) const {
const std::size_t page{(gpu_addr & Core::DEVICE_PAGEMASK) + size}; const std::size_t page{(gpu_addr & Core::DEVICE_PAGEMASK) + size};
return page <= Core::DEVICE_PAGESIZE; return page <= Core::DEVICE_PAGESIZE;
} }
if (GetEntry<false>(gpu_addr) != EntryType::Mapped) { if (GetEntry(gpu_addr, false) != EntryType::Mapped) {
return false; return false;
} }
const std::size_t page{(gpu_addr & Core::DEVICE_PAGEMASK) + size}; const std::size_t page{(gpu_addr & Core::DEVICE_PAGEMASK) + size};
@@ -649,10 +611,10 @@ bool MemoryManager::IsContinuousRange(GPUVAddr gpu_addr, std::size_t size) const
auto check_short_pages = [&](std::size_t page_index, std::size_t offset, auto check_short_pages = [&](std::size_t page_index, std::size_t offset,
std::size_t copy_amount) { std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, short_check, fail, fail); MemoryOperation(base, copy_amount, false, short_check, fail, fail);
return !result; return !result;
}; };
MemoryOperation<true>(gpu_addr, size, big_check, fail, check_short_pages); MemoryOperation(gpu_addr, size, true, big_check, fail, check_short_pages);
return result; return result;
} }
@@ -665,13 +627,12 @@ bool MemoryManager::IsFullyMappedRange(GPUVAddr gpu_addr, std::size_t size) cons
}; };
auto pass = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset, auto pass = [&]([[maybe_unused]] std::size_t page_index, [[maybe_unused]] std::size_t offset,
[[maybe_unused]] std::size_t copy_amount) { return false; }; [[maybe_unused]] std::size_t copy_amount) { return false; };
auto check_short_pages = [&](std::size_t page_index, std::size_t offset, auto check_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, pass, pass, fail); MemoryOperation(base, copy_amount, false, pass, pass, fail);
return !result; return !result;
}; };
MemoryOperation<true>(gpu_addr, size, pass, fail, check_short_pages); MemoryOperation(gpu_addr, size, true, pass, fail, check_short_pages);
return result; return result;
} }
@@ -683,13 +644,9 @@ MemoryManager::GetSubmappedRange(GPUVAddr gpu_addr, std::size_t size) const {
} }
template <bool is_gpu_address> template <bool is_gpu_address>
void MemoryManager::GetSubmappedRangeImpl( void MemoryManager::GetSubmappedRangeImpl(GPUVAddr gpu_addr, std::size_t size, boost::container::small_vector<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>, 32>& result)
GPUVAddr gpu_addr, std::size_t size,
boost::container::small_vector<
std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>, 32>& result)
const { const {
std::optional<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>> std::optional<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>> last_segment{};
last_segment{};
std::optional<DAddr> old_page_addr{}; std::optional<DAddr> old_page_addr{};
const auto split = [&last_segment, &result]([[maybe_unused]] std::size_t page_index, const auto split = [&last_segment, &result]([[maybe_unused]] std::size_t page_index,
[[maybe_unused]] std::size_t offset, [[maybe_unused]] std::size_t offset,
@@ -745,9 +702,9 @@ void MemoryManager::GetSubmappedRangeImpl(
}; };
auto do_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) { auto do_short_pages = [&](std::size_t page_index, std::size_t offset, std::size_t copy_amount) {
GPUVAddr base = (page_index << big_page_bits) + offset; GPUVAddr base = (page_index << big_page_bits) + offset;
MemoryOperation<false>(base, copy_amount, extend_size_short, split, split); MemoryOperation(base, copy_amount, false, extend_size_short, split, split);
}; };
MemoryOperation<true>(gpu_addr, size, extend_size_big, split, do_short_pages); MemoryOperation(gpu_addr, size, true, extend_size_big, split, do_short_pages);
split(0, 0, 0); split(0, 0, 0);
} }
+19 -40
View File
@@ -45,7 +45,7 @@ public:
static constexpr bool HAS_FLUSH_INVALIDATION = true; static constexpr bool HAS_FLUSH_INVALIDATION = true;
size_t GetID() const { inline size_t GetID() const noexcept {
return unique_identifier; return unique_identifier;
} }
@@ -66,16 +66,15 @@ public:
[[nodiscard]] const u8* GetPointer(GPUVAddr addr) const; [[nodiscard]] const u8* GetPointer(GPUVAddr addr) const;
template <typename T> template <typename T>
[[nodiscard]] T* GetPointer(GPUVAddr addr) { [[nodiscard]] inline T* GetPointer(GPUVAddr addr) noexcept {
const auto address{GpuToCpuAddress(addr)}; const auto address = GpuToCpuAddress(addr);
if (!address) { if (!address)
return {}; return {};
}
return memory.GetPointer<T>(*address); return memory.GetPointer<T>(*address);
} }
template <typename T> template <typename T>
[[nodiscard]] const T* GetPointer(GPUVAddr addr) const { [[nodiscard]] inline const T* GetPointer(GPUVAddr addr) const noexcept {
return GetPointer<T*>(addr); return GetPointer<T*>(addr);
} }
@@ -85,12 +84,9 @@ public:
* in the Host Memory counterpart. Note: This functions cause Host GPU Memory * in the Host Memory counterpart. Note: This functions cause Host GPU Memory
* Flushes and Invalidations, respectively to each operation. * Flushes and Invalidations, respectively to each operation.
*/ */
void ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, void ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, VideoCommon::CacheType which = VideoCommon::CacheType::All) const;
VideoCommon::CacheType which = VideoCommon::CacheType::All) const; void WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, VideoCommon::CacheType which = VideoCommon::CacheType::All);
void WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, void CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size, VideoCommon::CacheType which = VideoCommon::CacheType::All);
VideoCommon::CacheType which = VideoCommon::CacheType::All);
void CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size,
VideoCommon::CacheType which = VideoCommon::CacheType::All);
/** /**
* ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and * ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and
@@ -160,21 +156,14 @@ public:
u8* GetSpan(const GPUVAddr src_addr, const std::size_t size); u8* GetSpan(const GPUVAddr src_addr, const std::size_t size);
private: private:
template <bool is_big_pages, typename FuncMapped, typename FuncReserved, typename FuncUnmapped> template <typename FuncMapped, typename FuncReserved, typename FuncUnmapped>
inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, FuncMapped&& func_mapped, inline void MemoryOperation(GPUVAddr gpu_src_addr, std::size_t size, bool is_big_page, FuncMapped&& func_mapped, FuncReserved&& func_reserved, FuncUnmapped&& func_unmapped) const;
FuncReserved&& func_reserved, FuncUnmapped&& func_unmapped) const;
template <bool is_safe> void ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, VideoCommon::CacheType which, bool unsafe) const;
void ReadBlockImpl(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size, void WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, VideoCommon::CacheType which, bool unsafe);
VideoCommon::CacheType which) const;
template <bool is_safe> [[nodiscard]] std::size_t PageEntryIndex(GPUVAddr gpu_addr, bool is_big_page) const {
void WriteBlockImpl(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size, if (is_big_page) {
VideoCommon::CacheType which);
template <bool is_big_page>
[[nodiscard]] std::size_t PageEntryIndex(GPUVAddr gpu_addr) const {
if constexpr (is_big_page) {
return (gpu_addr >> big_page_bits) & big_page_table_mask; return (gpu_addr >> big_page_bits) & big_page_table_mask;
} else { } else {
return (gpu_addr >> page_bits) & page_table_mask; return (gpu_addr >> page_bits) & page_table_mask;
@@ -187,9 +176,7 @@ private:
template <bool is_gpu_address> template <bool is_gpu_address>
void GetSubmappedRangeImpl( void GetSubmappedRangeImpl(
GPUVAddr gpu_addr, std::size_t size, GPUVAddr gpu_addr, std::size_t size,
boost::container::small_vector< boost::container::small_vector<std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>, 32>& result) const;
std::pair<std::conditional_t<is_gpu_address, GPUVAddr, DAddr>, std::size_t>, 32>&
result) const;
Core::System& system; Core::System& system;
MaxwellDeviceMemoryManager& memory; MaxwellDeviceMemoryManager& memory;
@@ -219,19 +206,11 @@ private:
std::vector<u64> entries; std::vector<u64> entries;
std::vector<u64> big_entries; std::vector<u64> big_entries;
template <EntryType entry_type> GPUVAddr PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, PTEKind kind, EntryType entry_type);
GPUVAddr PageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, GPUVAddr BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, PTEKind kind, EntryType entry_type);
PTEKind kind);
template <EntryType entry_type> inline EntryType GetEntry(size_t position, bool is_big_page) const;
GPUVAddr BigPageTableOp(GPUVAddr gpu_addr, [[maybe_unused]] DAddr dev_addr, size_t size, inline void SetEntry(size_t position, EntryType entry, bool is_big_page);
PTEKind kind);
template <bool is_big_page>
inline EntryType GetEntry(size_t position) const;
template <bool is_big_page>
inline void SetEntry(size_t position, EntryType entry);
Common::MultiLevelPageTable<u32> page_table; Common::MultiLevelPageTable<u32> page_table;
Common::RangeMap<GPUVAddr, PTEKind> kind_map; Common::RangeMap<GPUVAddr, PTEKind> kind_map;
@@ -485,6 +485,7 @@ void RasterizerOpenGL::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType
texture_cache.DownloadMemory(addr, size); texture_cache.DownloadMemory(addr, size);
} }
if ((True(which & VideoCommon::CacheType::BufferCache))) { if ((True(which & VideoCommon::CacheType::BufferCache))) {
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.DownloadMemory(addr, size); buffer_cache.DownloadMemory(addr, size);
} }
if ((True(which & VideoCommon::CacheType::QueryCache))) { if ((True(which & VideoCommon::CacheType::QueryCache))) {
+58 -140
View File
@@ -545,10 +545,6 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view)
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) { void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
const VkRenderPass render_pass = framebuffer->RenderPass(); const VkRenderPass render_pass = framebuffer->RenderPass();
if (!render_pass) {
framebuffer->BeginRendering(cmdbuf);
return;
}
const VkFramebuffer framebuffer_handle = framebuffer->Handle(); const VkFramebuffer framebuffer_handle = framebuffer->Handle();
const VkExtent2D render_area = framebuffer->RenderArea(); const VkExtent2D render_area = framebuffer->RenderArea();
const VkRenderPassBeginInfo renderpass_bi{ const VkRenderPassBeginInfo renderpass_bi{
@@ -565,31 +561,6 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer)
}; };
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
} }
void EndRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
if (framebuffer->RenderPass()) {
cmdbuf.EndRenderPass();
} else {
cmdbuf.EndRendering();
}
}
[[nodiscard]] VkPipelineRenderingCreateInfo MakePipelineRenderingCreateInfo(
const Framebuffer* framebuffer) {
return VkPipelineRenderingCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
.pNext = nullptr,
.viewMask = 0,
.colorAttachmentCount = framebuffer->NumColorAttachments(),
.pColorAttachmentFormats = framebuffer->ColorAttachmentFormats().data(),
.depthAttachmentFormat = framebuffer->HasAspectDepthBit()
? framebuffer->DepthAttachmentFormat()
: VK_FORMAT_UNDEFINED,
.stencilAttachmentFormat = framebuffer->HasAspectStencilBit()
? framebuffer->DepthAttachmentFormat()
: VK_FORMAT_UNDEFINED,
};
}
} // Anonymous namespace } // Anonymous namespace
BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_, BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
@@ -652,12 +623,10 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
const BlitImagePipelineKey key{ const BlitImagePipelineKey key{
.renderpass = dst_framebuffer->RenderPass(), .renderpass = dst_framebuffer->RenderPass(),
.operation = operation, .operation = operation,
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
}; };
const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkPipelineLayout layout = *one_texture_pipeline_layout;
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler; const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key, dst_framebuffer); const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
RecordShaderReadBarrier(scheduler, src_image_view); RecordShaderReadBarrier(scheduler, src_image_view);
@@ -682,11 +651,9 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
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,
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
}; };
const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkPipelineLayout layout = *one_texture_pipeline_layout;
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key, dst_framebuffer); const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region, scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) { src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
@@ -699,7 +666,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
nullptr); nullptr);
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size); BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
cmdbuf.Draw(3, 1, 0, 0); cmdbuf.Draw(3, 1, 0, 0);
EndRenderPass(cmdbuf, dst_framebuffer); cmdbuf.EndRenderPass();
}); });
} }
@@ -709,12 +676,10 @@ void BlitImageHelper::BlitColorMSAA(const Framebuffer* dst_framebuffer,
const BlitMSAAPipelineKey key{ const BlitMSAAPipelineKey key{
.renderpass = dst_framebuffer->RenderPass(), .renderpass = dst_framebuffer->RenderPass(),
.samples = dst_framebuffer->Samples(), .samples = dst_framebuffer->Samples(),
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
}; };
const VkPipelineLayout layout = *one_texture_pipeline_layout; const VkPipelineLayout layout = *one_texture_pipeline_layout;
const VkSampler sampler = *nearest_sampler; const VkSampler sampler = *nearest_sampler;
const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key, dst_framebuffer); const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key);
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
RecordShaderReadBarrier(scheduler, src_image_view); RecordShaderReadBarrier(scheduler, src_image_view);
@@ -738,7 +703,7 @@ void BlitImageHelper::ResolveDepthStencil(const Framebuffer* dst_framebuffer,
const bool resolve_stencil = const bool resolve_stencil =
dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported(); dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported();
const VkPipeline pipeline = const VkPipeline pipeline =
FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer, resolve_stencil); FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer->RenderPass(), resolve_stencil);
const VkPipelineLayout layout = const VkPipelineLayout layout =
resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout; resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout;
const VkSampler sampler = *nearest_sampler; const VkSampler sampler = *nearest_sampler;
@@ -782,12 +747,10 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
const BlitImagePipelineKey key{ const BlitImagePipelineKey key{
.renderpass = dst_framebuffer->RenderPass(), .renderpass = dst_framebuffer->RenderPass(),
.operation = operation, .operation = operation,
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
}; };
const VkPipelineLayout layout = *two_textures_pipeline_layout; const VkPipelineLayout layout = *two_textures_pipeline_layout;
const VkSampler sampler = *nearest_sampler; const VkSampler sampler = *nearest_sampler;
const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key, dst_framebuffer); const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
const VkImageView src_depth_view = src_image_view.DepthView(); const VkImageView src_depth_view = src_image_view.DepthView();
const VkImageView src_stencil_view = src_image_view.StencilView(); const VkImageView src_stencil_view = src_image_view.StencilView();
@@ -809,25 +772,25 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) { const ImageView& src_image_view) {
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer); ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view); Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) { const ImageView& src_image_view) {
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer); ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view); Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) { const ImageView& src_image_view) {
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer); ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view); Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) { const ImageView& src_image_view) {
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer); ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view); Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
} }
@@ -838,35 +801,35 @@ void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping"); LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping");
return; return;
} }
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer, ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
convert_abgr8_to_d24s8_frag); convert_abgr8_to_d24s8_frag);
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view); Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer,
const ImageView& src_image_view) { const ImageView& src_image_view) {
ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer, ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer->RenderPass(),
convert_abgr8_to_d32f_frag); convert_abgr8_to_d32f_frag);
Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view); Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view) { ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer, ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
convert_d32f_to_abgr8_frag); convert_d32f_to_abgr8_frag);
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view); ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view) { ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer, ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
convert_d24s8_to_abgr8_frag); convert_d24s8_to_abgr8_frag);
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view); ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
} }
void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer, void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
ImageView& src_image_view) { ImageView& src_image_view) {
ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer, ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
convert_s8d24_to_abgr8_frag); convert_s8d24_to_abgr8_frag);
ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view); ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
} }
@@ -877,10 +840,8 @@ void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_ma
const BlitImagePipelineKey key{ const BlitImagePipelineKey key{
.renderpass = dst_framebuffer->RenderPass(), .renderpass = dst_framebuffer->RenderPass(),
.operation = Tegra::Engines::Fermi2D::Operation::BlendPremult, .operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
}; };
const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key, dst_framebuffer); const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key);
const VkPipelineLayout layout = *clear_color_pipeline_layout; const VkPipelineLayout layout = *clear_color_pipeline_layout;
scheduler.RequestRenderpass(dst_framebuffer); scheduler.RequestRenderpass(dst_framebuffer);
scheduler.Record( scheduler.Record(
@@ -906,10 +867,8 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
.stencil_mask = stencil_mask, .stencil_mask = stencil_mask,
.stencil_compare_mask = stencil_compare_mask, .stencil_compare_mask = stencil_compare_mask,
.stencil_ref = stencil_ref, .stencil_ref = stencil_ref,
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
}; };
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key, dst_framebuffer); const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key);
const VkPipelineLayout layout = *clear_color_pipeline_layout; const VkPipelineLayout layout = *clear_color_pipeline_layout;
scheduler.RequestRenderpass(dst_framebuffer); scheduler.RequestRenderpass(dst_framebuffer);
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) { scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
@@ -1181,14 +1140,12 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer
scheduler.InvalidateState(); scheduler.InvalidateState();
} }
VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key, VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
const Framebuffer* framebuffer) {
const auto it = std::ranges::find(blit_color_keys, key); const auto it = std::ranges::find(blit_color_keys, key);
if (it != blit_color_keys.end()) { if (it != blit_color_keys.end()) {
return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)]; return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
} }
blit_color_keys.push_back(key); blit_color_keys.push_back(key);
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag); const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
const VkPipelineColorBlendAttachmentState blend_attachment{ const VkPipelineColorBlendAttachmentState blend_attachment{
@@ -1216,7 +1173,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = key.renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1238,19 +1195,17 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
return *blit_color_pipelines.back(); return *blit_color_pipelines.back();
} }
VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key, VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key) {
const Framebuffer* framebuffer) {
const auto it = std::ranges::find(blit_depth_stencil_keys, key); const auto it = std::ranges::find(blit_depth_stencil_keys, key);
if (it != blit_depth_stencil_keys.end()) { if (it != blit_depth_stencil_keys.end()) {
return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)]; return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
} }
blit_depth_stencil_keys.push_back(key); blit_depth_stencil_keys.push_back(key);
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag); const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = key.renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1272,46 +1227,38 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
return *blit_depth_stencil_pipelines.back(); return *blit_depth_stencil_pipelines.back();
} }
VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key, VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key) {
const Framebuffer* framebuffer) {
const auto it = std::ranges::find(clear_color_keys, key); const auto it = std::ranges::find(clear_color_keys, key);
if (it != clear_color_keys.end()) { if (it != clear_color_keys.end()) {
return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)]; return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
} }
clear_color_keys.push_back(key); clear_color_keys.push_back(key);
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag); const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
const u32 num_color = framebuffer->NumColorAttachments(); const VkPipelineColorBlendAttachmentState color_blend_attachment_state{
constexpr VkColorComponentFlags full_write_mask = .blendEnable = VK_TRUE,
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | .srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
VK_COLOR_COMPONENT_A_BIT; .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
std::array<VkPipelineColorBlendAttachmentState, VideoCommon::NUM_RT> blend_attachments{}; .colorBlendOp = VK_BLEND_OP_ADD,
for (u32 index = 0; index < num_color; ++index) { .srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
blend_attachments[index] = VkPipelineColorBlendAttachmentState{ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
.blendEnable = index == 0 ? VK_TRUE : VK_FALSE, .alphaBlendOp = VK_BLEND_OP_ADD,
.srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR, .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.colorBlendOp = VK_BLEND_OP_ADD, };
.srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = index == 0 ? full_write_mask : VkColorComponentFlags{0},
};
}
const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{ const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.logicOpEnable = VK_FALSE, .logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_CLEAR, .logicOp = VK_LOGIC_OP_CLEAR,
.attachmentCount = num_color, .attachmentCount = 1,
.pAttachments = blend_attachments.data(), .pAttachments = &color_blend_attachment_state,
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
}; };
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = key.renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1334,26 +1281,13 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel
} }
VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer) { const BlitDepthStencilPipelineKey& key) {
const auto it = std::ranges::find(clear_stencil_keys, key); const auto it = std::ranges::find(clear_stencil_keys, key);
if (it != clear_stencil_keys.end()) { if (it != clear_stencil_keys.end()) {
return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)]; return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)];
} }
clear_stencil_keys.push_back(key); clear_stencil_keys.push_back(key);
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag); const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
const u32 num_color = framebuffer->NumColorAttachments();
std::array<VkPipelineColorBlendAttachmentState, VideoCommon::NUM_RT> blend_attachments{};
const VkPipelineColorBlendStateCreateInfo color_blend_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_CLEAR,
.attachmentCount = num_color,
.pAttachments = blend_attachments.data(),
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
};
const auto stencil = VkStencilOpState{ const auto stencil = VkStencilOpState{
.failOp = VK_STENCIL_OP_KEEP, .failOp = VK_STENCIL_OP_KEEP,
.passOp = VK_STENCIL_OP_REPLACE, .passOp = VK_STENCIL_OP_REPLACE,
@@ -1380,7 +1314,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = key.renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1391,7 +1325,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pDepthStencilState = &depth_stencil_ci, .pDepthStencilState = &depth_stencil_ci,
.pColorBlendState = &color_blend_ci, .pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO, .pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.layout = *clear_color_pipeline_layout, .layout = *clear_color_pipeline_layout,
.renderPass = key.renderpass, .renderPass = key.renderpass,
@@ -1402,14 +1336,12 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
return *clear_stencil_pipelines.back(); return *clear_stencil_pipelines.back();
} }
VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key, VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key) {
const Framebuffer* framebuffer) {
const auto it = std::ranges::find(blit_msaa_color_keys, key); const auto it = std::ranges::find(blit_msaa_color_keys, key);
if (it != blit_msaa_color_keys.end()) { if (it != blit_msaa_color_keys.end()) {
return *blit_msaa_color_pipelines[std::distance(blit_msaa_color_keys.begin(), it)]; return *blit_msaa_color_pipelines[std::distance(blit_msaa_color_keys.begin(), it)];
} }
blit_msaa_color_keys.push_back(key); blit_msaa_color_keys.push_back(key);
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = MakeStages(*full_screen_vert, *blit_color_msaa_frag); const std::array stages = MakeStages(*full_screen_vert, *blit_color_msaa_frag);
const VkPipelineMultisampleStateCreateInfo multisample_ci{ const VkPipelineMultisampleStateCreateInfo multisample_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
@@ -1425,7 +1357,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
blit_msaa_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ blit_msaa_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = key.renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1447,28 +1379,22 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip
return *blit_msaa_color_pipelines.back(); return *blit_msaa_color_pipelines.back();
} }
VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline( VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass,
const Framebuffer* framebuffer, bool resolve_stencil) { bool resolve_stencil) {
const VkRenderPass renderpass = framebuffer->RenderPass();
const ResolveDepthStencilPipelineKey key{
.renderpass = renderpass,
.depth_format = framebuffer->DepthAttachmentFormat(),
};
auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys; auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys;
auto& pipelines = resolve_stencil ? resolve_depth_stencil_pipelines : resolve_depth_pipelines; auto& pipelines = resolve_stencil ? resolve_depth_stencil_pipelines : resolve_depth_pipelines;
const auto it = std::ranges::find(keys, key); const auto it = std::ranges::find(keys, renderpass);
if (it != keys.end()) { if (it != keys.end()) {
return *pipelines[std::distance(keys.begin(), it)]; return *pipelines[std::distance(keys.begin(), it)];
} }
keys.push_back(key); keys.push_back(renderpass);
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = const std::array stages =
MakeStages(*full_screen_vert, MakeStages(*full_screen_vert,
resolve_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_frag); resolve_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_frag);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({ pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1536,29 +1462,25 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipeline
return *msaa_copy_pipelines.back(); return *msaa_copy_pipelines.back();
} }
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
const Framebuffer* framebuffer) { ConvertPipeline(pipeline, renderpass, false);
ConvertPipeline(pipeline, framebuffer, false);
} }
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
const Framebuffer* framebuffer) { ConvertPipeline(pipeline, renderpass, true);
ConvertPipeline(pipeline, framebuffer, true);
} }
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer, void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
vk::ShaderModule& module, bool single_texture, vk::ShaderModule& module, bool single_texture,
bool is_target_depth) { bool is_target_depth) {
if (pipeline) { if (pipeline) {
return; return;
} }
const VkRenderPass renderpass = framebuffer->RenderPass();
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
const std::array stages = MakeStages(*full_screen_vert, *module); const std::array stages = MakeStages(*full_screen_vert, *module);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
@@ -1580,32 +1502,28 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffe
}); });
} }
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
const Framebuffer* framebuffer,
vk::ShaderModule& module) { vk::ShaderModule& module) {
ConvertPipelineEx(pipeline, framebuffer, module, false, false); ConvertPipelineEx(pipeline, renderpass, module, false, false);
} }
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
const Framebuffer* framebuffer,
vk::ShaderModule& module) { vk::ShaderModule& module) {
ConvertPipelineEx(pipeline, framebuffer, module, true, true); ConvertPipelineEx(pipeline, renderpass, module, true, true);
} }
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer, void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
bool is_target_depth) { bool is_target_depth) {
if (pipeline) { if (pipeline) {
return; return;
} }
const VkRenderPass renderpass = framebuffer->RenderPass();
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
VkShaderModule frag_shader = VkShaderModule frag_shader =
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag; is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
const std::array stages = MakeStages(*full_screen_vert, frag_shader); const std::array stages = MakeStages(*full_screen_vert, frag_shader);
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = renderpass ? nullptr : &rendering_ci, .pNext = nullptr,
.flags = 0, .flags = 0,
.stageCount = static_cast<u32>(stages.size()), .stageCount = static_cast<u32>(stages.size()),
.pStages = stages.data(), .pStages = stages.data(),
+14 -32
View File
@@ -33,8 +33,6 @@ struct BlitImagePipelineKey {
VkRenderPass renderpass; VkRenderPass renderpass;
Tegra::Engines::Fermi2D::Operation operation; Tegra::Engines::Fermi2D::Operation operation;
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
VkFormat depth_format;
}; };
struct BlitDepthStencilPipelineKey { struct BlitDepthStencilPipelineKey {
@@ -45,8 +43,6 @@ struct BlitDepthStencilPipelineKey {
u8 stencil_mask; u8 stencil_mask;
u32 stencil_compare_mask; u32 stencil_compare_mask;
u32 stencil_ref; u32 stencil_ref;
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
VkFormat depth_format;
}; };
struct MSAACopyPipelineKey { struct MSAACopyPipelineKey {
@@ -62,15 +58,6 @@ struct BlitMSAAPipelineKey {
VkRenderPass renderpass; VkRenderPass renderpass;
VkSampleCountFlagBits samples; VkSampleCountFlagBits samples;
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
VkFormat depth_format;
};
struct ResolveDepthStencilPipelineKey {
constexpr auto operator<=>(const ResolveDepthStencilPipelineKey&) const noexcept = default;
VkRenderPass renderpass;
VkFormat depth_format;
}; };
class BlitImageHelper { class BlitImageHelper {
@@ -136,36 +123,31 @@ private:
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer, void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view); ImageView& src_image_view);
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key, [[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
const Framebuffer* framebuffer);
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key, [[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
const Framebuffer* framebuffer);
[[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key, [[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key);
const Framebuffer* framebuffer);
[[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline( [[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline(
const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer); const BlitDepthStencilPipelineKey& key);
[[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key); [[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key);
[[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key, [[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key);
const Framebuffer* framebuffer); [[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(VkRenderPass renderpass,
[[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(const Framebuffer* framebuffer,
bool resolve_stencil); bool resolve_stencil);
void ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer, void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
bool is_target_depth);
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer); void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer); void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
void ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer, void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
vk::ShaderModule& module, bool single_texture, bool is_target_depth); vk::ShaderModule& module, bool single_texture, bool is_target_depth);
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer, void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
vk::ShaderModule& module); vk::ShaderModule& module);
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer, void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
vk::ShaderModule& module); vk::ShaderModule& module);
const Device& device; const Device& device;
@@ -213,9 +195,9 @@ private:
std::vector<vk::Pipeline> msaa_copy_pipelines; std::vector<vk::Pipeline> msaa_copy_pipelines;
std::vector<BlitMSAAPipelineKey> blit_msaa_color_keys; std::vector<BlitMSAAPipelineKey> blit_msaa_color_keys;
std::vector<vk::Pipeline> blit_msaa_color_pipelines; std::vector<vk::Pipeline> blit_msaa_color_pipelines;
std::vector<ResolveDepthStencilPipelineKey> resolve_depth_keys; std::vector<VkRenderPass> resolve_depth_keys;
std::vector<vk::Pipeline> resolve_depth_pipelines; std::vector<vk::Pipeline> resolve_depth_pipelines;
std::vector<ResolveDepthStencilPipelineKey> resolve_depth_stencil_keys; std::vector<VkRenderPass> resolve_depth_stencil_keys;
std::vector<vk::Pipeline> resolve_depth_stencil_pipelines; std::vector<vk::Pipeline> resolve_depth_stencil_pipelines;
struct MSAACopyResources { struct MSAACopyResources {
u64 tick; u64 tick;
@@ -1,13 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstddef> #include <cstddef>
#include "video_core/renderer_vulkan/vk_command_pool.h" #include "video_core/renderer_vulkan/vk_command_pool.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -18,52 +14,32 @@ constexpr size_t COMMAND_BUFFER_POOL_SIZE = 4;
struct CommandPool::Pool { struct CommandPool::Pool {
vk::CommandPool handle; vk::CommandPool handle;
vk::CommandBuffers cmdbufs; vk::CommandBuffers cmdbufs;
u64 tick;
}; };
CommandPool::CommandPool(MasterSemaphore& master_semaphore_, const Device& device_) CommandPool::CommandPool(MasterSemaphore& master_semaphore_, const Device& device_)
: master_semaphore{master_semaphore_}, device{device_} {} : ResourcePool(master_semaphore_, COMMAND_BUFFER_POOL_SIZE), device{device_} {}
CommandPool::~CommandPool() = default; CommandPool::~CommandPool() = default;
void CommandPool::AllocatePool() { void CommandPool::Allocate(size_t begin, size_t end) {
// Command buffers are going to be committed, recorded, executed every single usage cycle.
// They are also going to be reset when committed.
Pool& pool = pools.emplace_back(); Pool& pool = pools.emplace_back();
pool.handle = device.GetLogical().CreateCommandPool({ pool.handle = device.GetLogical().CreateCommandPool({
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, .flags =
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
.queueFamilyIndex = device.GetGraphicsFamily(), .queueFamilyIndex = device.GetGraphicsFamily(),
}); });
pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE); pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE);
pool.tick = 0;
}
void CommandPool::AcquirePool() {
if (!pools.empty()) {
master_semaphore.Refresh();
const u64 gpu_tick = master_semaphore.KnownGpuTick();
for (size_t i = 0; i < pools.size(); ++i) {
const size_t candidate = (current_pool + 1 + i) % pools.size();
if (gpu_tick >= pools[candidate].tick) {
current_pool = candidate;
current_index = 0;
pools[current_pool].handle.Reset();
return;
}
}
}
AllocatePool();
current_pool = pools.size() - 1;
current_index = 0;
} }
VkCommandBuffer CommandPool::Commit() { VkCommandBuffer CommandPool::Commit() {
if (pools.empty() || current_index >= COMMAND_BUFFER_POOL_SIZE) { const size_t index = CommitResource();
AcquirePool(); const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE;
} const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE;
Pool& pool = pools[current_pool]; return pools[pool_index].cmdbufs[sub_index];
pool.tick = master_semaphore.CurrentTick();
return pool.cmdbufs[current_index++];
} }
} // namespace Vulkan } // namespace Vulkan
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -9,7 +6,7 @@
#include <cstddef> #include <cstddef>
#include <vector> #include <vector>
#include "common/common_types.h" #include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan { namespace Vulkan {
@@ -17,24 +14,20 @@ namespace Vulkan {
class Device; class Device;
class MasterSemaphore; class MasterSemaphore;
class CommandPool final { class CommandPool final : public ResourcePool {
public: public:
explicit CommandPool(MasterSemaphore& master_semaphore_, const Device& device_); explicit CommandPool(MasterSemaphore& master_semaphore_, const Device& device_);
~CommandPool(); ~CommandPool() override;
void Allocate(size_t begin, size_t end) override;
VkCommandBuffer Commit(); VkCommandBuffer Commit();
private: private:
struct Pool; struct Pool;
void AllocatePool();
void AcquirePool();
MasterSemaphore& master_semaphore;
const Device& device; const Device& device;
std::vector<Pool> pools; std::vector<Pool> pools;
size_t current_pool = 0;
size_t current_index = 0;
}; };
} // namespace Vulkan } // namespace Vulkan
@@ -290,10 +290,7 @@ GraphicsPipeline::GraphicsPipeline(
descriptor_update_template = descriptor_update_template =
builder.CreateTemplate(set_layout, *pipeline_layout, uses_push_descriptor); builder.CreateTemplate(set_layout, *pipeline_layout, uses_push_descriptor);
VkRenderPass render_pass{}; const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state, device))};
if (!device.IsKhrDynamicRenderingSupported()) {
render_pass = render_pass_cache.Get(MakeRenderPassKey(key.state, device));
}
Validate(); Validate();
try { try {
MakePipeline(render_pass); MakePipeline(render_pass);
@@ -999,47 +996,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
} }
const RenderPassKey renderpass_key{MakeRenderPassKey(key.state, device)};
std::array<VkFormat, Maxwell::NumRenderTargets> color_attachment_formats{};
for (size_t index = 0; index < renderpass_key.color_formats.size(); ++index) {
const PixelFormat pixel_format{renderpass_key.color_formats[index]};
if (pixel_format == PixelFormat::Invalid) {
color_attachment_formats[index] = VK_FORMAT_UNDEFINED;
continue;
}
color_attachment_formats[index] =
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, pixel_format).format;
}
VkFormat depth_attachment_format{VK_FORMAT_UNDEFINED};
VkFormat stencil_attachment_format{VK_FORMAT_UNDEFINED};
if (renderpass_key.depth_format != PixelFormat::Invalid) {
const VkFormat format{
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true,
renderpass_key.depth_format)
.format};
const auto surface_type{VideoCore::Surface::GetFormatType(renderpass_key.depth_format)};
if (surface_type == VideoCore::Surface::SurfaceType::Depth ||
surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
depth_attachment_format = format;
}
if (surface_type == VideoCore::Surface::SurfaceType::Stencil ||
surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
stencil_attachment_format = format;
}
}
const VkPipelineRenderingCreateInfo rendering_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
.pNext = nullptr,
.viewMask = 0,
.colorAttachmentCount = static_cast<u32>(NumAttachments(key.state)),
.pColorAttachmentFormats = color_attachment_formats.data(),
.depthAttachmentFormat = depth_attachment_format,
.stencilAttachmentFormat = stencil_attachment_format,
};
pipeline = device.GetLogical().CreateGraphicsPipeline({ pipeline = device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = device.IsKhrDynamicRenderingSupported() ? &rendering_ci : nullptr, .pNext = nullptr,
.flags = flags, .flags = flags,
.stageCount = static_cast<u32>(shader_stages.size()), .stageCount = static_cast<u32>(shader_stages.size()),
.pStages = shader_stages.data(), .pStages = shader_stages.data(),
@@ -305,8 +305,12 @@ size_t GetTotalPipelineWorkers() {
std::max<size_t>(static_cast<size_t>(std::thread::hardware_concurrency()), 2ULL) - 1ULL; std::max<size_t>(static_cast<size_t>(std::thread::hardware_concurrency()), 2ULL) - 1ULL;
#ifdef __ANDROID__ #ifdef __ANDROID__
const int configured = AndroidSettings::values.pipeline_worker_count.GetValue(); const int configured = AndroidSettings::values.pipeline_worker_count.GetValue();
const size_t desired = static_cast<size_t>(std::max(configured, 1)); const int clamped = std::clamp(configured, 4, 8);
return std::min<size_t>(max_core_threads, desired); const size_t desired = static_cast<size_t>(clamped);
if (desired == 0) {
return 1ULL;
}
return std::min(max_core_threads, desired);
#else #else
return max_core_threads; return max_core_threads;
#endif #endif
@@ -241,13 +241,11 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
if (!pipeline) { if (!pipeline) {
return; return;
} }
{ std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; // update engine as channel may be different.
pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->SetEngine(maxwell3d, gpu_memory);
if (!pipeline->Configure(is_indexed)) { if (!pipeline->Configure(is_indexed))
return; return;
}
}
UpdateDynamicStates(); UpdateDynamicStates();
@@ -675,6 +673,7 @@ void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType
texture_cache.DownloadMemory(addr, size); texture_cache.DownloadMemory(addr, size);
} }
if ((True(which & VideoCommon::CacheType::BufferCache))) { if ((True(which & VideoCommon::CacheType::BufferCache))) {
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.DownloadMemory(addr, size); buffer_cache.DownloadMemory(addr, size);
} }
if ((True(which & VideoCommon::CacheType::QueryCache))) { if ((True(which & VideoCommon::CacheType::QueryCache))) {
@@ -772,15 +771,12 @@ bool RasterizerVulkan::OnCPUWrite(DAddr addr, u64 size) {
return false; return false;
} }
static constexpr bool ENABLE_TEXTURE_CACHE_INVALIDATION_SKIP = true;
void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) { void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
if (addr == 0 || size == 0) { if (addr == 0 || size == 0) {
return; return;
} }
if (!ENABLE_TEXTURE_CACHE_INVALIDATION_SKIP || {
device_memory.IsRegionTextureCached(addr, size)) {
std::scoped_lock lock{texture_cache.mutex}; std::scoped_lock lock{texture_cache.mutex};
texture_cache.WriteMemory(addr, size); texture_cache.WriteMemory(addr, size);
} }
+5 -149
View File
@@ -93,53 +93,13 @@ void Scheduler::DispatchWork() {
} }
} }
void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear) {
const VkExtent2D render_area = framebuffer->RenderArea();
std::array<VkImageView, 9> attachment_views{};
const auto& color_views = framebuffer->ColorAttachments();
for (size_t index = 0; index < color_views.size(); ++index) {
attachment_views[index] = color_views[index];
}
attachment_views[8] = framebuffer->DepthAttachment();
state.renderpass = VkRenderPass{};
state.framebuffer = VkFramebuffer{};
state.attachment_views = attachment_views;
state.color_resolve_views = framebuffer->ColorResolveAttachments();
state.color_resolve_modes = framebuffer->ColorResolveModes();
state.discards_msaa_color = framebuffer->DiscardsMsaaColor();
state.discards_msaa_depth = framebuffer->DiscardsMsaaDepth();
state.render_area = render_area;
state.num_color = framebuffer->NumColorAttachments();
state.has_depth = framebuffer->HasAspectDepthBit();
state.has_stencil = framebuffer->HasAspectStencilBit();
state.layer_count = framebuffer->NumLayers();
state.rendering = true;
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
const std::string render_pass_info =
fmt::format("renderArea={}x{}, numImages={}", render_area.width, render_area.height,
framebuffer->NumImages());
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
}
RecordDynamicBegin(clear);
num_renderpass_images = framebuffer->NumImages();
renderpass_images = framebuffer->Images();
renderpass_image_ranges = framebuffer->ImageRanges();
}
void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass, void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
const VkClearValue* clear_values, u32 clear_value_count) { const VkClearValue* clear_values, u32 clear_value_count) {
if (device.IsKhrDynamicRenderingSupported()) {
BeginDynamicRendering(framebuffer, nullptr);
return;
}
const VkExtent2D render_area = framebuffer->RenderArea();
const VkFramebuffer framebuffer_handle = framebuffer->Handle(); const VkFramebuffer framebuffer_handle = framebuffer->Handle();
const VkExtent2D render_area = framebuffer->RenderArea();
state.renderpass = renderpass; state.renderpass = renderpass;
state.framebuffer = framebuffer_handle; state.framebuffer = framebuffer_handle;
state.render_area = render_area; state.render_area = render_area;
state.rendering = true;
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) { if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
const std::string render_pass_info = const std::string render_pass_info =
@@ -181,12 +141,6 @@ void Scheduler::RealizeDeferredClear() {
const DeferredClear dc = deferred_clear; const DeferredClear dc = deferred_clear;
deferred_clear = {}; deferred_clear = {};
if (device.IsKhrDynamicRenderingSupported()) {
EndRenderPass();
BeginDynamicRendering(dc.framebuffer, &dc);
return;
}
std::array<VkClearValue, 9> clear_values{}; std::array<VkClearValue, 9> clear_values{};
u32 count = 0; u32 count = 0;
const RenderPassKey& base = dc.framebuffer->RenderPassKeyBase(); const RenderPassKey& base = dc.framebuffer->RenderPassKeyBase();
@@ -241,25 +195,9 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
RealizeDeferredClear(); RealizeDeferredClear();
return; return;
} }
const VkExtent2D render_area = framebuffer->RenderArea();
if (device.IsKhrDynamicRenderingSupported()) {
std::array<VkImageView, 9> attachment_views{};
const auto& color_views = framebuffer->ColorAttachments();
for (size_t index = 0; index < color_views.size(); ++index) {
attachment_views[index] = color_views[index];
}
attachment_views[8] = framebuffer->DepthAttachment();
if (state.rendering && attachment_views == state.attachment_views &&
render_area.width == state.render_area.width &&
render_area.height == state.render_area.height) {
return;
}
EndRenderPass();
BeginDynamicRendering(framebuffer, nullptr);
return;
}
const VkRenderPass renderpass = framebuffer->RenderPass(); const VkRenderPass renderpass = framebuffer->RenderPass();
const VkFramebuffer framebuffer_handle = framebuffer->Handle(); const VkFramebuffer framebuffer_handle = framebuffer->Handle();
const VkExtent2D render_area = framebuffer->RenderArea();
if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer && if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer &&
render_area.width == state.render_area.width && render_area.width == state.render_area.width &&
render_area.height == state.render_area.height) { render_area.height == state.render_area.height) {
@@ -434,80 +372,6 @@ void Scheduler::InvalidateState() {
state_tracker.InvalidateCommandBufferState(); state_tracker.InvalidateCommandBufferState();
} }
void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
const std::array<VkImageView, 9> views = state.attachment_views;
const std::array<VkImageView, 8> resolve_views = state.color_resolve_views;
const std::array<VkResolveModeFlagBits, 8> resolve_modes = state.color_resolve_modes;
const u32 num_color = state.num_color;
const bool has_depth = state.has_depth;
const bool has_stencil = state.has_stencil;
const u32 layers = state.layer_count;
const VkExtent2D render_area = state.render_area;
const u32 color_clear_mask = clear ? clear->color_clear_mask : 0u;
const u32 color_discard_mask =
clear != nullptr && state.discards_msaa_color ? clear->color_clear_mask : 0u;
const std::array<VkClearValue, 8> color_clear_values =
clear ? clear->color_values : std::array<VkClearValue, 8>{};
const bool ds_clear = clear != nullptr && clear->depth_stencil;
const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{};
const bool ds_discard = state.discards_msaa_depth;
Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers,
render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear,
ds_clear_value, ds_discard](vk::CommandBuffer cmdbuf) {
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
for (u32 index = 0; index < num_color; ++index) {
const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0;
const VkImageView resolve_view = resolve_views[index];
const bool has_resolve = resolve_view != VK_NULL_HANDLE;
const bool discard_slot = has_resolve && ((color_discard_mask >> index) & 1u) != 0;
color_infos[index] = VkRenderingAttachmentInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = views[index],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = has_resolve ? resolve_modes[index] : VK_RESOLVE_MODE_NONE,
.resolveImageView = resolve_view,
.resolveImageLayout =
has_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = clear_slot ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = discard_slot ? VK_ATTACHMENT_STORE_OP_DONT_CARE
: VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = clear_slot ? color_clear_values[index] : VkClearValue{},
};
}
const VkRenderingAttachmentInfo depth_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = views[8],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = VK_RESOLVE_MODE_NONE,
.resolveImageView = VK_NULL_HANDLE,
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE
: VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
};
const VkRenderingInfo rendering_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.pNext = nullptr,
.flags = 0,
.renderArea =
{
.offset = {.x = 0, .y = 0},
.extent = render_area,
},
.layerCount = layers,
.viewMask = 0,
.colorAttachmentCount = num_color,
.pColorAttachments = color_infos.data(),
.pDepthAttachment = has_depth ? &depth_info : nullptr,
.pStencilAttachment = has_stencil ? &depth_info : nullptr,
};
cmdbuf.BeginRendering(rendering_info);
});
}
void Scheduler::EndPendingOperations() { void Scheduler::EndPendingOperations() {
query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64); query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64);
EndRenderPass(); EndRenderPass();
@@ -516,7 +380,7 @@ void Scheduler::EndPendingOperations() {
void Scheduler::EndRenderPass() void Scheduler::EndRenderPass()
{ {
RealizeDeferredClear(); RealizeDeferredClear();
if (!state.rendering) { if (!state.renderpass) {
return; return;
} }
@@ -534,8 +398,7 @@ void Scheduler::EndRenderPass()
Record([num_images = num_renderpass_images, Record([num_images = num_renderpass_images,
images = renderpass_images, images = renderpass_images,
ranges = renderpass_image_ranges, ranges = renderpass_image_ranges,
has_transform_feedback = device.IsExtTransformFeedbackSupported(), has_transform_feedback = device.IsExtTransformFeedbackSupported()](
dynamic_rendering = device.IsKhrDynamicRenderingSupported()](
vk::CommandBuffer cmdbuf) { vk::CommandBuffer cmdbuf) {
std::array<VkImageMemoryBarrier, 9> barriers; std::array<VkImageMemoryBarrier, 9> barriers;
for (size_t i = 0; i < num_images; ++i) { for (size_t i = 0; i < num_images; ++i) {
@@ -572,11 +435,7 @@ void Scheduler::EndRenderPass()
.subresourceRange = range, .subresourceRange = range,
}; };
} }
if (dynamic_rendering) { cmdbuf.EndRenderPass();
cmdbuf.EndRendering();
} else {
cmdbuf.EndRenderPass();
}
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
0, nullptr, nullptr, vk::Span(barriers.data(), num_images)); 0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
@@ -594,9 +453,6 @@ void Scheduler::EndRenderPass()
}); });
state.renderpass = VkRenderPass{}; state.renderpass = VkRenderPass{};
state.framebuffer = VkFramebuffer{};
state.attachment_views = {};
state.rendering = false;
num_renderpass_images = 0; num_renderpass_images = 0;
} }
+1 -16
View File
@@ -71,7 +71,7 @@ public:
/// Returns true when a render pass is currently active in the scheduler state. /// Returns true when a render pass is currently active in the scheduler state.
bool IsRenderPassActive() const { bool IsRenderPassActive() const {
return state.rendering; return state.renderpass != VK_NULL_HANDLE;
} }
/// Update the pipeline to the current execution context. /// Update the pipeline to the current execution context.
@@ -250,18 +250,8 @@ private:
struct State { struct State {
VkRenderPass renderpass{}; VkRenderPass renderpass{};
VkFramebuffer framebuffer{}; VkFramebuffer framebuffer{};
std::array<VkImageView, 9> attachment_views{};
std::array<VkImageView, 8> color_resolve_views{};
std::array<VkResolveModeFlagBits, 8> color_resolve_modes{};
VkExtent2D render_area = {0, 0}; VkExtent2D render_area = {0, 0};
GraphicsPipeline* graphics_pipeline = nullptr; GraphicsPipeline* graphics_pipeline = nullptr;
bool rendering = false;
bool discards_msaa_color = false;
bool discards_msaa_depth = false;
u32 num_color = 0;
bool has_depth = false;
bool has_stencil = false;
u32 layer_count = 1;
bool is_rescaling = false; bool is_rescaling = false;
bool rescaling_defined = false; bool rescaling_defined = false;
bool needs_state_enable_refresh = false; bool needs_state_enable_refresh = false;
@@ -279,9 +269,6 @@ private:
void BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass, void BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
const VkClearValue* clear_values, u32 clear_value_count); const VkClearValue* clear_values, u32 clear_value_count);
/// Begins a dynamic rendering pass, optionally realizing a deferred clear via load ops.
void BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear);
/// If a deferred clear is pending. /// If a deferred clear is pending.
void RealizeDeferredClear(); void RealizeDeferredClear();
@@ -295,8 +282,6 @@ private:
void EndPendingOperations(); void EndPendingOperations();
void RecordDynamicBegin(const DeferredClear* clear);
void EndRenderPass(); void EndRenderPass();
void AcquireNewChunk(); void AcquireNewChunk();
@@ -54,7 +54,6 @@ using VideoCore::Surface::SurfaceType;
namespace { namespace {
constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true; constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true;
constexpr bool ENABLE_MSAA_COLOR_DISCARD = true; constexpr bool ENABLE_MSAA_COLOR_DISCARD = true;
constexpr bool ENABLE_MSAA_DEPTH_DISCARD = true;
constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
if (color == std::array<float, 4>{0, 0, 0, 0}) { if (color == std::array<float, 4>{0, 0, 0, 0}) {
@@ -1042,32 +1041,6 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
shadow.extent = extent; shadow.extent = extent;
shadow.layers = layers; shadow.layers = layers;
shadow.up_to_date = true; shadow.up_to_date = true;
if (device.IsKhrDynamicRenderingSupported()) {
scheduler.RecordWithUploadBuffer(
[image = *shadow.image, layers](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
const VkImageMemoryBarrier barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = layers,
},
};
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
barrier);
});
}
return *shadow.view; return *shadow.view;
} }
@@ -1380,7 +1353,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
} }
void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) { void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
if (!dst->RenderPass() && !device.IsKhrDynamicRenderingSupported()) { if (!dst->RenderPass()) {
return; return;
} }
@@ -2710,7 +2683,7 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
.height = key.size.height, .height = key.size.height,
}} { }} {
CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled); CreateFramebuffer(runtime, color_buffers, depth_buffer, key.is_rescaled);
if (runtime.device.HasDebuggingToolAttached() && framebuffer) { if (runtime.device.HasDebuggingToolAttached()) {
framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str()); framebuffer.SetObjectNameEXT(VideoCommon::Name(key).c_str());
} }
} }
@@ -2753,12 +2726,6 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
image_ranges[num_images] = MakeSubresourceRange(color_buffer); image_ranges[num_images] = MakeSubresourceRange(color_buffer);
rt_map[index] = num_images; rt_map[index] = num_images;
samples = color_buffer->Samples(); samples = color_buffer->Samples();
color_attachments[index] = color_buffer->RenderTarget();
color_attachment_formats[index] =
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true,
color_buffer->format)
.format;
num_color_attachments = static_cast<u32>(index + 1);
++num_images; ++num_images;
} }
const size_t num_colors = attachments.size(); const size_t num_colors = attachments.size();
@@ -2774,11 +2741,6 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
const VkImageSubresourceRange subresource_range = MakeSubresourceRange(depth_buffer); const VkImageSubresourceRange subresource_range = MakeSubresourceRange(depth_buffer);
image_ranges[num_images] = subresource_range; image_ranges[num_images] = subresource_range;
samples = depth_buffer->Samples(); samples = depth_buffer->Samples();
depth_attachment = depth_buffer->RenderTarget();
depth_attachment_format =
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true,
depth_buffer->format)
.format;
++num_images; ++num_images;
has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
has_stencil = (subresource_range.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; has_stencil = (subresource_range.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
@@ -2792,9 +2754,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
discard_msaa_color = discard_msaa_color =
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color; ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
discard_msaa_depth = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD &&
samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler();
renderpass = runtime.render_pass_cache.Get(renderpass_key);
render_pass_key = renderpass_key; render_pass_key = renderpass_key;
render_pass_cache = &runtime.render_pass_cache; render_pass_cache = &runtime.render_pass_cache;
render_area.width = (std::min)(render_area.width, width); render_area.width = (std::min)(render_area.width, width);
@@ -2809,15 +2770,10 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
} }
const VkFormat vk_format = const VkFormat vk_format =
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true, format).format; MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true, format).format;
color_resolve_modes[index] = VideoCore::Surface::IsPixelFormatInteger(format)
? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT
: VK_RESOLVE_MODE_AVERAGE_BIT;
if (ENABLE_MSAA_RESOLVE_CONSUME) { if (ENABLE_MSAA_RESOLVE_CONSUME) {
const VkImage msaa_image = images[rt_map[index]]; const VkImage msaa_image = images[rt_map[index]];
const VkImageView shadow_view = runtime.GetOrCreateResolveShadow( attachments.push_back(runtime.GetOrCreateResolveShadow(msaa_image, vk_format,
msaa_image, vk_format, render_area, layers); render_area, layers));
color_resolve_attachments[index] = shadow_view;
attachments.push_back(shadow_view);
continue; continue;
} }
VkImageCreateInfo resolve_ci{ VkImageCreateInfo resolve_ci{
@@ -2856,33 +2812,6 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
.layerCount = layers, .layerCount = layers,
}, },
}); });
if (runtime.device.IsKhrDynamicRenderingSupported()) {
runtime.scheduler.RecordWithUploadBuffer(
[image = *resolve_image, layers](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
const VkImageMemoryBarrier barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = layers,
},
};
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, barrier);
});
}
color_resolve_attachments[index] = *resolve_view;
attachments.push_back(*resolve_view); attachments.push_back(*resolve_view);
resolve_images.push_back(std::move(resolve_image)); resolve_images.push_back(std::move(resolve_image));
resolve_image_views.push_back(std::move(resolve_view)); resolve_image_views.push_back(std::move(resolve_view));
@@ -2890,11 +2819,6 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
} }
num_color_buffers = static_cast<u32>(num_colors); num_color_buffers = static_cast<u32>(num_colors);
layer_count = static_cast<u32>((std::max)(num_layers, 1));
if (runtime.device.IsKhrDynamicRenderingSupported()) {
return;
}
renderpass = runtime.render_pass_cache.Get(renderpass_key);
framebuffer = runtime.device.GetLogical().CreateFramebuffer({ framebuffer = runtime.device.GetLogical().CreateFramebuffer({
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@@ -2904,7 +2828,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.width = render_area.width, .width = render_area.width,
.height = render_area.height, .height = render_area.height,
.layers = layer_count, .layers = static_cast<u32>((std::max)(num_layers, 1)),
}); });
} }
@@ -2920,53 +2844,6 @@ VkRenderPass Framebuffer::RenderPassVariant(u32 color_clear_mask, bool depth_ste
return render_pass_cache->Get(key); return render_pass_cache->Get(key);
} }
void Framebuffer::BeginRendering(vk::CommandBuffer cmdbuf) const {
std::array<VkRenderingAttachmentInfo, NUM_RT> color_attachment_infos{};
for (size_t index = 0; index < num_color_attachments; ++index) {
color_attachment_infos[index] = VkRenderingAttachmentInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = color_attachments[index],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = VK_RESOLVE_MODE_NONE,
.resolveImageView = VK_NULL_HANDLE,
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = {},
};
}
const VkRenderingAttachmentInfo depth_attachment_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = depth_attachment,
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = VK_RESOLVE_MODE_NONE,
.resolveImageView = VK_NULL_HANDLE,
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = {},
};
const VkRenderingInfo rendering_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.pNext = nullptr,
.flags = 0,
.renderArea =
{
.offset = {.x = 0, .y = 0},
.extent = render_area,
},
.layerCount = layer_count,
.viewMask = 0,
.colorAttachmentCount = num_color_attachments,
.pColorAttachments = color_attachment_infos.data(),
.pDepthAttachment = has_depth ? &depth_attachment_info : nullptr,
.pStencilAttachment = has_stencil ? &depth_attachment_info : nullptr,
};
cmdbuf.BeginRendering(rendering_info);
}
void TextureCacheRuntime::AccelerateImageUpload( void TextureCacheRuntime::AccelerateImageUpload(
Image& image, const StagingBufferRef& map, Image& image, const StagingBufferRef& map,
std::span<const VideoCommon::SwizzleParameters> swizzles, std::span<const VideoCommon::SwizzleParameters> swizzles,
@@ -178,8 +178,6 @@ public:
std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer, std::span<ImageView*, NUM_RT> color_buffers, ImageView* depth_buffer,
bool is_rescaled = false); bool is_rescaled = false);
void BeginRendering(vk::CommandBuffer cmdbuf) const;
[[nodiscard]] VkFramebuffer Handle() const noexcept { [[nodiscard]] VkFramebuffer Handle() const noexcept {
return *framebuffer; return *framebuffer;
} }
@@ -195,39 +193,6 @@ public:
[[nodiscard]] VkRenderPass RenderPassVariant(u32 color_clear_mask, bool depth_stencil_clear, [[nodiscard]] VkRenderPass RenderPassVariant(u32 color_clear_mask, bool depth_stencil_clear,
u32 color_discard_mask) const; u32 color_discard_mask) const;
[[nodiscard]] u32 NumColorAttachments() const noexcept {
return num_color_attachments;
}
[[nodiscard]] const std::array<VkImageView, NUM_RT>& ColorAttachments() const noexcept {
return color_attachments;
}
[[nodiscard]] const std::array<VkFormat, NUM_RT>& ColorAttachmentFormats() const noexcept {
return color_attachment_formats;
}
[[nodiscard]] const std::array<VkImageView, NUM_RT>& ColorResolveAttachments() const noexcept {
return color_resolve_attachments;
}
[[nodiscard]] const std::array<VkResolveModeFlagBits, NUM_RT>& ColorResolveModes()
const noexcept {
return color_resolve_modes;
}
[[nodiscard]] VkImageView DepthAttachment() const noexcept {
return depth_attachment;
}
[[nodiscard]] VkFormat DepthAttachmentFormat() const noexcept {
return depth_attachment_format;
}
[[nodiscard]] u32 NumLayers() const noexcept {
return layer_count;
}
[[nodiscard]] VkExtent2D RenderArea() const noexcept { [[nodiscard]] VkExtent2D RenderArea() const noexcept {
return render_area; return render_area;
} }
@@ -280,10 +245,6 @@ public:
return discard_msaa_color; return discard_msaa_color;
} }
[[nodiscard]] bool DiscardsMsaaDepth() const noexcept {
return discard_msaa_depth;
}
private: private:
vk::Framebuffer framebuffer; vk::Framebuffer framebuffer;
VkRenderPass renderpass{}; VkRenderPass renderpass{};
@@ -294,14 +255,6 @@ private:
std::array<VkImage, 9> images{}; std::array<VkImage, 9> images{};
std::array<VkImageSubresourceRange, 9> image_ranges{}; std::array<VkImageSubresourceRange, 9> image_ranges{};
std::array<size_t, NUM_RT> rt_map{}; std::array<size_t, NUM_RT> rt_map{};
std::array<VkImageView, NUM_RT> color_attachments{};
std::array<VkFormat, NUM_RT> color_attachment_formats{};
std::array<VkImageView, NUM_RT> color_resolve_attachments{};
std::array<VkResolveModeFlagBits, NUM_RT> color_resolve_modes{};
VkImageView depth_attachment{};
VkFormat depth_attachment_format = VK_FORMAT_UNDEFINED;
u32 num_color_attachments = 0;
u32 layer_count = 1;
bool has_depth{}; bool has_depth{};
bool has_stencil{}; bool has_stencil{};
bool is_rescaled{}; bool is_rescaled{};
@@ -310,7 +263,6 @@ private:
RenderPassKey render_pass_key{}; RenderPassKey render_pass_key{};
RenderPassCache* render_pass_cache{nullptr}; RenderPassCache* render_pass_cache{nullptr};
bool discard_msaa_color{}; bool discard_msaa_color{};
bool discard_msaa_depth{};
}; };
class Image : public VideoCommon::ImageBase { class Image : public VideoCommon::ImageBase {
@@ -2308,7 +2308,6 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
if (False(image.flags & ImageFlagBits::Sparse)) { if (False(image.flags & ImageFlagBits::Sparse)) {
if (image.cpu_addr < ~(1ULL << 40)) { if (image.cpu_addr < ~(1ULL << 40)) {
device_memory.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1); device_memory.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1);
device_memory.UpdateTexturePagesCount(image.cpu_addr, image.guest_size_bytes, 1);
} }
return; return;
} }
@@ -2321,14 +2320,12 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
const DAddr cpu_addr = map.cpu_addr; const DAddr cpu_addr = map.cpu_addr;
const std::size_t size = map.size; const std::size_t size = map.size;
device_memory.UpdatePagesCachedCount(cpu_addr, size, 1); device_memory.UpdatePagesCachedCount(cpu_addr, size, 1);
device_memory.UpdateTexturePagesCount(cpu_addr, size, 1);
} }
return; return;
} }
ForEachSparseSegment(image, ForEachSparseSegment(image,
[this]([[maybe_unused]] GPUVAddr gpu_addr, DAddr cpu_addr, size_t size) { [this]([[maybe_unused]] GPUVAddr gpu_addr, DAddr cpu_addr, size_t size) {
device_memory.UpdatePagesCachedCount(cpu_addr, size, 1); device_memory.UpdatePagesCachedCount(cpu_addr, size, 1);
device_memory.UpdateTexturePagesCount(cpu_addr, size, 1);
}); });
} }
@@ -2339,7 +2336,6 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
if (False(image.flags & ImageFlagBits::Sparse)) { if (False(image.flags & ImageFlagBits::Sparse)) {
if (image.cpu_addr < ~(1ULL << 40)) { if (image.cpu_addr < ~(1ULL << 40)) {
device_memory.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1); device_memory.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1);
device_memory.UpdateTexturePagesCount(image.cpu_addr, image.guest_size_bytes, -1);
} }
return; return;
} }
@@ -2352,7 +2348,6 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
const DAddr cpu_addr = map.cpu_addr; const DAddr cpu_addr = map.cpu_addr;
const std::size_t size = map.size; const std::size_t size = map.size;
device_memory.UpdatePagesCachedCount(cpu_addr, size, -1); device_memory.UpdatePagesCachedCount(cpu_addr, size, -1);
device_memory.UpdateTexturePagesCount(cpu_addr, size, -1);
} }
} }
@@ -257,7 +257,7 @@ public:
/// Prepare an image to be used /// Prepare an image to be used
void PrepareImage(ImageId image_id, bool is_modification, bool invalidate); void PrepareImage(ImageId image_id, bool is_modification, bool invalidate);
std::mutex mutex; std::recursive_mutex mutex;
private: private:
/// Iterate over all page indices in a range /// Iterate over all page indices in a range
@@ -1373,11 +1373,6 @@ void Device::RemoveUnsuitableExtensions() {
extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME); extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME); RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
// VK_KHR_dynamic_rendering
extensions.dynamic_rendering = features.dynamic_rendering.dynamicRendering;
RemoveExtensionFeatureIfUnsuitable(extensions.dynamic_rendering, features.dynamic_rendering,
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
// VK_KHR_maintenance4 // VK_KHR_maintenance4
extensions.maintenance4 = features.maintenance4.maintenance4; extensions.maintenance4 = features.maintenance4.maintenance4;
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4, RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4,
@@ -43,7 +43,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \ FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \
shader_demote_to_helper_invocation) \ shader_demote_to_helper_invocation) \
FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \ FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \
FEATURE(KHR, DynamicRendering, DYNAMIC_RENDERING, dynamic_rendering) \
FEATURE(KHR, Maintenance4, MAINTENANCE_4, maintenance4) \ FEATURE(KHR, Maintenance4, MAINTENANCE_4, maintenance4) \
FEATURE(KHR, Synchronization2, SYNCHRONIZATION_2, synchronization2) FEATURE(KHR, Synchronization2, SYNCHRONIZATION_2, synchronization2)
@@ -942,13 +941,6 @@ FN_MAX_LIMIT_LIST
return extensions.maintenance3; return extensions.maintenance3;
} }
static constexpr bool ENABLE_DYNAMIC_RENDERING = false;
/// Returns true if the device supports VK_KHR_dynamic_rendering.
bool IsKhrDynamicRenderingSupported() const {
return ENABLE_DYNAMIC_RENDERING && extensions.dynamic_rendering;
}
/// Returns true if the device supports VK_KHR_maintenance4. /// Returns true if the device supports VK_KHR_maintenance4.
bool IsKhrMaintenance4Supported() const { bool IsKhrMaintenance4Supported() const {
return extensions.maintenance4; return extensions.maintenance4;
@@ -92,7 +92,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdBeginConditionalRenderingEXT); X(vkCmdBeginConditionalRenderingEXT);
X(vkCmdBeginQuery); X(vkCmdBeginQuery);
X(vkCmdBeginRenderPass); X(vkCmdBeginRenderPass);
X(vkCmdBeginRendering);
X(vkCmdBeginTransformFeedbackEXT); X(vkCmdBeginTransformFeedbackEXT);
X(vkCmdBeginDebugUtilsLabelEXT); X(vkCmdBeginDebugUtilsLabelEXT);
X(vkCmdBindDescriptorSets); X(vkCmdBindDescriptorSets);
@@ -120,7 +119,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdEndConditionalRenderingEXT); X(vkCmdEndConditionalRenderingEXT);
X(vkCmdEndQuery); X(vkCmdEndQuery);
X(vkCmdEndRenderPass); X(vkCmdEndRenderPass);
X(vkCmdEndRendering);
X(vkCmdEndTransformFeedbackEXT); X(vkCmdEndTransformFeedbackEXT);
X(vkCmdEndDebugUtilsLabelEXT); X(vkCmdEndDebugUtilsLabelEXT);
X(vkCmdFillBuffer); X(vkCmdFillBuffer);
@@ -232,7 +230,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkMapMemory); X(vkMapMemory);
X(vkQueueSubmit); X(vkQueueSubmit);
X(vkQueueSubmit2); X(vkQueueSubmit2);
X(vkResetCommandPool);
X(vkResetFences); X(vkResetFences);
X(vkResetQueryPool); X(vkResetQueryPool);
X(vkSetDebugUtilsObjectNameEXT); X(vkSetDebugUtilsObjectNameEXT);
@@ -260,12 +257,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
Proc(dld.vkCmdDrawIndexedIndirectCount, dld, "vkCmdDrawIndexedIndirectCountKHR", device); Proc(dld.vkCmdDrawIndexedIndirectCount, dld, "vkCmdDrawIndexedIndirectCountKHR", device);
} }
// Support for dynamic rendering is optional until Vulkan 1.3
if (!dld.vkCmdBeginRendering) {
Proc(dld.vkCmdBeginRendering, dld, "vkCmdBeginRenderingKHR", device);
Proc(dld.vkCmdEndRendering, dld, "vkCmdEndRenderingKHR", device);
}
// Synchronization2 is core in Vulkan 1.3, otherwise requires VK_KHR_synchronization2 // Synchronization2 is core in Vulkan 1.3, otherwise requires VK_KHR_synchronization2
if (!dld.vkCmdPipelineBarrier2) { if (!dld.vkCmdPipelineBarrier2) {
Proc(dld.vkCmdPipelineBarrier2, dld, "vkCmdPipelineBarrier2KHR", device); Proc(dld.vkCmdPipelineBarrier2, dld, "vkCmdPipelineBarrier2KHR", device);
@@ -208,7 +208,6 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT{}; PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT{};
PFN_vkCmdBeginQuery vkCmdBeginQuery{}; PFN_vkCmdBeginQuery vkCmdBeginQuery{};
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass{}; PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass{};
PFN_vkCmdBeginRendering vkCmdBeginRendering{};
PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT{}; PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT{};
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets{}; PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets{};
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer{}; PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer{};
@@ -237,7 +236,6 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{};
PFN_vkCmdEndQuery vkCmdEndQuery{}; PFN_vkCmdEndQuery vkCmdEndQuery{};
PFN_vkCmdEndRenderPass vkCmdEndRenderPass{}; PFN_vkCmdEndRenderPass vkCmdEndRenderPass{};
PFN_vkCmdEndRendering vkCmdEndRendering{};
PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{}; PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{};
PFN_vkCmdFillBuffer vkCmdFillBuffer{}; PFN_vkCmdFillBuffer vkCmdFillBuffer{};
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier{}; PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier{};
@@ -348,7 +346,6 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkMapMemory vkMapMemory{}; PFN_vkMapMemory vkMapMemory{};
PFN_vkQueueSubmit vkQueueSubmit{}; PFN_vkQueueSubmit vkQueueSubmit{};
PFN_vkQueueSubmit2 vkQueueSubmit2{}; PFN_vkQueueSubmit2 vkQueueSubmit2{};
PFN_vkResetCommandPool vkResetCommandPool{};
PFN_vkResetFences vkResetFences{}; PFN_vkResetFences vkResetFences{};
PFN_vkResetQueryPool vkResetQueryPool{}; PFN_vkResetQueryPool vkResetQueryPool{};
PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT{}; PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT{};
@@ -928,10 +925,6 @@ public:
CommandBuffers Allocate(std::size_t num_buffers, CommandBuffers Allocate(std::size_t num_buffers,
VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
void Reset(VkCommandPoolResetFlags flags = 0) const {
Check(dld->vkResetCommandPool(owner, handle, flags));
}
/// Set object name. /// Set object name.
void SetObjectNameEXT(const char* name) const; void SetObjectNameEXT(const char* name) const;
}; };
@@ -1193,14 +1186,6 @@ public:
dld->vkCmdEndRenderPass(handle); dld->vkCmdEndRenderPass(handle);
} }
void BeginRendering(const VkRenderingInfo& rendering_info) const noexcept {
dld->vkCmdBeginRendering(handle, &rendering_info);
}
void EndRendering() const noexcept {
dld->vkCmdEndRendering(handle);
}
void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept { void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
dld->vkCmdBeginQuery(handle, query_pool, query, flags); dld->vkCmdBeginQuery(handle, query_pool, query, flags);
} }
+3 -9
View File
@@ -233,8 +233,7 @@
</property> </property>
<addaction name="action_Report_Compatibility"/> <addaction name="action_Report_Compatibility"/>
<addaction name="action_Open_Mods_Page"/> <addaction name="action_Open_Mods_Page"/>
<addaction name="action_Open_Quickstart_Guide"/> <addaction name="action_Open_UserHandbook"/>
<addaction name="action_Open_FAQ"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="action_About"/> <addaction name="action_About"/>
<addaction name="action_Eden_Dependencies"/> <addaction name="action_Eden_Dependencies"/>
@@ -407,14 +406,9 @@
<string>Open &amp;Mods Page</string> <string>Open &amp;Mods Page</string>
</property> </property>
</action> </action>
<action name="action_Open_Quickstart_Guide"> <action name="action_Open_UserHandbook">
<property name="text"> <property name="text">
<string>Open &amp;Quickstart Guide</string> <string>&amp;User Handbook</string>
</property>
</action>
<action name="action_Open_FAQ">
<property name="text">
<string>&amp;FAQ</string>
</property> </property>
</action> </action>
<action name="action_Capture_Screenshot"> <action name="action_Capture_Screenshot">
+7 -14
View File
@@ -1500,8 +1500,7 @@ void MainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Pause, &MainWindow::OnPauseContinueGame); connect_menu(ui->action_Pause, &MainWindow::OnPauseContinueGame);
connect_menu(ui->action_Stop, &MainWindow::OnStopGame); connect_menu(ui->action_Stop, &MainWindow::OnStopGame);
connect_menu(ui->action_Open_Mods_Page, &MainWindow::OnOpenModsPage); connect_menu(ui->action_Open_Mods_Page, &MainWindow::OnOpenModsPage);
connect_menu(ui->action_Open_Quickstart_Guide, &MainWindow::OnOpenQuickstartGuide); connect_menu(ui->action_Open_UserHandbook, &MainWindow::OnOpenUserHandbook);
connect_menu(ui->action_Open_FAQ, &MainWindow::OnOpenFAQ);
connect_menu(ui->action_Restart, &MainWindow::OnRestartGame); connect_menu(ui->action_Restart, &MainWindow::OnRestartGame);
connect_menu(ui->action_Configure, &MainWindow::OnConfigure); connect_menu(ui->action_Configure, &MainWindow::OnConfigure);
connect_menu(ui->action_Configure_Current_Game, &MainWindow::OnConfigurePerGame); connect_menu(ui->action_Configure_Current_Game, &MainWindow::OnConfigurePerGame);
@@ -1837,12 +1836,10 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar
case Core::SystemResultStatus::ErrorVideoCore: case Core::SystemResultStatus::ErrorVideoCore:
QMessageBox::critical( QMessageBox::critical(
this, tr("An error occurred initializing the video core."), this, tr("An error occurred initializing the video core."),
tr("Eden has encountered an error while running the video core. " tr("This is usually caused by outdated GPU drivers. "
"This is usually caused by outdated GPU drivers, including integrated ones. " "Please see the log for more details. See: "
"Please see the log for more details. " "<a href='https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md'>"
"For more information on accessing the log, please see the following page: " "How to access log files</a>."));
"<a href='https://yuzu-mirror.github.io/help/reference/log-files/'>"
"How to Upload the Log File</a>. "));
break; break;
default: default:
if (result > Core::SystemResultStatus::ErrorLoader) { if (result > Core::SystemResultStatus::ErrorLoader) {
@@ -3149,12 +3146,8 @@ void MainWindow::OnOpenModsPage() {
OpenURL(QUrl(QStringLiteral("https://github.com/eden-emulator/yuzu-mod-archive"))); OpenURL(QUrl(QStringLiteral("https://github.com/eden-emulator/yuzu-mod-archive")));
} }
void MainWindow::OnOpenQuickstartGuide() { void MainWindow::OnOpenUserHandbook() {
OpenURL(QUrl(QStringLiteral("https://yuzu-mirror.github.io/help/quickstart/"))); OpenURL(QUrl(QStringLiteral("https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/README.md")));
}
void MainWindow::OnOpenFAQ() {
OpenURL(QUrl(QStringLiteral("https://yuzu-mirror.github.io/help")));
} }
void MainWindow::ToggleFullscreen() { void MainWindow::ToggleFullscreen() {
+1 -2
View File
@@ -336,8 +336,7 @@ private slots:
void OnPrepareForSleep(bool prepare_sleep); void OnPrepareForSleep(bool prepare_sleep);
void OnMenuReportCompatibility(); void OnMenuReportCompatibility();
void OnOpenModsPage(); void OnOpenModsPage();
void OnOpenQuickstartGuide(); void OnOpenUserHandbook();
void OnOpenFAQ();
/// Called whenever a user selects a game in the game list widget. /// Called whenever a user selects a game in the game list widget.
void OnGameListLoadFile(QString game_path, u64 program_id); void OnGameListLoadFile(QString game_path, u64 program_id);