renderer_vulkan: Gracefully handle lack of MSAA support (#2779)

* renderer_vulkan: Update `IsMultiSampleSupported` to check for `shaderStorageImageMultisample`

`shaderStorageImageMultisample` is required for the reinterpretation compute shaders in particular and should be part of the main MSAA requirement for now.

* renderer_vulkan: Conditionally create multisample compute shaders based on MSAA support

These shaders should not be compiled on systems that do not support `shaderStorageImageMultisample`. Some systems, such as newer Intel iGPUs, seem to gracefully handle compiling these compute shaders despite not supporting `shaderStorageImageMultisample`. Other drivers such as Mobile GPUs, will have the entire compute pipeline compilation fail.

* renderer_vulkan: Allow hardware-accelerated reinterpretations to fail

Propagate blit-helper results to `TextureRuntime::Reinterpret` return value. Allows a slow-path reinterpretation to be done in the case of backend failure.
This commit is contained in:
Wunk authored and GitHub committed 2026-11-06 19:32:58 +01:00
1 parent 1dfc9ed1b3
commit 6b4e7f2e69
4 files changed
+45 -42

No files matched your search

@@ -194,16 +194,15 @@ bool TextureRuntime::Reinterpret(Surface& source, Surface& dest,
ASSERT_MSG(src_format != dst_format, "Reinterpretation with the same format is invalid");
if (src_format == PixelFormat::D24S8 && dst_format == PixelFormat::RGBA8) {
blit_helper.ConvertDS24S8ToRGBA8(source, dest, copy);
return blit_helper.ConvertDS24S8ToRGBA8(source, dest, copy);
} else if (src_format == PixelFormat::RGBA4 && dst_format == PixelFormat::RGB5A1) {
blit_helper.ConvertRGBA4ToRGB5A1(source, dest, copy);
} else {
LOG_WARNING(Render_OpenGL, "Unimplemented reinterpretation {}({:#x}) -> {}({:#x})",
VideoCore::PixelFormatAsString(src_format), source.Tuple().internal_format,
VideoCore::PixelFormatAsString(dst_format), dest.Tuple().internal_format);
return false;
return blit_helper.ConvertRGBA4ToRGB5A1(source, dest, copy);
}
return true;
LOG_WARNING(Render_OpenGL, "Unimplemented reinterpretation {}({:#x}) -> {}({:#x})",
VideoCore::PixelFormatAsString(src_format), source.Tuple().internal_format,
VideoCore::PixelFormatAsString(dst_format), dest.Tuple().internal_format);
return false;
}
bool TextureRuntime::ClearTextureWithoutFbo(Surface& surface,
@@ -249,10 +249,10 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_,
vk::ShaderStageFlagBits::eVertex, device)},
d24s8_to_rgba8_comp{Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_COMP,
vk::ShaderStageFlagBits::eCompute, device)},
#if !defined(__APPLE__)
d24s8_to_rgba8_ms_comp{Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_MS_COMP,
vk::ShaderStageFlagBits::eCompute, device)},
#endif
d24s8_to_rgba8_ms_comp{instance_.IsMultiSampleSupported()
? Compile(HostShaders::VULKAN_D24S8_TO_RGBA8_MS_COMP,
vk::ShaderStageFlagBits::eCompute, device)
: VK_NULL_HANDLE},
depth_to_buffer_comp{Compile(HostShaders::VULKAN_DEPTH_TO_BUFFER_COMP,
vk::ShaderStageFlagBits::eCompute, device)},
blit_depth_stencil_frag{VK_NULL_HANDLE},
@@ -265,10 +265,10 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_,
mmpx_frag{Compile(HostShaders::MMPX_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
refine_frag{Compile(HostShaders::REFINE_FRAG, vk::ShaderStageFlagBits::eFragment, device)},
d24s8_to_rgba8_pipeline{MakeComputePipeline(d24s8_to_rgba8_comp, compute_pipeline_layout)},
#if !defined(__APPLE__)
d24s8_to_rgba8_ms_pipeline{
MakeComputePipeline(d24s8_to_rgba8_ms_comp, compute_pipeline_layout)},
#endif
instance_.IsMultiSampleSupported()
? MakeComputePipeline(d24s8_to_rgba8_ms_comp, compute_pipeline_layout)
: VK_NULL_HANDLE},
depth_to_buffer_pipeline{
MakeComputePipeline(depth_to_buffer_comp, compute_buffer_pipeline_layout)},
depth_blit_pipeline{VK_NULL_HANDLE},
@@ -293,17 +293,18 @@ BlitHelper::BlitHelper(const Instance& instance_, Scheduler& scheduler_,
"BlitHelper: three_textures_pipeline_layout");
SetObjectName(device, full_screen_vert, "BlitHelper: full_screen_vert");
SetObjectName(device, d24s8_to_rgba8_comp, "BlitHelper: d24s8_to_rgba8_comp");
#if !defined(__APPLE__)
SetObjectName(device, d24s8_to_rgba8_ms_comp, "BlitHelper: d24s8_to_rgba8_ms_comp");
#endif
if (d24s8_to_rgba8_ms_comp) {
SetObjectName(device, d24s8_to_rgba8_ms_comp, "BlitHelper: d24s8_to_rgba8_ms_comp");
}
SetObjectName(device, depth_to_buffer_comp, "BlitHelper: depth_to_buffer_comp");
if (blit_depth_stencil_frag) {
SetObjectName(device, blit_depth_stencil_frag, "BlitHelper: blit_depth_stencil_frag");
}
SetObjectName(device, d24s8_to_rgba8_pipeline, "BlitHelper: d24s8_to_rgba8_pipeline");
#if !defined(__APPLE__)
SetObjectName(device, d24s8_to_rgba8_ms_pipeline, "BlitHelper: d24s8_to_rgba8_ms_pipeline");
#endif
if (d24s8_to_rgba8_ms_pipeline) {
SetObjectName(device, d24s8_to_rgba8_ms_pipeline,
"BlitHelper: d24s8_to_rgba8_ms_pipeline");
}
SetObjectName(device, depth_to_buffer_pipeline, "BlitHelper: depth_to_buffer_pipeline");
if (depth_blit_pipeline) {
SetObjectName(device, depth_blit_pipeline, "BlitHelper: depth_blit_pipeline");
@@ -325,9 +326,9 @@ BlitHelper::~BlitHelper() {
device.destroyPipelineLayout(three_textures_pipeline_layout);
device.destroyShaderModule(full_screen_vert);
device.destroyShaderModule(d24s8_to_rgba8_comp);
#if !defined(__APPLE__)
device.destroyShaderModule(d24s8_to_rgba8_ms_comp);
#endif
if (d24s8_to_rgba8_ms_comp) {
device.destroyShaderModule(d24s8_to_rgba8_ms_comp);
}
device.destroyShaderModule(depth_to_buffer_comp);
if (blit_depth_stencil_frag) {
device.destroyShaderModule(blit_depth_stencil_frag);
@@ -340,9 +341,9 @@ BlitHelper::~BlitHelper() {
device.destroyShaderModule(refine_frag);
device.destroyPipeline(depth_to_buffer_pipeline);
device.destroyPipeline(d24s8_to_rgba8_pipeline);
#if !defined(__APPLE__)
device.destroyPipeline(d24s8_to_rgba8_ms_pipeline);
#endif
if (d24s8_to_rgba8_ms_pipeline) {
device.destroyPipeline(d24s8_to_rgba8_ms_pipeline);
}
device.destroyPipeline(depth_blit_pipeline);
device.destroySampler(linear_sampler);
device.destroySampler(nearest_sampler);
@@ -425,11 +426,13 @@ bool BlitHelper::ConvertDS24S8ToRGBA8(Surface& source, Surface& dest,
const bool multisample = (source.sample_count > 1) && (dest.sample_count > 1);
const Type src_type = multisample ? Type::MultiSampled : Type::Current;
#if !defined(__APPLE__)
if (multisample && !instance.IsMultiSampleSupported()) {
LOG_ERROR(Render_Vulkan,
"Multisampled DS24S8->RGBA8 conversion is not supported on this device");
return false;
}
const auto pipeline = multisample ? d24s8_to_rgba8_ms_pipeline : d24s8_to_rgba8_pipeline;
#else
const auto pipeline = d24s8_to_rgba8_pipeline;
#endif
const auto descriptor_set = compute_provider.Commit();
update_queue.AddImageSampler(descriptor_set, 0, 0, source.ImageView(ViewType::Depth, src_type),
@@ -917,8 +920,8 @@ void BlitHelper::FilterPass(Surface& surface, vk::Pipeline pipeline, vk::Pipelin
FILTER_PUSH_CONSTANT_RANGE.offset, FILTER_PUSH_CONSTANT_RANGE.size,
&push_constants);
// Set up viewport and scissor for filtering (don't use BindBlitState as it overwrites push
// constants)
// Set up viewport and scissor for filtering (don't use BindBlitState as it overwrites
// push constants)
const vk::Offset2D offset{
.x = std::min<s32>(blit.dst_rect.left, blit.dst_rect.right),
.y = std::min<s32>(blit.dst_rect.bottom, blit.dst_rect.top),
+4 -2
View File
@@ -256,9 +256,11 @@ public:
return triangle_fan_supported;
}
// Returns true when sampleRateShading, VK_KHR_create_renderpass2, VK_KHR_depth_stencil_resolve
// Returns true when shaderStorageImageMultisample, sampleRateShading,
// VK_KHR_create_renderpass2, VK_KHR_depth_stencil_resolve
bool IsMultiSampleSupported() const {
return features.sampleRateShading && create_renderpass2 && depth_stencil_resolve;
return features.shaderStorageImageMultisample && features.sampleRateShading &&
create_renderpass2 && depth_stencil_resolve;
}
/// Returns true if dynamic indices can be used inside shaders.
@@ -339,14 +339,13 @@ bool TextureRuntime::Reinterpret(Surface& source, Surface& dest,
}
if (src_format == PixelFormat::D24S8 && dst_format == PixelFormat::RGBA8) {
blit_helper.ConvertDS24S8ToRGBA8(source, dest, copy);
} else {
LOG_WARNING(Render_Vulkan, "Unimplemented reinterpretation {}({}) -> {}({})",
VideoCore::PixelFormatAsString(src_format), vk::to_string(source.traits.native),
VideoCore::PixelFormatAsString(dst_format), vk::to_string(dest.traits.native));
return false;
return blit_helper.ConvertDS24S8ToRGBA8(source, dest, copy);
}
return true;
LOG_WARNING(Render_Vulkan, "Unimplemented reinterpretation {}({}) -> {}({})",
VideoCore::PixelFormatAsString(src_format), vk::to_string(source.traits.native),
VideoCore::PixelFormatAsString(dst_format), vk::to_string(dest.traits.native));
return false;
}
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {