Compare commits

..

4 Commits

Author SHA1 Message Date
xbzk cea858f8fc [fs] debug_knobs controlled delay (us) for IStorage::Read 2026-08-25 22:35:04 -03:00
xbzk 926cc3185f [settings] make debug_knobs per-game wise 2026-08-25 22:35:04 -03:00
xbzk cc62c5644e [android] Expose log filter setting 2026-08-25 22:35:04 -03:00
xbzk d81579ba51 [core] Add compact guest backtrace decoder 2026-08-25 22:35:04 -03:00
21 changed files with 250 additions and 547 deletions
@@ -11,6 +11,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
enum class StringSetting(override val key: String) : AbstractStringSetting {
DRIVER_PATH("driver_path"),
DEVICE_NAME("device_name"),
LOG_FILTER("log_filter"),
PROGRAM_ARGS("program_args"),
WEB_TOKEN("eden_token"),
@@ -1032,6 +1032,13 @@ abstract class SettingsItem(
descriptionId = R.string.use_auto_stub_description
)
)
put(
StringInputSetting(
StringSetting.LOG_FILTER,
titleId = R.string.log_filter,
descriptionId = R.string.log_filter_description
)
)
put(
SpinBoxSetting(
ShortSetting.DEBUG_KNOBS,
@@ -1322,6 +1322,7 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.log))
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
add(StringSetting.LOG_FILTER.key)
}
add(HeaderSetting(R.string.general))
@@ -636,6 +636,8 @@
<string name="log">Logging</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="log_filter">Log filter</string>
<string name="log_filter_description">Controls Eden\'s log categories. Example: *:Info Service.LM:Debug</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">GPU Logging</string>
+4 -4
View File
@@ -224,7 +224,7 @@ struct ColorConsoleBackend final : public Backend {
auto const df = GetDirectFormatArgs(entry);
// more restrictive, because take for example this simple prelude:
// [ 50.872256] Config <Info> common/settings.cpp:142:LogSettings:
char buffer[256];
char buffer[128];
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(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) {
if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) {
auto const flush = ::Settings::values.log_flush_line.GetValue();
char buffer[BUFSIZ];
auto result = fmt::vformat_to_n(buffer, sizeof(buffer) - 1, format, args);
buffer[(std::min)(result.size, sizeof(buffer) - 1)] = '\0';
buffer[result.size] = '\0';
auto const flush = ::Settings::values.log_flush_line.GetValue();
logging_instance->ForEachBackend([=](Backend& backend) {
backend.Write(Entry{
.message = buffer,
.message_len = (std::min)(result.size, sizeof(buffer) - 1),
.message_len = (std::min)(sizeof(buffer) - 1, result.size),
.timestamp = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - logging_instance->time_origin),
.log_class = log_class,
.log_level = log_level,
+5 -3
View File
@@ -132,9 +132,11 @@ void LogSettings() {
}
}
}
LOG_INFO(Config, "Eden Configuration:");
std::string settings_str{};
for (auto const& e : settings_list)
LOG_INFO(Config, "{}", e);
settings_str += e;
LOG_INFO(Config, "Eden Configuration:\n{}", settings_str);
#define LOG_PATH(NAME) \
LOG_INFO(Config, #NAME ": {}", Common::FS::PathToUTF8String(Common::FS::GetEdenPath(Common::FS::EdenPath::NAME)))
LOG_PATH(CacheDir);
@@ -369,7 +371,7 @@ void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info)
}
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.active = true;
info.active = info.up_scale != 1 || info.down_shift != 0;
}
void UpdateRescalingInfo() {
+1 -1
View File
@@ -904,7 +904,7 @@ struct Values {
0,
65535,
"debug_knobs",
Category::Debugging,
Category::System,
Specialization::Countable,
true,
true};
+182 -14
View File
@@ -3,14 +3,158 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// 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 "core/arm/arm_interface.h"
#include "core/arm/debug.h"
#include "core/core.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc_types.h"
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 {
Kernel::Svc::ThreadContext ctx;
this->GetContext(ctx);
@@ -26,21 +170,45 @@ void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
ctx.r[28], ctx.fp, ctx.lr, ctx.sp,
};
std::string msg = fmt::format("Backtrace @ PC={:016X}\n", ctx.pc);
for (size_t i = 0; i < 32; i += 4)
msg += fmt::format("R{:02}={:016X} R{:02}={:016X} R{:02}={:016X} R{:02}={:016X}\n",
i + 0, xreg[i + 0], i + 1, xreg[i + 1],
i + 2, xreg[i + 2], i + 3, xreg[i + 3]);
for (size_t i = 0; i < 32; i += 2)
msg += fmt::format("V{:02}={:016X}_{:016X} V{:02}={:016X}_{:016X}\n",
i + 0, ctx.v[i + 0][0], ctx.v[i + 0][1],
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);
msg += fmt::format("{:20}{:20}{:20}{:20}{}\n", "Module", "Address", "Original Address", "Offset", "Symbol");
LOG_ERROR(Core_ARM,
"Guest backtrace context: process=\"{}\" pid={} program_id={:016X} pc={:016X} "
"lr={:016X} fp={:016X} sp={:016X} pstate={:08X}",
process->GetName(), process->GetProcessId(), process->GetProgramId(), ctx.pc,
ctx.lr, ctx.fp, ctx.sp, ctx.pstate);
std::vector<u64> logged_strings;
for (size_t i = 0; i < xreg.size(); i++) {
LogGuestStringCandidate(process, xreg[i], fmt::format("R{:02}", i), logged_strings);
}
LogStackStringCandidates(process, ctx.sp, "SP", logged_strings);
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);
for (auto const& entry : backtrace)
msg += fmt::format("{:20}{:016X} {:016X} {:016X} {}\n", entry.module, entry.address, entry.original_address, entry.offset, entry.name);
LOG_ERROR(Core_ARM, "{}", msg);
for (size_t i = 0; i < std::min(backtrace.size(), MaxBacktraceFrames); i++) {
const auto& entry = backtrace[i];
if (entry.original_address == 0) {
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(
@@ -3,6 +3,9 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono>
#include <thread>
#include "common/settings.h"
#include "core/file_sys/errors.h"
#include "core/hle/service/cmif_serialization.h"
@@ -30,6 +33,15 @@ Result IStorage::Read(
R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
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
backend->Read(out_bytes.data(), length, offset);
@@ -206,40 +206,6 @@ foreach(VARIANT IN ITEMS ${SHADER_TYPE_VARIANTS})
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
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})
get_filename_component(FILENAME ${FILEPATH} NAME)
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
@@ -5,13 +5,9 @@
#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_8bit_storage : require
#endif
#define HAS_EXTENDED_TYPES 1
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS };
#define UNIFORM(n)
@@ -5,13 +5,9 @@
#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_8bit_storage : require
#endif
#define HAS_EXTENDED_TYPES 1
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS };
#define UNIFORM(n)
@@ -5,13 +5,9 @@
#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_8bit_storage : require
#endif
#define HAS_EXTENDED_TYPES 1
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS };
#define UNIFORM(n)
@@ -22,13 +22,7 @@
#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_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_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/surface.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
@@ -878,291 +872,4 @@ 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
@@ -164,49 +164,4 @@ private:
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
@@ -449,9 +449,7 @@ void Scheduler::EndRenderPass()
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
| VK_ACCESS_TRANSFER_READ_BIT
| VK_ACCESS_TRANSFER_WRITE_BIT,
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@@ -462,7 +460,7 @@ void Scheduler::EndRenderPass()
}
cmdbuf.EndRenderPass();
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_TRANSFER,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
if (has_transform_feedback) {
static constexpr VkMemoryBarrier XFB_OUTPUT_BARRIER{
@@ -160,55 +160,6 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
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,
std::optional<VkFormat> format_override = {}) {
auto format_info =
@@ -297,18 +248,8 @@ constexpr u32 UNSWIZZLE_WORKGROUP_INVOCATIONS = 32 * 32;
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,
VkFormat format, VkImageViewType view_type) {
VkFormat format) {
static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr,
@@ -319,7 +260,7 @@ constexpr u32 UNSWIZZLE_WORKGROUP_INVOCATIONS = 32 * 32;
.pNext = &storage_image_view_usage_create_info,
.flags = 0,
.image = image,
.viewType = view_type,
.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
.format = format,
.components{
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
@@ -717,11 +658,18 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
.subresourceRange = subresource_range,
};
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
read_barrier);
cmdbuf.CopyBufferToImage(src_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copies);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0,
nullptr, nullptr, write_barrier);
// TODO: Move this to another API
cmdbuf.PipelineBarrier(
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,
@@ -1020,14 +968,6 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
bl3d_unswizzle_pass.emplace(device, scheduler, descriptor_pool,
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() {
@@ -1962,12 +1902,16 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
if (runtime->device.HasDebuggingToolAttached()) {
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;
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} {}
@@ -2377,39 +2321,16 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
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 {
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];
auto& view = storage_image_views[level];
if (!view) {
auto format_info =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
if (astc_decode) {
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
format_info.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
}
if (unswizzle_upload) {
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));
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image),
format_info.format);
}
return *view;
}
@@ -2440,7 +2361,6 @@ bool Image::ScaleUp(bool ignore) {
runtime->ViewFormats(info.format));
ignore = false;
}
ignore = true;
current_image = &Image::scaled_image;
if (ignore) {
return true;
@@ -2469,7 +2389,6 @@ bool Image::ScaleDown(bool ignore) {
}
ASSERT(info.type != ImageType::Linear);
flags &= ~ImageFlagBits::Rescaled;
ignore = true;
current_image = &Image::original_image;
if (ignore) {
return true;
@@ -3222,19 +3141,6 @@ void TextureCacheRuntime::AccelerateImageUpload(
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 (IsPixelFormatBCn(image.info.format) && image.info.type == ImageType::e3D) {
ASSERT(false && "GPU unswizzle is disabled for BCn 3D texture");
@@ -159,9 +159,6 @@ public:
std::optional<ASTCDecoderPass> astc_decoder_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;
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
@@ -373,8 +370,6 @@ private:
bool NeedsScaleHelper() const;
std::vector<vk::ImageView>& StorageViewsFor(vk::Image Image::*image);
Scheduler* scheduler{};
TextureCacheRuntime* runtime{};
@@ -392,7 +387,6 @@ private:
vk::Image Image::*current_image{};
std::vector<vk::ImageView> storage_image_views;
std::vector<vk::ImageView> scaled_storage_image_views;
VkImageAspectFlags aspect_mask = 0;
bool initialized = false;
@@ -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-License-Identifier: GPL-2.0-or-later
@@ -26,8 +23,8 @@ struct BlockLinearSwizzle2DParams {
};
struct BlockLinearSwizzle3DParams {
alignas(16) std::array<u32, 3> origin;
alignas(16) std::array<s32, 3> destination;
std::array<u32, 3> origin;
std::array<s32, 3> destination;
u32 bytes_per_block_log2;
u32 slice_size;
u32 block_size;
+4 -4
View File
@@ -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;
{
bool is_feedback = false;
bool is_continue = false;
for (size_t i = 0; i < 8; ++i)
is_feedback |= (rt_active_mask & (1u << i)) && view_image_id == rt_image_id[i];
if (is_feedback)
return true;
is_continue |= (rt_active_mask & (1u << i)) && view_image_id == rt_image_id[i];
if (is_continue)
continue;
}
if (depth_active && view_image_id == rt_depth_image_id) {
return true;
@@ -354,7 +354,6 @@ public:
#define FN_MAX_LIMIT_LIST \
FN_MAX_LIMIT_ELEM(ComputeSharedMemorySize) \
FN_MAX_LIMIT_ELEM(ComputeWorkGroupInvocations) \
FN_MAX_LIMIT_ELEM(PerStageDescriptorSampledImages) \
FN_MAX_LIMIT_ELEM(PerStageResources) \
FN_MAX_LIMIT_ELEM(DescriptorSetSamplers) \