Browse Source

[TEST] Added another MSAA depth stencil shaders to convert into non msaa + sanitize MSAA UINT/SINT path

android-meows
CamilleLaVey 1 day ago
parent
commit
945d5c373b
  1. 2
      src/video_core/host_shaders/CMakeLists.txt
  2. 20
      src/video_core/host_shaders/convert_msaa_to_non_msaa_depth.frag
  3. 23
      src/video_core/host_shaders/convert_msaa_to_non_msaa_depth_stencil.frag
  4. 29
      src/video_core/renderer_vulkan/blit_image.cpp
  5. 5
      src/video_core/renderer_vulkan/blit_image.h
  6. 10
      src/video_core/renderer_vulkan/vk_rasterizer.cpp
  7. 76
      src/video_core/renderer_vulkan/vk_texture_cache.cpp
  8. 10
      src/video_core/vulkan_common/vulkan_device.h

2
src/video_core/host_shaders/CMakeLists.txt

@ -33,6 +33,8 @@ set(SHADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/convert_float_to_depth.frag
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.comp
${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

20
src/video_core/host_shaders/convert_msaa_to_non_msaa_depth.frag

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#version 450 core
layout(binding = 0) uniform sampler2DMS msaa_in;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
ivec2 src_offset;
ivec2 scale;
};
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;
gl_FragDepth = texelFetch(msaa_in, msaa_coord, sample_id).r;
}

23
src/video_core/host_shaders/convert_msaa_to_non_msaa_depth_stencil.frag

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#version 450 core
#extension GL_ARB_shader_stencil_export : require
layout(binding = 0) uniform sampler2DMS depth_tex;
layout(binding = 1) uniform usampler2DMS stencil_tex;
layout(push_constant) uniform PushConstants {
ivec2 dst_offset;
ivec2 src_offset;
ivec2 scale;
};
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;
gl_FragDepth = texelFetch(depth_tex, msaa_coord, sample_id).r;
gl_FragStencilRefARB = int(texelFetch(stencil_tex, msaa_coord, sample_id).r);
}

29
src/video_core/renderer_vulkan/blit_image.cpp

@ -22,6 +22,8 @@
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
#include "video_core/host_shaders/convert_msaa_to_non_msaa_frag_spv.h"
#include "video_core/host_shaders/convert_msaa_to_non_msaa_depth_frag_spv.h"
#include "video_core/host_shaders/convert_msaa_to_non_msaa_depth_stencil_frag_spv.h"
#include "video_core/host_shaders/convert_msaa_to_non_msaa_sint_frag_spv.h"
#include "video_core/host_shaders/convert_msaa_to_non_msaa_uint_frag_spv.h"
#include "video_core/host_shaders/convert_non_msaa_to_msaa_frag_spv.h"
@ -636,6 +638,10 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_SINT_FRAG_SPV)),
convert_msaa_to_non_msaa_uint_frag(
BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_UINT_FRAG_SPV)),
convert_msaa_to_non_msaa_depth_frag(
BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_DEPTH_FRAG_SPV)),
convert_msaa_to_non_msaa_depth_stencil_frag(
BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_DEPTH_STENCIL_FRAG_SPV)),
convert_non_msaa_to_msaa_frag(BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_FRAG_SPV)),
convert_non_msaa_to_msaa_sint_frag(
BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_SINT_FRAG_SPV)),
@ -1606,14 +1612,15 @@ void BlitImageHelper::CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage
VideoCore::Surface::PixelFormat dst_format, VkImage src_image,
VideoCore::Surface::PixelFormat src_format, u32 num_samples,
std::span<const VideoCommon::ImageCopy> copies,
bool copy_stencil) {
bool copy_stencil, bool msaa_to_non_msaa) {
while (!msaa_copy_resources.empty() && scheduler.IsFree(msaa_copy_resources.front().tick)) {
msaa_copy_resources.pop_front();
}
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(static_cast<int>(num_samples));
const s32 scale_x = 1 << samples_x;
const s32 scale_y = 1 << samples_y;
const VkSampleCountFlagBits samples = SampleCountFlag(num_samples);
const VkSampleCountFlagBits samples =
msaa_to_non_msaa ? VK_SAMPLE_COUNT_1_BIT : SampleCountFlag(num_samples);
RenderPassKey renderpass_key{};
renderpass_key.color_formats.fill(VideoCore::Surface::PixelFormat::Invalid);
renderpass_key.depth_format = dst_format;
@ -1622,7 +1629,7 @@ void BlitImageHelper::CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage
const MSAACopyPipelineKey key{
.renderpass = renderpass,
.samples = samples,
.msaa_to_non_msaa = false,
.msaa_to_non_msaa = msaa_to_non_msaa,
.format_class = MSAACopyFormatClass::Float,
};
const VkPipeline pipeline = FindOrEmplaceMSAACopyDepthPipeline(key, copy_stencil);
@ -1859,16 +1866,22 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyDepthPipeline(const MSAACopyPip
return *pipelines[std::distance(keys.begin(), it)];
}
keys.push_back(key);
const std::array stages =
MakeStages(*clear_color_vert, copy_stencil ? *convert_non_msaa_to_msaa_depth_stencil_frag
: *convert_non_msaa_to_msaa_depth_frag);
VkShaderModule frag_module;
if (key.msaa_to_non_msaa) {
frag_module = copy_stencil ? *convert_msaa_to_non_msaa_depth_stencil_frag
: *convert_msaa_to_non_msaa_depth_frag;
} else {
frag_module = copy_stencil ? *convert_non_msaa_to_msaa_depth_stencil_frag
: *convert_non_msaa_to_msaa_depth_frag;
}
const std::array stages = MakeStages(*clear_color_vert, frag_module);
const VkPipelineMultisampleStateCreateInfo multisample_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.rasterizationSamples = key.samples,
.sampleShadingEnable = VK_TRUE,
.minSampleShading = 1.0f,
.sampleShadingEnable = key.msaa_to_non_msaa ? VK_FALSE : VK_TRUE,
.minSampleShading = key.msaa_to_non_msaa ? 0.0f : 1.0f,
.pSampleMask = nullptr,
.alphaToCoverageEnable = VK_FALSE,
.alphaToOneEnable = VK_FALSE,

5
src/video_core/renderer_vulkan/blit_image.h

@ -132,7 +132,8 @@ public:
void CopyMSAADepth(RenderPassCache& render_pass_cache, VkImage dst_image,
VideoCore::Surface::PixelFormat dst_format, VkImage src_image,
VideoCore::Surface::PixelFormat src_format, u32 num_samples,
std::span<const VideoCommon::ImageCopy> copies, bool copy_stencil);
std::span<const VideoCommon::ImageCopy> copies, bool copy_stencil,
bool msaa_to_non_msaa);
private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
@ -207,6 +208,8 @@ private:
vk::ShaderModule convert_msaa_to_non_msaa_frag;
vk::ShaderModule convert_msaa_to_non_msaa_sint_frag;
vk::ShaderModule convert_msaa_to_non_msaa_uint_frag;
vk::ShaderModule convert_msaa_to_non_msaa_depth_frag;
vk::ShaderModule convert_msaa_to_non_msaa_depth_stencil_frag;
vk::ShaderModule convert_non_msaa_to_msaa_frag;
vk::ShaderModule convert_non_msaa_to_msaa_sint_frag;
vk::ShaderModule convert_non_msaa_to_msaa_uint_frag;

10
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -854,12 +854,10 @@ void RasterizerVulkan::WaitForIdle() {
// fragment shaders can still write storage buffers.
VkPipelineStageFlags flags =
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
if (device.SupportsTessellationShader()) {
flags |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
}
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
if (device.SupportsGeometryShader()) {
flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
}

76
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -1749,8 +1749,20 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
return;
}
}
if (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT ||
VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) {
const VkImageAspectFlags dst_aspect_mask = dst.AspectMask();
if ((dst_aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
const bool copies_stencil = (dst_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
device.IsExtShaderStencilExportSupported();
if ((dst_aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 && !copies_stencil) {
UNIMPLEMENTED_MSG("Copying images with different samples is not supported.");
return;
}
blit_image_helper.CopyMSAADepth(render_pass_cache, dst.Handle(), dst.info.format,
src.Handle(), src.info.format, num_samples, copies,
copies_stencil, msaa_to_non_msaa);
return;
}
if ((dst_aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) == 0) {
UNIMPLEMENTED_MSG("Copying images with different samples is not supported.");
return;
}
@ -1767,7 +1779,17 @@ u64 TextureCacheRuntime::GetDeviceMemoryUsage() const {
}
bool TextureCacheRuntime::CanDownloadMsaa(const VideoCommon::ImageInfo& info) const {
return ImageAspectMask(info.format) == VK_IMAGE_ASPECT_COLOR_BIT;
const VkImageAspectFlags aspect_mask = ImageAspectMask(info.format);
if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
return true;
}
if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) == 0) {
return false;
}
if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
return device.IsExtShaderStencilExportSupported();
}
return true;
}
bool TextureCacheRuntime::CanReportMemoryUsage() const {
@ -1953,7 +1975,7 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
runtime->blit_image_helper.CopyMSAADepth(runtime->render_pass_cache, Handle(),
info.format, temp_vk_image, info.format,
info.num_samples, image_copies,
msaa_upload_copies_stencil);
msaa_upload_copies_stencil, false);
} else {
runtime->blit_image_helper.CopyMSAA(runtime->render_pass_cache, Handle(), info.format,
temp_vk_image, info.format, info.num_samples,
@ -2024,33 +2046,53 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
image_ci.format =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format)
.format;
image_ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
const bool msaa_download_is_depth =
(aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
const bool msaa_download_copies_stencil =
msaa_download_is_depth && (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
runtime->device.IsExtShaderStencilExportSupported();
image_ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if (msaa_download_is_depth) {
image_ci.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
} else {
image_ci.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci);
const VkImage temp_vk_image = *temp_image;
const VkImageAspectFlags temp_aspect_mask = aspect_mask;
const VkAccessFlags attachment_access =
msaa_download_is_depth ? (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)
: (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
const VkPipelineStageFlags attachment_stage =
msaa_download_is_depth ? (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)
: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
scheduler->RequestOutsideRenderPassOperationContext();
scheduler->Record([temp_vk_image](vk::CommandBuffer cmdbuf) {
scheduler->Record([temp_vk_image, temp_aspect_mask, attachment_access,
attachment_stage](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier init_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = attachment_access,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = temp_vk_image,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.aspectMask = temp_aspect_mask,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, attachment_stage, 0,
init_barrier);
});
@ -2065,9 +2107,15 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
image_copies.push_back(image_copy);
}
runtime->blit_image_helper.CopyMSAA(runtime->render_pass_cache, temp_vk_image,
info.format, Handle(), info.format,
info.num_samples, image_copies, true);
if (msaa_download_is_depth) {
runtime->blit_image_helper.CopyMSAADepth(
runtime->render_pass_cache, temp_vk_image, info.format, Handle(), info.format,
info.num_samples, image_copies, msaa_download_copies_stencil, true);
} else {
runtime->blit_image_helper.CopyMSAA(runtime->render_pass_cache, temp_vk_image,
info.format, Handle(), info.format,
info.num_samples, image_copies, true);
}
boost::container::small_vector<VkBuffer, 8> buffers_vector{};
boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8>

10
src/video_core/vulkan_common/vulkan_device.h

@ -1023,25 +1023,19 @@ FN_MAX_LIMIT_LIST
return features2.features.multiViewport;
}
bool SupportsTessellationShader() const {
return features2.features.tessellationShader;
}
bool SupportsGeometryShader() const {
return features2.features.geometryShader;
}
VkPipelineStageFlags AttachmentConsumerStages() const {
VkPipelineStageFlags stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
if (features2.features.tessellationShader) {
stages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
}
if (features2.features.geometryShader) {
stages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
}

Loading…
Cancel
Save