[TEST] Adjustments on MSAA

This commit is contained in:
CamilleLaVey
2026-08-22 02:49:06 -04:00
parent 9f776cfca7
commit b0b4817162
13 changed files with 128 additions and 135 deletions
@@ -295,7 +295,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) {
break;
}
if (zbc_used_color_entries >= zbc_table_size) {
if (zbc_used_color_entries >= ZBC_TABLE_SIZE) {
LOG_WARNING(Service_NVDRV, "ZBCSetTable: color table is full, fmt={:#x}",
params.format);
return NvResult::InsufficientMemory;
@@ -324,7 +324,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) {
break;
}
if (zbc_used_depth_entries >= zbc_table_size) {
if (zbc_used_depth_entries >= ZBC_TABLE_SIZE) {
LOG_WARNING(Service_NVDRV, "ZBCSetTable: depth table is full, fmt={:#x}",
depth_entry.format);
return NvResult::InsufficientMemory;
@@ -350,32 +350,41 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) {
std::scoped_lock lk(zbc_mutex);
if (params.type == 0) {
params.index_size = zbc_table_size;
params.index_size = ZBC_TABLE_SIZE;
return NvResult::Success;
}
if (params.index_size >= zbc_table_size) {
LOG_ERROR(Service_NVDRV, "ZBCQueryTable: invalid index {:#x}", params.index_size);
return NvResult::BadParameter;
}
switch (static_cast<ZBCTypes>(params.type)) {
case ZBCTypes::color: {
if (params.index_size >= zbc_used_color_entries) {
LOG_ERROR(Service_NVDRV, "ZBCQueryTable: invalid color index {:#x}",
params.index_size);
return NvResult::BadParameter;
}
const auto& colors = zbc_colors[params.index_size];
std::copy_n(colors.color_ds.begin(), colors.color_ds.size(), std::begin(params.color_ds));
std::copy_n(colors.color_l2.begin(), colors.color_l2.size(), std::begin(params.color_l2));
params.depth = 0;
params.ref_cnt = colors.ref_cnt;
params.format = colors.format;
params.index_size = zbc_used_color_entries;
break;
}
case ZBCTypes::depth: {
if (params.index_size >= zbc_used_depth_entries) {
LOG_ERROR(Service_NVDRV, "ZBCQueryTable: invalid depth index {:#x}",
params.index_size);
return NvResult::BadParameter;
}
const auto& depth_entry = zbc_depths[params.index_size];
std::fill(std::begin(params.color_ds), std::end(params.color_ds), 0);
std::fill(std::begin(params.color_l2), std::end(params.color_l2), 0);
params.depth = depth_entry.depth;
params.ref_cnt = depth_entry.ref_cnt;
params.format = depth_entry.format;
params.index_size = zbc_used_depth_entries;
break;
}
}
+38 -4
View File
@@ -35,12 +35,8 @@ set(SHADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa_depth.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa_depth_stencil.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa_sint.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa_uint.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.comp
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa_sint.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa_uint.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa_depth.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa_depth_stencil.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_s8d24_to_abgr8.frag
@@ -174,6 +170,44 @@ foreach(SOURCE_FILE IN ITEMS ${SHADER_FILES})
endif()
endforeach()
# Integer variants of the MSAA conversion shaders. They only differ from the float
# source in the sampler and output types, so they are generated from it via defines.
set(SHADER_TYPE_VARIANTS
"convert_msaa_to_non_msaa.frag|sint|isampler2DMS|ivec4"
"convert_msaa_to_non_msaa.frag|uint|usampler2DMS|uvec4"
"convert_non_msaa_to_msaa.frag|sint|isampler2D|ivec4"
"convert_non_msaa_to_msaa.frag|uint|usampler2D|uvec4"
)
foreach(VARIANT IN ITEMS ${SHADER_TYPE_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_SAMPLER)
list(GET VARIANT_PARTS 3 VARIANT_TEXEL)
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}
-DSAMPLER_TYPE=${VARIANT_SAMPLER} -DTEXEL_TYPE=${VARIANT_TEXEL}
--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})
@@ -3,7 +3,14 @@
#version 450 core
layout(binding = 0) uniform sampler2DMS msaa_in;
#ifndef SAMPLER_TYPE
#define SAMPLER_TYPE sampler2DMS
#endif
#ifndef TEXEL_TYPE
#define TEXEL_TYPE vec4
#endif
layout(binding = 0) uniform SAMPLER_TYPE msaa_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
@@ -11,7 +18,7 @@ layout(push_constant) uniform PushConstants {
ivec2 scale;
};
layout(location = 0) out vec4 frag_color;
layout(location = 0) out TEXEL_TYPE frag_color;
void main() {
const ivec2 coord = ivec2(gl_FragCoord.xy) - dst_offset + src_offset;
@@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#version 450 core
layout(binding = 0) uniform isampler2DMS msaa_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
ivec2 src_offset;
ivec2 scale;
};
layout(location = 0) out ivec4 frag_color;
void main() {
const ivec2 coord = ivec2(gl_FragCoord.xy) - dst_offset + src_offset;
const ivec2 msaa_coord = coord / scale;
const ivec2 sample_offset = coord % scale;
const int sample_id = sample_offset.x + scale.x * sample_offset.y;
frag_color = texelFetch(msaa_in, msaa_coord, sample_id);
}
@@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#version 450 core
layout(binding = 0) uniform usampler2DMS msaa_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
ivec2 src_offset;
ivec2 scale;
};
layout(location = 0) out uvec4 frag_color;
void main() {
const ivec2 coord = ivec2(gl_FragCoord.xy) - dst_offset + src_offset;
const ivec2 msaa_coord = coord / scale;
const ivec2 sample_offset = coord % scale;
const int sample_id = sample_offset.x + scale.x * sample_offset.y;
frag_color = texelFetch(msaa_in, msaa_coord, sample_id);
}
@@ -3,7 +3,14 @@
#version 450 core
layout(binding = 0) uniform sampler2D img_in;
#ifndef SAMPLER_TYPE
#define SAMPLER_TYPE sampler2D
#endif
#ifndef TEXEL_TYPE
#define TEXEL_TYPE vec4
#endif
layout(binding = 0) uniform SAMPLER_TYPE img_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
@@ -11,7 +18,7 @@ layout(push_constant) uniform PushConstants {
ivec2 scale;
};
layout(location = 0) out vec4 frag_color;
layout(location = 0) out TEXEL_TYPE frag_color;
void main() {
const ivec2 msaa_coord = ivec2(gl_FragCoord.xy) - dst_offset;
@@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#version 450 core
layout(binding = 0) uniform isampler2D img_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
ivec2 src_offset;
ivec2 scale;
};
layout(location = 0) out ivec4 frag_color;
void main() {
const ivec2 msaa_coord = ivec2(gl_FragCoord.xy) - dst_offset;
const ivec2 sample_offset = ivec2(gl_SampleID % scale.x, gl_SampleID / scale.x);
const ivec2 coord = msaa_coord * scale + sample_offset + src_offset;
frag_color = texelFetch(img_in, coord, 0);
}
@@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#version 450 core
layout(binding = 0) uniform usampler2D img_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
ivec2 src_offset;
ivec2 scale;
};
layout(location = 0) out uvec4 frag_color;
void main() {
const ivec2 msaa_coord = ivec2(gl_FragCoord.xy) - dst_offset;
const ivec2 sample_offset = ivec2(gl_SampleID % scale.x, gl_SampleID / scale.x);
const ivec2 coord = msaa_coord * scale + sample_offset + src_offset;
frag_color = texelFetch(img_in, coord, 0);
}
@@ -1815,6 +1815,7 @@ void BlitImageHelper::CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage
}
}
}
scheduler.InvalidateState();
}
VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key) {
@@ -615,7 +615,6 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, 0, image_barrier);
});
scheduler.Finish();
}
constexpr u32 BL3D_BINDING_INPUT_BUFFER = 0;
@@ -720,17 +719,14 @@ void BlockLinearUnswizzle3DPass::Unswizzle(
const u32 blocks_x = (image.info.size.width + 3) / 4;
const u32 blocks_y = (image.info.size.height + 3) / 4;
const bool is_initialized = image.ExchangeInitialization();
scheduler.RequestOutsideRenderPassOperationContext();
for (u32 z_offset = 0; z_offset < z_count; z_offset += MAX_BATCH_SLICES) {
const u32 current_chunk_slices = (std::min)(MAX_BATCH_SLICES, z_count - z_offset);
const u32 current_z_start = z_start + z_offset;
UnswizzleChunk(image, swizzled, sw, params, blocks_x, blocks_y,
current_z_start, current_chunk_slices, is_initialized);
current_z_start, current_chunk_slices);
}
scheduler.Finish();
}
void BlockLinearUnswizzle3DPass::UnswizzleChunk(
@@ -739,7 +735,7 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
const VideoCommon::SwizzleParameters& sw,
const BlockLinearSwizzle3DParams& params,
u32 blocks_x, u32 blocks_y,
u32 z_start, u32 z_count, bool is_initialized)
u32 z_start, u32 z_count)
{
BlockLinearUnswizzle3DPushConstants pc{};
pc.origin[0] = params.origin[0];
@@ -783,7 +779,6 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
const VkDeviceSize barrier_size = output_slice_size * z_count;
const bool is_first_chunk = (z_start == 0);
const bool use_undefined_layout = !is_initialized && is_first_chunk;
const VkBuffer out_buffer = *image.compute_unswizzle_buffer;
const VkImage dst_image = image.Handle();
@@ -792,7 +787,7 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
const u32 image_height = image.info.size.height;
scheduler.Record([this, set, descriptor_data, pc, gx, gy, gz, z_start, z_count,
barrier_size, use_undefined_layout, out_buffer, dst_image, aspect,
barrier_size, is_first_chunk, out_buffer, dst_image, aspect,
image_width, image_height
](vk::CommandBuffer cmdbuf) {
@@ -819,23 +814,14 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
.size = barrier_size,
};
VkAccessFlags pre_barrier_src_access = VK_ACCESS_SHADER_READ_BIT;
VkImageLayout pre_barrier_old_layout = VK_IMAGE_LAYOUT_GENERAL;
VkPipelineStageFlags pre_barrier_src_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
if (use_undefined_layout) {
pre_barrier_src_access = VkAccessFlags{};
pre_barrier_old_layout = VK_IMAGE_LAYOUT_UNDEFINED;
pre_barrier_src_stages |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
} else {
pre_barrier_src_stages |= vk::PIPELINE_STAGE_GRAPHICS_COMPUTE;
}
const VkImageMemoryBarrier pre_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = pre_barrier_src_access,
.srcAccessMask = is_first_chunk ? VkAccessFlags{} :
static_cast<VkAccessFlags>(VK_ACCESS_TRANSFER_WRITE_BIT),
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = pre_barrier_old_layout,
.oldLayout = is_first_chunk ? VK_IMAGE_LAYOUT_UNDEFINED :
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@@ -845,7 +831,7 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
// Single barrier handles both buffer and image
cmdbuf.PipelineBarrier(
pre_barrier_src_stages,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
nullptr, buffer_barrier, pre_barrier
@@ -1122,7 +1108,6 @@ void BlockLinearUnswizzle2DPass::Unswizzle(
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
0, {}, {}, post_copy);
});
scheduler.Finish();
}
namespace {
@@ -1374,7 +1359,6 @@ void BlockLinearUnswizzle3DBufferPass::Unswizzle(
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
0, {}, {}, post_copy);
});
scheduler.Finish();
}
} // namespace Vulkan
@@ -156,7 +156,7 @@ public:
const VideoCommon::SwizzleParameters& sw,
const BlockLinearSwizzle3DParams& params,
u32 blocks_x, u32 blocks_y,
u32 z_start, u32 z_count, bool is_initialized);
u32 z_start, u32 z_count);
private:
Scheduler& scheduler;
@@ -229,6 +229,18 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
.preserveAttachmentCount = 0,
.pPreserveAttachments = nullptr,
};
const VkSubpassDependency feedback_loop_dependency{
.srcSubpass = 0,
.dstSubpass = 0,
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
};
const VkSubpassDependency counter_resume_dependency{
.srcSubpass = 0,
.dstSubpass = 0,
@@ -324,6 +336,23 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
counter_resume_dependency2.srcAccessMask = 0;
counter_resume_dependency2.dstAccessMask = 0;
}
const VkSubpassDependency2 feedback_loop_dependency2{
.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
.pNext = nullptr,
.srcSubpass = feedback_loop_dependency.srcSubpass,
.dstSubpass = feedback_loop_dependency.dstSubpass,
.srcStageMask = feedback_loop_dependency.srcStageMask,
.dstStageMask = feedback_loop_dependency.dstStageMask,
.srcAccessMask = feedback_loop_dependency.srcAccessMask,
.dstAccessMask = feedback_loop_dependency.dstAccessMask,
.dependencyFlags = feedback_loop_dependency.dependencyFlags,
.viewOffset = 0,
};
boost::container::static_vector<VkSubpassDependency2, 2> dependencies2{
feedback_loop_dependency2};
if (can_resume_transform_feedback) {
dependencies2.push_back(counter_resume_dependency2);
}
pair->second = device->GetLogical().CreateRenderPass2({
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,
.pNext = nullptr,
@@ -332,14 +361,18 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
.pAttachments = descriptions2.empty() ? nullptr : descriptions2.data(),
.subpassCount = 1,
.pSubpasses = &subpass2,
.dependencyCount = can_resume_transform_feedback ? 1u : 0u,
.pDependencies = can_resume_transform_feedback ? &counter_resume_dependency2 : nullptr,
.dependencyCount = static_cast<u32>(dependencies2.size()),
.pDependencies = dependencies2.data(),
.correlatedViewMaskCount = 0,
.pCorrelatedViewMasks = nullptr,
});
return *pair->second;
}
boost::container::static_vector<VkSubpassDependency, 2> dependencies{feedback_loop_dependency};
if (can_resume_transform_feedback) {
dependencies.push_back(counter_resume_dependency);
}
pair->second = device->GetLogical().CreateRenderPass({
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.pNext = nullptr,
@@ -348,8 +381,8 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
.pAttachments = descriptions.empty() ? nullptr : descriptions.data(),
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = can_resume_transform_feedback ? 1u : 0u,
.pDependencies = can_resume_transform_feedback ? &counter_resume_dependency : nullptr,
.dependencyCount = static_cast<u32>(dependencies.size()),
.pDependencies = dependencies.data(),
});
return *pair->second;
}
+8 -4
View File
@@ -279,11 +279,12 @@ void TextureCache<P>::CheckFeedbackLoop(std::span<const ImageViewInOut> views) {
const ImageId view_image_id = slot_image_views[view.id].image_id;
{
bool is_continue = false;
bool aliases_color_rt = false;
for (size_t i = 0; i < 8; ++i)
is_continue |= (rt_active_mask & (1u << i)) && view_image_id == rt_image_id[i];
if (is_continue)
continue;
aliases_color_rt |=
(rt_active_mask & (1u << i)) && view_image_id == rt_image_id[i];
if (aliases_color_rt)
return true;
}
if (depth_active && view_image_id == rt_depth_image_id) {
return true;
@@ -1710,6 +1711,9 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
if (!overlap.IsSafeGpuCopy()) {
continue;
}
if (overlap.info.num_samples != new_image.info.num_samples) {
continue;
}
const auto alias_pointer = join_alias_indices.find(copy_object.id);
if (alias_pointer == join_alias_indices.end()) {
continue;