vk_pipeline_cache: Add fallbacks for R8Srgb and B5G6R5 (#3264)

* vk_pipeline_cache: Add fallbacks for R8Srgb and B5G6R5

* blit_helper: Fix validation error

* renderer_vulkan: Emulate B5G6R5 with swizzle
This commit is contained in:
TheTurtle 2025-07-18 12:25:07 +03:00 committed by GitHub
parent 3019bfb978
commit b56039b15a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 39 additions and 32 deletions

View File

@ -171,6 +171,7 @@ enum class MrtSwizzle : u8 {
static constexpr u32 MaxColorBuffers = 8;
struct PsColorBuffer {
AmdGpu::DataFormat data_format : 6;
AmdGpu::NumberFormat num_format : 4;
AmdGpu::NumberConversion num_conversion : 3;
AmdGpu::Liverpool::ShaderExportFormat export_format : 4;

View File

@ -248,6 +248,15 @@ constexpr CompMapping RemapSwizzle(const DataFormat format, const CompMapping sw
result.a = swizzle.r;
return result;
}
case DataFormat::Format5_6_5: {
// Remap to a more supported component order.
CompMapping result;
result.r = swizzle.b;
result.g = swizzle.g;
result.b = swizzle.r;
result.a = swizzle.a;
return result;
}
default:
return swizzle;
}

View File

@ -671,7 +671,7 @@ std::span<const SurfaceFormatInfo> SurfaceFormats() {
vk::Format::eR32G32B32A32Sfloat),
// 5_6_5
CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format5_6_5, AmdGpu::NumberFormat::Unorm,
vk::Format::eB5G6R5UnormPack16),
vk::Format::eR5G6B5UnormPack16),
// 1_5_5_5
CreateSurfaceFormatInfo(AmdGpu::DataFormat::Format1_5_5_5, AmdGpu::NumberFormat::Unorm,
vk::Format::eA1R5G5B5UnormPack16),

View File

@ -244,9 +244,24 @@ GraphicsPipeline::GraphicsPipeline(
const auto depth_format =
instance.GetSupportedFormat(LiverpoolToVK::DepthFormat(key.z_format, key.stencil_format),
vk::FormatFeatureFlagBits2::eDepthStencilAttachment);
std::array<vk::Format, Shader::IR::NumRenderTargets> color_formats;
for (s32 i = 0; i < key.num_color_attachments; ++i) {
const auto& col_buf = key.color_buffers[i];
const auto format = LiverpoolToVK::SurfaceFormat(col_buf.data_format, col_buf.num_format);
const auto color_format =
instance.GetSupportedFormat(format, vk::FormatFeatureFlagBits2::eColorAttachment);
if (!instance.IsFormatSupported(color_format,
vk::FormatFeatureFlagBits2::eColorAttachment)) {
LOG_WARNING(Render_Vulkan,
"color buffer format {} does not support COLOR_ATTACHMENT_BIT",
vk::to_string(color_format));
}
color_formats[i] = color_format;
}
const vk::PipelineRenderingCreateInfo pipeline_rendering_ci = {
.colorAttachmentCount = key.num_color_attachments,
.pColorAttachmentFormats = key.color_formats.data(),
.pColorAttachmentFormats = color_formats.data(),
.depthAttachmentFormat = key.z_format != Liverpool::DepthBuffer::ZFormat::Invalid
? depth_format
: vk::Format::eUndefined,

View File

@ -36,7 +36,6 @@ struct GraphicsPipelineKey {
std::array<vk::Format, MaxVertexBufferCount> vertex_buffer_formats;
u32 patch_control_points;
u32 num_color_attachments;
std::array<vk::Format, Liverpool::NumColorBuffers> color_formats;
std::array<Shader::PsColorBuffer, Liverpool::NumColorBuffers> color_buffers;
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;

View File

@ -669,6 +669,12 @@ vk::Format Instance::GetSupportedFormat(const vk::Format format,
if (IsFormatSupported(vk::Format::eD32SfloatS8Uint, flags)) {
return vk::Format::eD32SfloatS8Uint;
}
break;
case vk::Format::eR8Srgb:
if (IsFormatSupported(vk::Format::eR8Unorm, flags)) {
return vk::Format::eR8Unorm;
}
break;
default:
break;
}

View File

@ -315,7 +315,6 @@ bool PipelineCache::RefreshGraphicsKey() {
// attachments. This might be not a case as HW color buffers can be bound in an arbitrary
// order. We need to do some arrays compaction at this stage
key.num_color_attachments = 0;
key.color_formats.fill(vk::Format::eUndefined);
key.color_buffers.fill({});
key.blend_controls.fill({});
key.write_masks.fill({});
@ -351,16 +350,8 @@ bool PipelineCache::RefreshGraphicsKey() {
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8 ||
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8_8_8);
const auto format =
LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
key.color_formats[remapped_cb] = format;
if (!instance.IsFormatSupported(format, vk::FormatFeatureFlagBits2::eColorAttachment)) {
LOG_WARNING(Render_Vulkan,
"color buffer format {} does not support COLOR_ATTACHMENT_BIT",
vk::to_string(format));
}
key.color_buffers[remapped_cb] = Shader::PsColorBuffer{
.data_format = col_buf.GetDataFmt(),
.num_format = col_buf.GetNumberFmt(),
.num_conversion = col_buf.GetNumberConversion(),
.export_format = regs.color_export_format.GetFormat(cb),
@ -479,9 +470,7 @@ bool PipelineCache::RefreshGraphicsKey() {
// Attachment is masked out by either color_target_mask or shader mrt_mask. In the case
// of the latter we need to change format to undefined, and either way we need to
// increment the index for the null attachment binding.
key.color_formats[remapped_cb] = vk::Format::eUndefined;
key.color_buffers[remapped_cb] = {};
++remapped_cb;
key.color_buffers[remapped_cb++] = {};
continue;
}

View File

@ -126,13 +126,13 @@ void BlitHelper::BlitColorToMsDepth(Image& source, Image& dest) {
.minDepth = 0.f,
.maxDepth = 1.f,
};
cmdbuf.setViewport(0, viewport);
cmdbuf.setViewportWithCount(viewport);
const vk::Rect2D scissor = {
.offset = {0, 0},
.extent = {state.width, state.height},
};
cmdbuf.setScissor(0, scissor);
cmdbuf.setScissorWithCount(scissor);
cmdbuf.draw(3, 1, 0, 0);

View File

@ -21,7 +21,7 @@ static vk::ImageUsageFlags ImageUsageFlags(const ImageInfo& info) {
if (info.IsDepthStencil()) {
usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
} else {
if (!info.IsBlockCoded() && !info.IsPacked()) {
if (!info.IsBlockCoded()) {
usage |= vk::ImageUsageFlagBits::eColorAttachment;
}
// In cases where an image is created as a render/depth target and cleared with compute,

View File

@ -176,17 +176,6 @@ bool ImageInfo::IsBlockCoded() const {
}
}
bool ImageInfo::IsPacked() const {
switch (pixel_format) {
case vk::Format::eB5G5R5A1UnormPack16:
[[fallthrough]];
case vk::Format::eB5G6R5UnormPack16:
return true;
default:
return false;
}
}
bool ImageInfo::IsDepthStencil() const {
switch (pixel_format) {
case vk::Format::eD16Unorm:

View File

@ -31,7 +31,6 @@ struct ImageInfo {
}
bool IsBlockCoded() const;
bool IsPacked() const;
bool IsDepthStencil() const;
bool HasStencil() const;

View File

@ -626,7 +626,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
image_copy.push_back({
.bufferOffset = mip.offset,
.bufferRowLength = mip_pitch,
.bufferImageHeight = mip_height,
.bufferImageHeight = mip_height ? std::max(mip_height, 8U) : mip_height,
.imageSubresource{
.aspectMask = image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil,
.mipLevel = m,