mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-28 17:45:39 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 930989ab82 | |||
| 8cbe8d1ce9 | |||
| ff596b6e8a | |||
| 8d2d61bd8c | |||
| d0b135afb5 | |||
| 159841a6fc | |||
| 2ea449f71a | |||
| 602756e990 | |||
| 34f9c0fdec | |||
| faaf1bac64 |
@@ -188,7 +188,7 @@ android {
|
|||||||
create("mainline") {
|
create("mainline") {
|
||||||
dimension = "version"
|
dimension = "version"
|
||||||
isDefault = true
|
isDefault = true
|
||||||
minSdk = 30
|
minSdk = 33
|
||||||
|
|
||||||
manifestPlaceholders += mapOf("appNameBase" to "Eden")
|
manifestPlaceholders += mapOf("appNameBase" to "Eden")
|
||||||
resValue("string", "app_name_suffixed", "Eden")
|
resValue("string", "app_name_suffixed", "Eden")
|
||||||
|
|||||||
-1
@@ -11,7 +11,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
|
|||||||
enum class StringSetting(override val key: String) : AbstractStringSetting {
|
enum class StringSetting(override val key: String) : AbstractStringSetting {
|
||||||
DRIVER_PATH("driver_path"),
|
DRIVER_PATH("driver_path"),
|
||||||
DEVICE_NAME("device_name"),
|
DEVICE_NAME("device_name"),
|
||||||
LOG_FILTER("log_filter"),
|
|
||||||
PROGRAM_ARGS("program_args"),
|
PROGRAM_ARGS("program_args"),
|
||||||
|
|
||||||
WEB_TOKEN("eden_token"),
|
WEB_TOKEN("eden_token"),
|
||||||
|
|||||||
-7
@@ -1032,13 +1032,6 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.use_auto_stub_description
|
descriptionId = R.string.use_auto_stub_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
StringInputSetting(
|
|
||||||
StringSetting.LOG_FILTER,
|
|
||||||
titleId = R.string.log_filter,
|
|
||||||
descriptionId = R.string.log_filter_description
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SpinBoxSetting(
|
SpinBoxSetting(
|
||||||
ShortSetting.DEBUG_KNOBS,
|
ShortSetting.DEBUG_KNOBS,
|
||||||
|
|||||||
-1
@@ -1322,7 +1322,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(HeaderSetting(R.string.log))
|
add(HeaderSetting(R.string.log))
|
||||||
|
|
||||||
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
|
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
|
||||||
add(StringSetting.LOG_FILTER.key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add(HeaderSetting(R.string.general))
|
add(HeaderSetting(R.string.general))
|
||||||
|
|||||||
@@ -636,8 +636,6 @@
|
|||||||
<string name="log">Logging</string>
|
<string name="log">Logging</string>
|
||||||
<string name="flush_by_line">Flush debug logs by line</string>
|
<string name="flush_by_line">Flush debug logs by line</string>
|
||||||
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
|
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
|
||||||
<string name="log_filter">Log filter</string>
|
|
||||||
<string name="log_filter_description">Controls Eden\'s log categories. Example: *:Info Service.LM:Debug</string>
|
|
||||||
|
|
||||||
<!-- GPU Logging strings -->
|
<!-- GPU Logging strings -->
|
||||||
<string name="gpu_logging_header">GPU Logging</string>
|
<string name="gpu_logging_header">GPU Logging</string>
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ struct ColorConsoleBackend final : public Backend {
|
|||||||
auto const df = GetDirectFormatArgs(entry);
|
auto const df = GetDirectFormatArgs(entry);
|
||||||
// more restrictive, because take for example this simple prelude:
|
// more restrictive, because take for example this simple prelude:
|
||||||
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
|
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
|
||||||
char buffer[128];
|
char buffer[256];
|
||||||
auto result = fmt::format_to_n(buffer, sizeof(buffer) - 1, "\x1b{}[{:4d}.{:06d}] {} <{}> {}:{}:{}: ", color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
|
auto result = fmt::format_to_n(buffer, sizeof(buffer) - 1, "\x1b{}[{:4d}.{:06d}] {} <{}> {}:{}:{}: ", color_str, df.time_seconds, df.time_fractional, df.class_name, df.level_name, entry.filename, entry.line_num, entry.function, entry.message);
|
||||||
std::fwrite(buffer, 1, (std::min)(sizeof(buffer) - 1, result.size), stdout);
|
std::fwrite(buffer, 1, (std::min)(sizeof(buffer) - 1, result.size), stdout);
|
||||||
std::fwrite(entry.message, 1, entry.message_len, stdout);
|
std::fwrite(entry.message, 1, entry.message_len, stdout);
|
||||||
@@ -425,14 +425,14 @@ void SetColorConsoleBackendEnabled(bool enabled) {
|
|||||||
|
|
||||||
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) {
|
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) {
|
||||||
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
|
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
|
||||||
|
auto const flush = ::Settings::values.log_flush_line.GetValue();
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
|
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
|
||||||
buffer[result.size] = '\0';
|
buffer[(std::min)(result.size, sizeof(buffer) - 1)] = '\0';
|
||||||
auto const flush = ::Settings::values.log_flush_line.GetValue();
|
|
||||||
logging_instance->ForEachBackend([=](Backend& backend) {
|
logging_instance->ForEachBackend([=](Backend& backend) {
|
||||||
backend.Write(Entry{
|
backend.Write(Entry{
|
||||||
.message = buffer,
|
.message = buffer,
|
||||||
.message_len = (std::min)(sizeof(buffer) - 1, result.size),
|
.message_len = (std::min)(result.size, sizeof(buffer) - 1),
|
||||||
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
|
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
|
||||||
.log_class = log_class,
|
.log_class = log_class,
|
||||||
.log_level = log_level,
|
.log_level = log_level,
|
||||||
|
|||||||
@@ -132,11 +132,9 @@ void LogSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG_INFO(Config, "Eden Configuration:");
|
||||||
std::string settings_str{};
|
|
||||||
for (auto const& e : settings_list)
|
for (auto const& e : settings_list)
|
||||||
settings_str += e;
|
LOG_INFO(Config, "{}", e);
|
||||||
LOG_INFO(Config, "Eden Configuration:\n{}", settings_str);
|
|
||||||
#define LOG_PATH(NAME) \
|
#define LOG_PATH(NAME) \
|
||||||
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
|
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
|
||||||
LOG_PATH(CacheDir);
|
LOG_PATH(CacheDir);
|
||||||
@@ -371,7 +369,7 @@ void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info)
|
|||||||
}
|
}
|
||||||
info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift);
|
info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift);
|
||||||
info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale;
|
info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale;
|
||||||
info.active = info.up_scale != 1 || info.down_shift != 0;
|
info.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateRescalingInfo() {
|
void UpdateRescalingInfo() {
|
||||||
|
|||||||
@@ -904,7 +904,7 @@ struct Values {
|
|||||||
0,
|
0,
|
||||||
65535,
|
65535,
|
||||||
"debug_knobs",
|
"debug_knobs",
|
||||||
Category::System,
|
Category::Debugging,
|
||||||
Specialization::Countable,
|
Specialization::Countable,
|
||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
|||||||
+14
-182
@@ -3,158 +3,14 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <cctype>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/debug.h"
|
#include "core/arm/debug.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/k_memory_block.h"
|
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "core/hle/kernel/svc_types.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr std::size_t GuestStringProbeBytes = 0x100;
|
|
||||||
constexpr std::size_t StackProbeWords = 96;
|
|
||||||
constexpr std::size_t MaxGuestStringLogs = 16;
|
|
||||||
constexpr std::size_t MaxBacktraceFrames = 64;
|
|
||||||
constexpr std::size_t MinGuestStringLength = 4;
|
|
||||||
|
|
||||||
std::string SanitizeGuestString(std::string_view text) {
|
|
||||||
std::string sanitized;
|
|
||||||
sanitized.reserve(text.size());
|
|
||||||
|
|
||||||
for (const char ch : text) {
|
|
||||||
switch (ch) {
|
|
||||||
case '\\':
|
|
||||||
sanitized += "\\\\";
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
sanitized += "\\\"";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sanitized += ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sanitized;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsUsefulGuestString(std::string_view text) {
|
|
||||||
if (text.size() < MinGuestStringLength) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t alpha_numeric_count{};
|
|
||||||
for (const char ch : text) {
|
|
||||||
const auto byte = static_cast<unsigned char>(ch);
|
|
||||||
if (std::isprint(byte) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::isalnum(byte) != 0) {
|
|
||||||
alpha_numeric_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return alpha_numeric_count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QueryGuestMemoryInfo(Kernel::KProcess* process, u64 address,
|
|
||||||
Kernel::Svc::MemoryInfo* out_info) {
|
|
||||||
if (address == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Kernel::KMemoryInfo mem_info{};
|
|
||||||
Kernel::Svc::PageInfo page_info{};
|
|
||||||
if (process->GetPageTable().QueryInfo(&mem_info, &page_info, address).IsFailure()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_info = mem_info.GetSvcMemoryInfo();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogGuestStringCandidate(Kernel::KProcess* process, u64 address, std::string_view label,
|
|
||||||
std::vector<u64>& logged_strings) {
|
|
||||||
if (logged_strings.size() >= MaxGuestStringLogs) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (std::find(logged_strings.begin(), logged_strings.end(), address) != logged_strings.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Kernel::Svc::MemoryInfo mem_info{};
|
|
||||||
if (!QueryGuestMemoryInfo(process, address, &mem_info)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mem_info.state == Kernel::Svc::MemoryState::Free ||
|
|
||||||
mem_info.permission == Kernel::Svc::MemoryPermission::None) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address < mem_info.base_address) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u64 region_offset = address - mem_info.base_address;
|
|
||||||
if (region_offset >= mem_info.size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u64 available_bytes = mem_info.size - region_offset;
|
|
||||||
const auto probe_size =
|
|
||||||
static_cast<std::size_t>(std::min<u64>(GuestStringProbeBytes, available_bytes));
|
|
||||||
if (probe_size < MinGuestStringLength ||
|
|
||||||
!process->GetMemory().IsValidVirtualAddressRange(address, probe_size)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto text = process->GetMemory().ReadCString(address, probe_size);
|
|
||||||
if (!IsUsefulGuestString(text)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logged_strings.push_back(address);
|
|
||||||
LOG_ERROR(Core_ARM, "Guest backtrace string {:02}: {}={:016X} \"{}\"",
|
|
||||||
logged_strings.size() - 1, label, address, SanitizeGuestString(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogStackStringCandidates(Kernel::KProcess* process, u64 base, std::string_view label,
|
|
||||||
std::vector<u64>& logged_strings) {
|
|
||||||
if (base == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& memory = process->GetMemory();
|
|
||||||
for (std::size_t i = 0; i < StackProbeWords; i++) {
|
|
||||||
const u64 address = base + i * sizeof(u64);
|
|
||||||
if (!memory.IsValidVirtualAddressRange(address, sizeof(u64))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 value{};
|
|
||||||
if (!memory.ReadBlock(address, &value, sizeof(value))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogGuestStringCandidate(process, value, fmt::format("{}+{:03X}", label, i * sizeof(u64)),
|
|
||||||
logged_strings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
||||||
Kernel::Svc::ThreadContext ctx;
|
Kernel::Svc::ThreadContext ctx;
|
||||||
this->GetContext(ctx);
|
this->GetContext(ctx);
|
||||||
@@ -170,45 +26,21 @@ void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
|||||||
ctx.r[28], ctx.fp, ctx.lr, ctx.sp,
|
ctx.r[28], ctx.fp, ctx.lr, ctx.sp,
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_ERROR(Core_ARM,
|
std::string msg = fmt::format("Backtrace @ PC={:016X}\n", ctx.pc);
|
||||||
"Guest backtrace context: process=\"{}\" pid={} program_id={:016X} pc={:016X} "
|
for (size_t i = 0; i < 32; i += 4)
|
||||||
"lr={:016X} fp={:016X} sp={:016X} pstate={:08X}",
|
msg += fmt::format("R{:02}={:016X} R{:02}={:016X} R{:02}={:016X} R{:02}={:016X}\n",
|
||||||
process->GetName(), process->GetProcessId(), process->GetProgramId(), ctx.pc,
|
i + 0, xreg[i + 0], i + 1, xreg[i + 1],
|
||||||
ctx.lr, ctx.fp, ctx.sp, ctx.pstate);
|
i + 2, xreg[i + 2], i + 3, xreg[i + 3]);
|
||||||
|
for (size_t i = 0; i < 32; i += 2)
|
||||||
std::vector<u64> logged_strings;
|
msg += fmt::format("V{:02}={:016X}_{:016X} V{:02}={:016X}_{:016X}\n",
|
||||||
for (size_t i = 0; i < xreg.size(); i++) {
|
i + 0, ctx.v[i + 0][0], ctx.v[i + 0][1],
|
||||||
LogGuestStringCandidate(process, xreg[i], fmt::format("R{:02}", i), logged_strings);
|
i + 1, ctx.v[i + 1][0], ctx.v[i + 1][1]);
|
||||||
}
|
msg += fmt::format("PSTATE={:08X} FPCR={:08X} FPSR={:08X} TPIDR={:016X}\n", ctx.pstate, ctx.fpcr, ctx.fpsr, ctx.tpidr);
|
||||||
LogStackStringCandidates(process, ctx.sp, "SP", logged_strings);
|
msg += fmt::format("{:20}{:20}{:20}{:20}{}\n", "Module", "Address", "Original Address", "Offset", "Symbol");
|
||||||
if (ctx.fp != ctx.sp) {
|
|
||||||
LogStackStringCandidates(process, ctx.fp, "FP", logged_strings);
|
|
||||||
}
|
|
||||||
if (logged_strings.empty()) {
|
|
||||||
LOG_ERROR(Core_ARM, "Guest backtrace strings: none found in registers or stack");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const backtrace = GetBacktraceFromContext(process, ctx);
|
auto const backtrace = GetBacktraceFromContext(process, ctx);
|
||||||
for (size_t i = 0; i < std::min(backtrace.size(), MaxBacktraceFrames); i++) {
|
for (auto const& entry : backtrace)
|
||||||
const auto& entry = backtrace[i];
|
msg += fmt::format("{:20}{:016X} {:016X} {:016X} {}\n", entry.module, entry.address, entry.original_address, entry.offset, entry.name);
|
||||||
if (entry.original_address == 0) {
|
LOG_ERROR(Core_ARM, "{}", msg);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.name.empty()) {
|
|
||||||
LOG_ERROR(Core_ARM, "Guest backtrace frame {:03}: {}+0x{:X} pc={:016X} mapped={:016X}",
|
|
||||||
i, entry.module, entry.offset, entry.original_address, entry.address);
|
|
||||||
} else {
|
|
||||||
LOG_ERROR(Core_ARM,
|
|
||||||
"Guest backtrace frame {:03}: {}+0x{:X} pc={:016X} mapped={:016X} symbol={}",
|
|
||||||
i, entry.module, entry.offset, entry.original_address, entry.address,
|
|
||||||
entry.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (backtrace.size() > MaxBacktraceFrames) {
|
|
||||||
LOG_ERROR(Core_ARM, "Guest backtrace truncated: logged={} total={}", MaxBacktraceFrames,
|
|
||||||
backtrace.size());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Kernel::DebugWatchpoint* ArmInterface::MatchingWatchpoint(
|
const Kernel::DebugWatchpoint* ArmInterface::MatchingWatchpoint(
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
#include "common/settings.h"
|
|
||||||
|
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/hle/service/cmif_serialization.h"
|
#include "core/hle/service/cmif_serialization.h"
|
||||||
@@ -33,15 +30,6 @@ Result IStorage::Read(
|
|||||||
|
|
||||||
R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
|
R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
|
||||||
R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
|
R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
|
||||||
static thread_local std::chrono::steady_clock::time_point last_read_tick{};
|
|
||||||
const auto now = std::chrono::steady_clock::now();
|
|
||||||
const auto period = Settings::values.debug_knobs.GetValue();
|
|
||||||
const auto ReadInterval = std::chrono::microseconds{period};
|
|
||||||
if (last_read_tick != std::chrono::steady_clock::time_point{} &&
|
|
||||||
now - last_read_tick < ReadInterval) {
|
|
||||||
std::this_thread::sleep_for(ReadInterval - (now - last_read_tick));
|
|
||||||
}
|
|
||||||
last_read_tick = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
// Read the data from the Storage backend
|
// Read the data from the Storage backend
|
||||||
backend->Read(out_bytes.data(), length, offset);
|
backend->Read(out_bytes.data(), length, offset);
|
||||||
|
|||||||
@@ -206,6 +206,40 @@ foreach(VARIANT IN ITEMS ${SHADER_TYPE_VARIANTS})
|
|||||||
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
set(SHADER_DEFINE_VARIANTS
|
||||||
|
"block_linear_unswizzle_2d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||||
|
"pitch_unswizzle.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||||
|
"block_linear_unswizzle_3d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(VARIANT IN ITEMS ${SHADER_DEFINE_VARIANTS})
|
||||||
|
string(REPLACE "|" ";" VARIANT_PARTS ${VARIANT})
|
||||||
|
list(GET VARIANT_PARTS 0 VARIANT_FILENAME)
|
||||||
|
list(GET VARIANT_PARTS 1 VARIANT_SUFFIX)
|
||||||
|
list(GET VARIANT_PARTS 2 VARIANT_DEFINE)
|
||||||
|
|
||||||
|
set(VARIANT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${VARIANT_FILENAME})
|
||||||
|
get_filename_component(VARIANT_STEM ${VARIANT_FILENAME} NAME_WE)
|
||||||
|
get_filename_component(VARIANT_EXT ${VARIANT_FILENAME} EXT)
|
||||||
|
string(REPLACE "." "" VARIANT_EXT ${VARIANT_EXT})
|
||||||
|
set(VARIANT_NAME ${VARIANT_STEM}_${VARIANT_SUFFIX}_${VARIANT_EXT})
|
||||||
|
|
||||||
|
string(TOUPPER ${VARIANT_NAME}_SPV VARIANT_VARIABLE_NAME)
|
||||||
|
set(VARIANT_HEADER_FILE ${SHADER_DIR}/${VARIANT_NAME}_spv.h)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT
|
||||||
|
${VARIANT_HEADER_FILE}
|
||||||
|
COMMAND
|
||||||
|
${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS}
|
||||||
|
-D${VARIANT_DEFINE}
|
||||||
|
--variable-name ${VARIANT_VARIABLE_NAME} -o ${VARIANT_HEADER_FILE} ${VARIANT_SOURCE}
|
||||||
|
--target-env ${SPIR_V_VERSION}
|
||||||
|
MAIN_DEPENDENCY
|
||||||
|
${VARIANT_SOURCE}
|
||||||
|
)
|
||||||
|
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
|
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
|
||||||
get_filename_component(FILENAME ${FILEPATH} NAME)
|
get_filename_component(FILENAME ${FILEPATH} NAME)
|
||||||
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
|
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
|
||||||
|
|||||||
@@ -5,9 +5,13 @@
|
|||||||
|
|
||||||
#ifdef VULKAN
|
#ifdef VULKAN
|
||||||
|
|
||||||
|
#ifndef HAS_EXTENDED_TYPES
|
||||||
|
#define HAS_EXTENDED_TYPES 1
|
||||||
|
#endif
|
||||||
|
#if HAS_EXTENDED_TYPES
|
||||||
#extension GL_EXT_shader_16bit_storage : require
|
#extension GL_EXT_shader_16bit_storage : require
|
||||||
#extension GL_EXT_shader_8bit_storage : require
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
#define HAS_EXTENDED_TYPES 1
|
#endif
|
||||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||||
#define END_PUSH_CONSTANTS };
|
#define END_PUSH_CONSTANTS };
|
||||||
#define UNIFORM(n)
|
#define UNIFORM(n)
|
||||||
|
|||||||
@@ -5,9 +5,13 @@
|
|||||||
|
|
||||||
#ifdef VULKAN
|
#ifdef VULKAN
|
||||||
|
|
||||||
|
#ifndef HAS_EXTENDED_TYPES
|
||||||
|
#define HAS_EXTENDED_TYPES 1
|
||||||
|
#endif
|
||||||
|
#if HAS_EXTENDED_TYPES
|
||||||
#extension GL_EXT_shader_16bit_storage : require
|
#extension GL_EXT_shader_16bit_storage : require
|
||||||
#extension GL_EXT_shader_8bit_storage : require
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
#define HAS_EXTENDED_TYPES 1
|
#endif
|
||||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||||
#define END_PUSH_CONSTANTS };
|
#define END_PUSH_CONSTANTS };
|
||||||
#define UNIFORM(n)
|
#define UNIFORM(n)
|
||||||
|
|||||||
@@ -5,9 +5,13 @@
|
|||||||
|
|
||||||
#ifdef VULKAN
|
#ifdef VULKAN
|
||||||
|
|
||||||
|
#ifndef HAS_EXTENDED_TYPES
|
||||||
|
#define HAS_EXTENDED_TYPES 1
|
||||||
|
#endif
|
||||||
|
#if HAS_EXTENDED_TYPES
|
||||||
#extension GL_EXT_shader_16bit_storage : require
|
#extension GL_EXT_shader_16bit_storage : require
|
||||||
#extension GL_EXT_shader_8bit_storage : require
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
#define HAS_EXTENDED_TYPES 1
|
#endif
|
||||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||||
#define END_PUSH_CONSTANTS };
|
#define END_PUSH_CONSTANTS };
|
||||||
#define UNIFORM(n)
|
#define UNIFORM(n)
|
||||||
|
|||||||
@@ -22,7 +22,13 @@
|
|||||||
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
||||||
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
|
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
|
||||||
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
|
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
|
||||||
|
#include "video_core/host_shaders/block_linear_unswizzle_2d_comp_spv.h"
|
||||||
|
#include "video_core/host_shaders/block_linear_unswizzle_2d_nonarrow_comp_spv.h"
|
||||||
#include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h"
|
#include "video_core/host_shaders/block_linear_unswizzle_3d_bcn_comp_spv.h"
|
||||||
|
#include "video_core/host_shaders/block_linear_unswizzle_3d_comp_spv.h"
|
||||||
|
#include "video_core/host_shaders/block_linear_unswizzle_3d_nonarrow_comp_spv.h"
|
||||||
|
#include "video_core/host_shaders/pitch_unswizzle_comp_spv.h"
|
||||||
|
#include "video_core/host_shaders/pitch_unswizzle_nonarrow_comp_spv.h"
|
||||||
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
||||||
#include "video_core/surface.h"
|
#include "video_core/surface.h"
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
@@ -872,4 +878,291 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr u32 UNSWIZZLE_BINDING_INPUT_BUFFER = 0;
|
||||||
|
constexpr u32 UNSWIZZLE_BINDING_OUTPUT_IMAGE = 1;
|
||||||
|
constexpr size_t UNSWIZZLE_NUM_BINDINGS = 2;
|
||||||
|
|
||||||
|
constexpr std::array<VkDescriptorSetLayoutBinding, UNSWIZZLE_NUM_BINDINGS>
|
||||||
|
UNSWIZZLE_DESCRIPTOR_SET_BINDINGS{{
|
||||||
|
{
|
||||||
|
.binding = UNSWIZZLE_BINDING_INPUT_BUFFER,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.binding = UNSWIZZLE_BINDING_OUTPUT_IMAGE,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
constexpr std::array<VkDescriptorUpdateTemplateEntry, UNSWIZZLE_NUM_BINDINGS>
|
||||||
|
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE{{
|
||||||
|
{
|
||||||
|
.dstBinding = UNSWIZZLE_BINDING_INPUT_BUFFER,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.offset = UNSWIZZLE_BINDING_INPUT_BUFFER * sizeof(DescriptorUpdateEntry),
|
||||||
|
.stride = sizeof(DescriptorUpdateEntry),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.dstBinding = UNSWIZZLE_BINDING_OUTPUT_IMAGE,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
|
.offset = UNSWIZZLE_BINDING_OUTPUT_IMAGE * sizeof(DescriptorUpdateEntry),
|
||||||
|
.stride = sizeof(DescriptorUpdateEntry),
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
constexpr DescriptorBankInfo UNSWIZZLE_BANK_INFO{
|
||||||
|
.uniform_buffers = 0,
|
||||||
|
.storage_buffers = 1,
|
||||||
|
.texture_buffers = 0,
|
||||||
|
.image_buffers = 0,
|
||||||
|
.textures = 0,
|
||||||
|
.images = 1,
|
||||||
|
.score = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] std::span<const u32> UnswizzleSpv(const Device& device,
|
||||||
|
std::span<const u32> extended,
|
||||||
|
std::span<const u32> narrow) {
|
||||||
|
if (device.IsStorageBuffer8BitAccessSupported() &&
|
||||||
|
device.IsStorageBuffer16BitAccessSupported()) {
|
||||||
|
return extended;
|
||||||
|
}
|
||||||
|
return narrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PitchUnswizzlePushConstants {
|
||||||
|
alignas(8) std::array<u32, 2> origin;
|
||||||
|
alignas(8) std::array<s32, 2> destination;
|
||||||
|
u32 bytes_per_block;
|
||||||
|
u32 pitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
void RecordUnswizzleEntryBarrier(Scheduler& scheduler, VkPipeline vk_pipeline, VkImage vk_image,
|
||||||
|
VkImageAspectFlags aspect_mask, bool is_initialized) {
|
||||||
|
scheduler.Record([vk_pipeline, vk_image, aspect_mask,
|
||||||
|
is_initialized](vk::CommandBuffer cmdbuf) {
|
||||||
|
VkAccessFlags src_access = VK_ACCESS_NONE;
|
||||||
|
VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
if (is_initialized) {
|
||||||
|
src_access = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
old_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
}
|
||||||
|
const VkImageMemoryBarrier image_barrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = src_access,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
|
.oldLayout = old_layout,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = vk_image,
|
||||||
|
.subresourceRange{
|
||||||
|
.aspectMask = aspect_mask,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
VkPipelineStageFlags src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
if (is_initialized) {
|
||||||
|
src_stage = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER;
|
||||||
|
}
|
||||||
|
cmdbuf.PipelineBarrier(src_stage, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||||
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordUnswizzleExitBarrier(Scheduler& scheduler, VkImage vk_image,
|
||||||
|
VkImageAspectFlags aspect_mask) {
|
||||||
|
scheduler.Record([vk_image, aspect_mask](vk::CommandBuffer cmdbuf) {
|
||||||
|
const VkImageMemoryBarrier image_barrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = vk_image,
|
||||||
|
.subresourceRange{
|
||||||
|
.aspectMask = aspect_mask,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, 0, image_barrier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
BlockLinearUnswizzle2DPass::BlockLinearUnswizzle2DPass(
|
||||||
|
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||||
|
: ComputePass(device_, scheduler_, descriptor_pool_, UNSWIZZLE_DESCRIPTOR_SET_BINDINGS,
|
||||||
|
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE, UNSWIZZLE_BANK_INFO,
|
||||||
|
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(
|
||||||
|
VideoCommon::Accelerated::BlockLinearSwizzle2DParams)>,
|
||||||
|
UnswizzleSpv(device_, BLOCK_LINEAR_UNSWIZZLE_2D_COMP_SPV,
|
||||||
|
BLOCK_LINEAR_UNSWIZZLE_2D_NONARROW_COMP_SPV)),
|
||||||
|
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||||
|
|
||||||
|
BlockLinearUnswizzle2DPass::~BlockLinearUnswizzle2DPass() = default;
|
||||||
|
|
||||||
|
void BlockLinearUnswizzle2DPass::Unswizzle(
|
||||||
|
Image& image, const StagingBufferRef& map,
|
||||||
|
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||||
|
using namespace VideoCommon::Accelerated;
|
||||||
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
|
const VkPipeline vk_pipeline = *pipeline;
|
||||||
|
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||||
|
const VkImage vk_image = image.Handle();
|
||||||
|
const bool is_initialized = image.ExchangeInitialization();
|
||||||
|
RecordUnswizzleEntryBarrier(scheduler, vk_pipeline, vk_image, aspect_mask, is_initialized);
|
||||||
|
|
||||||
|
const u32 num_layers = static_cast<u32>(image.info.resources.layers);
|
||||||
|
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||||
|
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||||
|
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
|
||||||
|
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
|
||||||
|
|
||||||
|
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||||
|
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||||
|
image.guest_size_bytes - swizzle.buffer_offset);
|
||||||
|
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||||
|
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||||
|
|
||||||
|
const auto params = MakeBlockLinearSwizzle2DParams(swizzle, image.info);
|
||||||
|
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_layers, params,
|
||||||
|
descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||||
|
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||||
|
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||||
|
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params);
|
||||||
|
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_layers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RecordUnswizzleExitBarrier(scheduler, vk_image, aspect_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockLinearUnswizzleImage3DPass::BlockLinearUnswizzleImage3DPass(
|
||||||
|
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||||
|
: ComputePass(device_, scheduler_, descriptor_pool_, UNSWIZZLE_DESCRIPTOR_SET_BINDINGS,
|
||||||
|
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE, UNSWIZZLE_BANK_INFO,
|
||||||
|
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(BlockLinearSwizzle3DParams)>,
|
||||||
|
UnswizzleSpv(device_, BLOCK_LINEAR_UNSWIZZLE_3D_COMP_SPV,
|
||||||
|
BLOCK_LINEAR_UNSWIZZLE_3D_NONARROW_COMP_SPV)),
|
||||||
|
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||||
|
|
||||||
|
BlockLinearUnswizzleImage3DPass::~BlockLinearUnswizzleImage3DPass() = default;
|
||||||
|
|
||||||
|
void BlockLinearUnswizzleImage3DPass::Unswizzle(
|
||||||
|
Image& image, const StagingBufferRef& map,
|
||||||
|
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||||
|
using namespace VideoCommon::Accelerated;
|
||||||
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
|
const VkPipeline vk_pipeline = *pipeline;
|
||||||
|
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||||
|
const VkImage vk_image = image.Handle();
|
||||||
|
const bool is_initialized = image.ExchangeInitialization();
|
||||||
|
RecordUnswizzleEntryBarrier(scheduler, vk_pipeline, vk_image, aspect_mask, is_initialized);
|
||||||
|
|
||||||
|
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||||
|
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||||
|
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 16U);
|
||||||
|
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
|
||||||
|
const u32 num_dispatches_z = Common::DivCeil(swizzle.num_tiles.depth, 8U);
|
||||||
|
|
||||||
|
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||||
|
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||||
|
image.guest_size_bytes - swizzle.buffer_offset);
|
||||||
|
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||||
|
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||||
|
|
||||||
|
const auto params = MakeBlockLinearSwizzle3DParams(swizzle, image.info);
|
||||||
|
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, params,
|
||||||
|
descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||||
|
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||||
|
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||||
|
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params);
|
||||||
|
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, num_dispatches_z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RecordUnswizzleExitBarrier(scheduler, vk_image, aspect_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
PitchUnswizzlePass::PitchUnswizzlePass(
|
||||||
|
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||||
|
: ComputePass(device_, scheduler_, descriptor_pool_, UNSWIZZLE_DESCRIPTOR_SET_BINDINGS,
|
||||||
|
UNSWIZZLE_DESCRIPTOR_UPDATE_TEMPLATE, UNSWIZZLE_BANK_INFO,
|
||||||
|
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(PitchUnswizzlePushConstants)>,
|
||||||
|
UnswizzleSpv(device_, PITCH_UNSWIZZLE_COMP_SPV,
|
||||||
|
PITCH_UNSWIZZLE_NONARROW_COMP_SPV)),
|
||||||
|
scheduler{scheduler_}, compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||||
|
|
||||||
|
PitchUnswizzlePass::~PitchUnswizzlePass() = default;
|
||||||
|
|
||||||
|
void PitchUnswizzlePass::Unswizzle(Image& image, const StagingBufferRef& map,
|
||||||
|
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||||
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
|
const VkPipeline vk_pipeline = *pipeline;
|
||||||
|
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||||
|
const VkImage vk_image = image.Handle();
|
||||||
|
const bool is_initialized = image.ExchangeInitialization();
|
||||||
|
RecordUnswizzleEntryBarrier(scheduler, vk_pipeline, vk_image, aspect_mask, is_initialized);
|
||||||
|
|
||||||
|
const u32 bytes_per_block = VideoCore::Surface::BytesPerBlock(image.info.format);
|
||||||
|
const u32 pitch = image.info.pitch;
|
||||||
|
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||||
|
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||||
|
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 32U);
|
||||||
|
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 32U);
|
||||||
|
|
||||||
|
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||||
|
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||||
|
image.guest_size_bytes - swizzle.buffer_offset);
|
||||||
|
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||||
|
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||||
|
|
||||||
|
const PitchUnswizzlePushConstants params{
|
||||||
|
.origin{0, 0},
|
||||||
|
.destination{0, 0},
|
||||||
|
.bytes_per_block = bytes_per_block,
|
||||||
|
.pitch = pitch,
|
||||||
|
};
|
||||||
|
scheduler.Record([this, num_dispatches_x, num_dispatches_y, params,
|
||||||
|
descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||||
|
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||||
|
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||||
|
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, params);
|
||||||
|
cmdbuf.Dispatch(num_dispatches_x, num_dispatches_y, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RecordUnswizzleExitBarrier(scheduler, vk_image, aspect_mask);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -164,4 +164,49 @@ private:
|
|||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BlockLinearUnswizzle2DPass final : public ComputePass {
|
||||||
|
public:
|
||||||
|
explicit BlockLinearUnswizzle2DPass(
|
||||||
|
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||||
|
~BlockLinearUnswizzle2DPass();
|
||||||
|
|
||||||
|
void Unswizzle(Image& image, const StagingBufferRef& map,
|
||||||
|
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scheduler& scheduler;
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlockLinearUnswizzleImage3DPass final : public ComputePass {
|
||||||
|
public:
|
||||||
|
explicit BlockLinearUnswizzleImage3DPass(
|
||||||
|
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||||
|
~BlockLinearUnswizzleImage3DPass();
|
||||||
|
|
||||||
|
void Unswizzle(Image& image, const StagingBufferRef& map,
|
||||||
|
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scheduler& scheduler;
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PitchUnswizzlePass final : public ComputePass {
|
||||||
|
public:
|
||||||
|
explicit PitchUnswizzlePass(const Device& device_, Scheduler& scheduler_,
|
||||||
|
DescriptorPool& descriptor_pool_,
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||||
|
~PitchUnswizzlePass();
|
||||||
|
|
||||||
|
void Unswizzle(Image& image, const StagingBufferRef& map,
|
||||||
|
std::span<const VideoCommon::SwizzleParameters> swizzles);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scheduler& scheduler;
|
||||||
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -449,7 +449,9 @@ void Scheduler::EndRenderPass()
|
|||||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||||
|
| VK_ACCESS_TRANSFER_READ_BIT
|
||||||
|
| VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
@@ -460,7 +462,7 @@ void Scheduler::EndRenderPass()
|
|||||||
}
|
}
|
||||||
cmdbuf.EndRenderPass();
|
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_TRANSFER,
|
||||||
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
||||||
if (has_transform_feedback) {
|
if (has_transform_feedback) {
|
||||||
static constexpr VkMemoryBarrier XFB_OUTPUT_BARRIER{
|
static constexpr VkMemoryBarrier XFB_OUTPUT_BARRIER{
|
||||||
|
|||||||
@@ -160,6 +160,55 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||||||
info.size.depth == 1;
|
info.size.depth == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] PixelFormat UnswizzleViewFormat(u32 bytes_per_block) {
|
||||||
|
switch (bytes_per_block) {
|
||||||
|
case 1:
|
||||||
|
return PixelFormat::R8_UINT;
|
||||||
|
case 2:
|
||||||
|
return PixelFormat::R16_UINT;
|
||||||
|
case 4:
|
||||||
|
return PixelFormat::R32_UINT;
|
||||||
|
case 8:
|
||||||
|
return PixelFormat::R32G32_UINT;
|
||||||
|
case 16:
|
||||||
|
return PixelFormat::R32G32B32A32_UINT;
|
||||||
|
default:
|
||||||
|
return PixelFormat::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr u32 UNSWIZZLE_WORKGROUP_INVOCATIONS = 32 * 32;
|
||||||
|
|
||||||
|
[[nodiscard]] bool SupportsAcceleratedUnswizzleDevice(const Device& device) {
|
||||||
|
return device.IsKhrImageFormatListSupported() &&
|
||||||
|
device.GetMaxComputeWorkGroupInvocations() >= UNSWIZZLE_WORKGROUP_INVOCATIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool SupportsAcceleratedUnswizzle(const Device& device, const ImageInfo& info) {
|
||||||
|
if (!SupportsAcceleratedUnswizzleDevice(device)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (info.num_samples > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (info.type != ImageType::e2D && info.type != ImageType::e3D &&
|
||||||
|
info.type != ImageType::Linear) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const PixelFormat view_format =
|
||||||
|
UnswizzleViewFormat(VideoCore::Surface::BytesPerBlock(info.format));
|
||||||
|
if (view_format == PixelFormat::Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!VideoCore::Surface::IsViewCompatible(info.format, view_format, false, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto host_format =
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, view_format);
|
||||||
|
return device.IsFormatSupported(host_format.format, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,
|
||||||
|
FormatType::Optimal);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info,
|
[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info,
|
||||||
std::optional<VkFormat> format_override = {}) {
|
std::optional<VkFormat> format_override = {}) {
|
||||||
auto format_info =
|
auto format_info =
|
||||||
@@ -248,8 +297,18 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||||||
return allocator.CreateImage(image_ci);
|
return allocator.CreateImage(image_ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkImageViewType StorageViewType(ImageType type) {
|
||||||
|
if (type == ImageType::e3D) {
|
||||||
|
return VK_IMAGE_VIEW_TYPE_3D;
|
||||||
|
}
|
||||||
|
if (type == ImageType::Linear) {
|
||||||
|
return VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
}
|
||||||
|
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image,
|
[[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image,
|
||||||
VkFormat format) {
|
VkFormat format, VkImageViewType view_type) {
|
||||||
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
|
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
@@ -260,7 +319,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
|
|||||||
.pNext = &storage_image_view_usage_create_info,
|
.pNext = &storage_image_view_usage_create_info,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.image = image,
|
.image = image,
|
||||||
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
.viewType = view_type,
|
||||||
.format = format,
|
.format = format,
|
||||||
.components{
|
.components{
|
||||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
@@ -658,18 +717,11 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
|
|||||||
.subresourceRange = subresource_range,
|
.subresourceRange = subresource_range,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
|
||||||
read_barrier);
|
read_barrier);
|
||||||
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
|
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
|
||||||
// TODO: Move this to another API
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0,
|
||||||
cmdbuf.PipelineBarrier(
|
nullptr, nullptr, write_barrier);
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
||||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
0, nullptr, nullptr, write_barrier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
|
[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
|
||||||
@@ -968,6 +1020,14 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
|||||||
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||||
staging_buffer_pool, compute_pass_descriptor_queue);
|
staging_buffer_pool, compute_pass_descriptor_queue);
|
||||||
}
|
}
|
||||||
|
if (SupportsAcceleratedUnswizzleDevice(device)) {
|
||||||
|
bl_unswizzle_2d_pass.emplace(device, scheduler, descriptor_pool,
|
||||||
|
compute_pass_descriptor_queue);
|
||||||
|
bl_unswizzle_image_3d_pass.emplace(device, scheduler, descriptor_pool,
|
||||||
|
compute_pass_descriptor_queue);
|
||||||
|
pitch_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
|
||||||
|
compute_pass_descriptor_queue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCacheRuntime::Finish() {
|
void TextureCacheRuntime::Finish() {
|
||||||
@@ -1902,16 +1962,12 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
|||||||
if (runtime->device.HasDebuggingToolAttached()) {
|
if (runtime->device.HasDebuggingToolAttached()) {
|
||||||
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
|
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
|
||||||
}
|
}
|
||||||
|
if (False(flags & VideoCommon::ImageFlagBits::Converted) &&
|
||||||
|
SupportsAcceleratedUnswizzle(runtime->device, info)) {
|
||||||
|
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||||
|
}
|
||||||
current_image = &Image::original_image;
|
current_image = &Image::original_image;
|
||||||
storage_image_views.resize(info.resources.levels);
|
storage_image_views.resize(info.resources.levels);
|
||||||
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
|
|
||||||
const auto& device = runtime->device.GetLogical();
|
|
||||||
const VkFormat storage_format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
|
||||||
for (s32 level = 0; level < info.resources.levels; ++level) {
|
|
||||||
storage_image_views[level] =
|
|
||||||
MakeStorageView(device, level, *original_image, storage_format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {}
|
Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {}
|
||||||
@@ -2321,16 +2377,39 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
|
|||||||
DownloadMemory(buffers, offsets, copies);
|
DownloadMemory(buffers, offsets, copies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<vk::ImageView>& Image::StorageViewsFor(vk::Image Image::*image) {
|
||||||
|
if (image == &Image::scaled_image) {
|
||||||
|
if (scaled_storage_image_views.empty()) {
|
||||||
|
scaled_storage_image_views.resize(info.resources.levels);
|
||||||
|
}
|
||||||
|
return scaled_storage_image_views;
|
||||||
|
}
|
||||||
|
return storage_image_views;
|
||||||
|
}
|
||||||
|
|
||||||
VkImageView Image::StorageImageView(s32 level) noexcept {
|
VkImageView Image::StorageImageView(s32 level) noexcept {
|
||||||
auto& view = storage_image_views[level];
|
const bool astc_decode = WillUseAcceleratedAstcDecode(runtime->device, info);
|
||||||
|
const bool unswizzle_upload =
|
||||||
|
!astc_decode && True(flags & ImageFlagBits::AcceleratedUpload);
|
||||||
|
vk::Image Image::*target = current_image;
|
||||||
|
if (astc_decode || unswizzle_upload) {
|
||||||
|
target = &Image::original_image;
|
||||||
|
}
|
||||||
|
auto& view = StorageViewsFor(target)[level];
|
||||||
if (!view) {
|
if (!view) {
|
||||||
auto format_info =
|
auto format_info =
|
||||||
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
|
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
|
||||||
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
|
if (astc_decode) {
|
||||||
format_info.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
format_info.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||||
}
|
}
|
||||||
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image),
|
if (unswizzle_upload) {
|
||||||
format_info.format);
|
const PixelFormat view_format =
|
||||||
|
UnswizzleViewFormat(VideoCore::Surface::BytesPerBlock(info.format));
|
||||||
|
format_info = MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, false,
|
||||||
|
view_format);
|
||||||
|
}
|
||||||
|
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*target),
|
||||||
|
format_info.format, StorageViewType(info.type));
|
||||||
}
|
}
|
||||||
return *view;
|
return *view;
|
||||||
}
|
}
|
||||||
@@ -2361,6 +2440,7 @@ bool Image::ScaleUp(bool ignore) {
|
|||||||
runtime->ViewFormats(info.format));
|
runtime->ViewFormats(info.format));
|
||||||
ignore = false;
|
ignore = false;
|
||||||
}
|
}
|
||||||
|
ignore = true;
|
||||||
current_image = &Image::scaled_image;
|
current_image = &Image::scaled_image;
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
return true;
|
return true;
|
||||||
@@ -2389,6 +2469,7 @@ bool Image::ScaleDown(bool ignore) {
|
|||||||
}
|
}
|
||||||
ASSERT(info.type != ImageType::Linear);
|
ASSERT(info.type != ImageType::Linear);
|
||||||
flags &= ~ImageFlagBits::Rescaled;
|
flags &= ~ImageFlagBits::Rescaled;
|
||||||
|
ignore = true;
|
||||||
current_image = &Image::original_image;
|
current_image = &Image::original_image;
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
return true;
|
return true;
|
||||||
@@ -3141,6 +3222,19 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
|||||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bl_unswizzle_2d_pass && image.info.type == ImageType::e2D) {
|
||||||
|
return bl_unswizzle_2d_pass->Unswizzle(image, map, swizzles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bl_unswizzle_image_3d_pass && image.info.type == ImageType::e3D &&
|
||||||
|
!IsPixelFormatBCn(image.info.format)) {
|
||||||
|
return bl_unswizzle_image_3d_pass->Unswizzle(image, map, swizzles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pitch_unswizzle_pass && image.info.type == ImageType::Linear) {
|
||||||
|
return pitch_unswizzle_pass->Unswizzle(image, map, swizzles);
|
||||||
|
}
|
||||||
|
|
||||||
if (!Settings::values.gpu_unswizzle_enabled.GetValue() || !bl3d_unswizzle_pass) {
|
if (!Settings::values.gpu_unswizzle_enabled.GetValue() || !bl3d_unswizzle_pass) {
|
||||||
if (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) {
|
if (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) {
|
||||||
ASSERT(false && "GPU unswizzle is disabled for BCn 3D texture");
|
ASSERT(false && "GPU unswizzle is disabled for BCn 3D texture");
|
||||||
|
|||||||
@@ -159,6 +159,9 @@ public:
|
|||||||
std::optional<ASTCDecoderPass> astc_decoder_pass;
|
std::optional<ASTCDecoderPass> astc_decoder_pass;
|
||||||
|
|
||||||
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
|
std::optional<BlockLinearUnswizzle3DPass> bl3d_unswizzle_pass;
|
||||||
|
std::optional<BlockLinearUnswizzle2DPass> bl_unswizzle_2d_pass;
|
||||||
|
std::optional<BlockLinearUnswizzleImage3DPass> bl_unswizzle_image_3d_pass;
|
||||||
|
std::optional<PitchUnswizzlePass> pitch_unswizzle_pass;
|
||||||
const Settings::ResolutionScalingInfo& resolution;
|
const Settings::ResolutionScalingInfo& resolution;
|
||||||
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
|
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
|
||||||
|
|
||||||
@@ -370,6 +373,8 @@ private:
|
|||||||
|
|
||||||
bool NeedsScaleHelper() const;
|
bool NeedsScaleHelper() const;
|
||||||
|
|
||||||
|
std::vector<vk::ImageView>& StorageViewsFor(vk::Image Image::*image);
|
||||||
|
|
||||||
Scheduler* scheduler{};
|
Scheduler* scheduler{};
|
||||||
TextureCacheRuntime* runtime{};
|
TextureCacheRuntime* runtime{};
|
||||||
|
|
||||||
@@ -387,6 +392,7 @@ private:
|
|||||||
vk::Image Image::*current_image{};
|
vk::Image Image::*current_image{};
|
||||||
|
|
||||||
std::vector<vk::ImageView> storage_image_views;
|
std::vector<vk::ImageView> storage_image_views;
|
||||||
|
std::vector<vk::ImageView> scaled_storage_image_views;
|
||||||
VkImageAspectFlags aspect_mask = 0;
|
VkImageAspectFlags aspect_mask = 0;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -23,8 +26,8 @@ struct BlockLinearSwizzle2DParams {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BlockLinearSwizzle3DParams {
|
struct BlockLinearSwizzle3DParams {
|
||||||
std::array<u32, 3> origin;
|
alignas(16) std::array<u32, 3> origin;
|
||||||
std::array<s32, 3> destination;
|
alignas(16) std::array<s32, 3> destination;
|
||||||
u32 bytes_per_block_log2;
|
u32 bytes_per_block_log2;
|
||||||
u32 slice_size;
|
u32 slice_size;
|
||||||
u32 block_size;
|
u32 block_size;
|
||||||
|
|||||||
@@ -279,11 +279,11 @@ void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) {
|
|||||||
|
|
||||||
const ImageId view_image_id = slot_image_views[view.id].image_id;
|
const ImageId view_image_id = slot_image_views[view.id].image_id;
|
||||||
{
|
{
|
||||||
bool is_continue = false;
|
bool is_feedback = false;
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
is_continue |= (rt_active_mask & (1u << i)) && view_image_id == rt_image_id[i];
|
is_feedback |= (rt_active_mask & (1u << i)) && view_image_id == rt_image_id[i];
|
||||||
if (is_continue)
|
if (is_feedback)
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
if (depth_active && view_image_id == rt_depth_image_id) {
|
if (depth_active && view_image_id == rt_depth_image_id) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -354,6 +354,7 @@ public:
|
|||||||
|
|
||||||
#define FN_MAX_LIMIT_LIST \
|
#define FN_MAX_LIMIT_LIST \
|
||||||
FN_MAX_LIMIT_ELEM(ComputeSharedMemorySize) \
|
FN_MAX_LIMIT_ELEM(ComputeSharedMemorySize) \
|
||||||
|
FN_MAX_LIMIT_ELEM(ComputeWorkGroupInvocations) \
|
||||||
FN_MAX_LIMIT_ELEM(PerStageDescriptorSampledImages) \
|
FN_MAX_LIMIT_ELEM(PerStageDescriptorSampledImages) \
|
||||||
FN_MAX_LIMIT_ELEM(PerStageResources) \
|
FN_MAX_LIMIT_ELEM(PerStageResources) \
|
||||||
FN_MAX_LIMIT_ELEM(DescriptorSetSamplers) \
|
FN_MAX_LIMIT_ELEM(DescriptorSetSamplers) \
|
||||||
|
|||||||
Reference in New Issue
Block a user