rasterizer: Add multi-sampled surfaces

Vulkan implementation only
This commit is contained in:
Wunkolo 2023-11-10 17:55:28 -08:00
parent 82e9f4ca03
commit c091457984
4 changed files with 61 additions and 27 deletions

View file

@ -273,6 +273,7 @@ bool RasterizerCache<T>::AccelerateDisplayTransfer(const Pica::DisplayTransferCo
src_params.height = config.output_height; src_params.height = config.output_height;
src_params.is_tiled = !config.input_linear; src_params.is_tiled = !config.input_linear;
src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.input_format); src_params.pixel_format = PixelFormatFromGPUPixelFormat(config.input_format);
src_params.sample_count = sample_count;
src_params.UpdateParams(); src_params.UpdateParams();
SurfaceParams dst_params; SurfaceParams dst_params;
@ -283,6 +284,7 @@ bool RasterizerCache<T>::AccelerateDisplayTransfer(const Pica::DisplayTransferCo
: config.output_height.Value(); : config.output_height.Value();
dst_params.is_tiled = config.input_linear != config.dont_swizzle; dst_params.is_tiled = config.input_linear != config.dont_swizzle;
dst_params.pixel_format = PixelFormatFromGPUPixelFormat(config.output_format); dst_params.pixel_format = PixelFormatFromGPUPixelFormat(config.output_format);
dst_params.sample_count = sample_count;
dst_params.UpdateParams(); dst_params.UpdateParams();
// Using flip_vertically alongside crop_input_lines produces skewed output on hardware. // Using flip_vertically alongside crop_input_lines produces skewed output on hardware.
@ -556,6 +558,7 @@ SurfaceId RasterizerCache<T>::GetTextureSurface(const Pica::Texture::TextureInfo
params.is_tiled = true; params.is_tiled = true;
params.pixel_format = PixelFormatFromTextureFormat(info.format); params.pixel_format = PixelFormatFromTextureFormat(info.format);
params.res_scale = filter != Settings::TextureFilter::None ? resolution_scale_factor : 1; params.res_scale = filter != Settings::TextureFilter::None ? resolution_scale_factor : 1;
params.sample_count = max_level == 0 ? sample_count : 1;
params.UpdateParams(); params.UpdateParams();
const u32 min_width = info.width >> max_level; const u32 min_width = info.width >> max_level;
@ -683,6 +686,7 @@ FramebufferHelper<T> RasterizerCache<T>::GetFramebufferSurfaces(bool using_color
SurfaceParams color_params; SurfaceParams color_params;
color_params.is_tiled = true; color_params.is_tiled = true;
color_params.res_scale = resolution_scale_factor; color_params.res_scale = resolution_scale_factor;
color_params.sample_count = sample_count;
color_params.width = config.GetWidth(); color_params.width = config.GetWidth();
color_params.height = config.GetHeight(); color_params.height = config.GetHeight();
SurfaceParams depth_params = color_params; SurfaceParams depth_params = color_params;

View file

@ -71,6 +71,10 @@ public:
return height * res_scale; return height * res_scale;
} }
[[nodiscard]] u8 GetSampleCount() const noexcept {
return sample_count;
}
[[nodiscard]] Common::Rectangle<u32> GetRect(u32 level = 0) const noexcept { [[nodiscard]] Common::Rectangle<u32> GetRect(u32 level = 0) const noexcept {
return {0, height >> level, width >> level, 0}; return {0, height >> level, width >> level, 0};
} }
@ -104,6 +108,7 @@ public:
u32 stride = 0; u32 stride = 0;
u32 levels = 1; u32 levels = 1;
u32 res_scale = 1; u32 res_scale = 1;
u8 sample_count = 1;
bool is_tiled = false; bool is_tiled = false;
TextureType texture_type = TextureType::Texture2D; TextureType texture_type = TextureType::Texture2D;

View file

@ -144,8 +144,8 @@ boost::container::small_vector<vk::ImageMemoryBarrier, 3> MakeInitBarriers(
} }
Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, TextureType type, Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, TextureType type,
vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags flags, vk::Format format, vk::SampleCountFlagBits samples, vk::ImageUsageFlags usage,
vk::ImageAspectFlags aspect, bool need_format_list, vk::ImageCreateFlags flags, vk::ImageAspectFlags aspect, bool need_format_list,
std::string_view debug_name = {}) { std::string_view debug_name = {}) {
const u32 layers = type == TextureType::CubeMap ? 6 : 1; const u32 layers = type == TextureType::CubeMap ? 6 : 1;
@ -166,7 +166,7 @@ Handle MakeHandle(const Instance* instance, u32 width, u32 height, u32 levels, T
.extent = {width, height, 1}, .extent = {width, height, 1},
.mipLevels = levels, .mipLevels = levels,
.arrayLayers = layers, .arrayLayers = layers,
.samples = vk::SampleCountFlagBits::e1, .samples = samples,
.usage = usage, .usage = usage,
}; };
@ -311,7 +311,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
.aspect = surface.Aspect(), .aspect = surface.Aspect(),
.pipeline_flags = surface.PipelineStageFlags(), .pipeline_flags = surface.PipelineStageFlags(),
.src_access = surface.AccessFlags(), .src_access = surface.AccessFlags(),
.src_image = surface.Image(), .src_image = surface.GetSampleCount() > 1 ? surface.Image(3) : surface.Image(),
}; };
if (clear.texture_rect == surface.GetScaledRect()) { if (clear.texture_rect == surface.GetScaledRect()) {
@ -377,7 +377,8 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
const auto color_format = is_color ? surface.pixel_format : PixelFormat::Invalid; const auto color_format = is_color ? surface.pixel_format : PixelFormat::Invalid;
const auto depth_format = is_color ? PixelFormat::Invalid : surface.pixel_format; const auto depth_format = is_color ? PixelFormat::Invalid : surface.pixel_format;
const auto render_pass = renderpass_cache.GetRenderpass(color_format, depth_format, true); const auto render_pass =
renderpass_cache.GetRenderpass(color_format, depth_format, true, surface.GetSampleCount());
const RecordParams params = { const RecordParams params = {
.aspect = surface.Aspect(), .aspect = surface.Aspect(),
@ -432,13 +433,14 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
}; };
const auto clear_value = MakeClearValue(clear.value); const auto clear_value = MakeClearValue(clear.value);
std::array<vk::ClearValue, 2> clear_values = {clear_value, clear_value};
const vk::RenderPassBeginInfo renderpass_begin_info = { const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = render_pass, .renderPass = render_pass,
.framebuffer = framebuffer, .framebuffer = framebuffer,
.renderArea = render_area, .renderArea = render_area,
.clearValueCount = 1, .clearValueCount = 2,
.pClearValues = &clear_value, .pClearValues = clear_values.data(),
}; };
cmdbuf.pipelineBarrier(params.pipeline_flags, pipeline_flags, cmdbuf.pipelineBarrier(params.pipeline_flags, pipeline_flags,
@ -725,18 +727,29 @@ Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& param
flags |= vk::ImageCreateFlagBits::eMutableFormat; flags |= vk::ImageCreateFlagBits::eMutableFormat;
} }
// Native image
const bool need_format_list = is_mutable && instance->IsImageFormatListSupported(); const bool need_format_list = is_mutable && instance->IsImageFormatListSupported();
handles[0] = MakeHandle(instance, width, height, levels, texture_type, format, traits.usage, handles[0] = MakeHandle(instance, width, height, levels, texture_type, format,
flags, traits.aspect, need_format_list, DebugName(false)); vk::SampleCountFlagBits::e1, traits.usage, flags, traits.aspect,
need_format_list, DebugName(false));
raw_images.emplace_back(handles[0].image); raw_images.emplace_back(handles[0].image);
// Upscaled image
if (res_scale != 1) { if (res_scale != 1) {
handles[1] = handles[1] = MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type,
MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type, format, format, vk::SampleCountFlagBits::e1, traits.usage, flags,
traits.usage, flags, traits.aspect, need_format_list, DebugName(true)); traits.aspect, need_format_list, DebugName(true));
raw_images.emplace_back(handles[1].image); raw_images.emplace_back(handles[1].image);
} }
// Upscales+MSAA image
if (vk::SampleCountFlagBits(sample_count) > vk::SampleCountFlagBits::e1) {
handles[3] = MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type,
format, vk::SampleCountFlagBits(sample_count), traits.usage, flags,
traits.aspect, need_format_list, DebugName(true));
raw_images.emplace_back(handles[3].image);
}
runtime->renderpass_cache.EndRendering(); runtime->renderpass_cache.EndRendering();
scheduler->Record([raw_images, aspect = traits.aspect](vk::CommandBuffer cmdbuf) { scheduler->Record([raw_images, aspect = traits.aspect](vk::CommandBuffer cmdbuf) {
const auto barriers = MakeInitBarriers(aspect, raw_images); const auto barriers = MakeInitBarriers(aspect, raw_images);
@ -757,7 +770,7 @@ Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceBase& surface
const bool has_normal = mat && mat->Map(MapType::Normal); const bool has_normal = mat && mat->Map(MapType::Normal);
const vk::Format format = traits.native; const vk::Format format = traits.native;
boost::container::static_vector<vk::Image, 2> raw_images; boost::container::static_vector<vk::Image, 4> raw_images;
vk::ImageCreateFlags flags{}; vk::ImageCreateFlags flags{};
if (texture_type == VideoCore::TextureType::CubeMap) { if (texture_type == VideoCore::TextureType::CubeMap) {
@ -766,18 +779,26 @@ Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceBase& surface
const std::string debug_name = DebugName(false, true); const std::string debug_name = DebugName(false, true);
handles[0] = MakeHandle(instance, mat->width, mat->height, levels, texture_type, format, handles[0] = MakeHandle(instance, mat->width, mat->height, levels, texture_type, format,
traits.usage, flags, traits.aspect, false, debug_name); vk::SampleCountFlagBits::e1, traits.usage, flags, traits.aspect, false,
debug_name);
raw_images.emplace_back(handles[0].image); raw_images.emplace_back(handles[0].image);
if (res_scale != 1) { if (res_scale != 1) {
handles[1] = MakeHandle(instance, mat->width, mat->height, levels, texture_type, handles[1] = MakeHandle(instance, mat->width, mat->height, levels, texture_type,
vk::Format::eR8G8B8A8Unorm, traits.usage, flags, traits.aspect, vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1,
false, debug_name); traits.usage, flags, traits.aspect, false, debug_name);
raw_images.emplace_back(handles[1].image); raw_images.emplace_back(handles[1].image);
} }
if (vk::SampleCountFlagBits(sample_count) > vk::SampleCountFlagBits::e1) {
handles[3] = MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type,
format, vk::SampleCountFlagBits(sample_count), traits.usage, flags,
traits.aspect, false, debug_name);
raw_images.emplace_back(handles[3].image);
}
if (has_normal) { if (has_normal) {
handles[2] = MakeHandle(instance, mat->width, mat->height, levels, texture_type, format, handles[2] = MakeHandle(instance, mat->width, mat->height, levels, texture_type, format,
traits.usage, flags, traits.aspect, false, debug_name); vk::SampleCountFlagBits::e1, traits.usage, flags, traits.aspect,
false, debug_name);
raw_images.emplace_back(handles[2].image); raw_images.emplace_back(handles[2].image);
} }
@ -1076,9 +1097,9 @@ void Surface::ScaleUp(u32 new_scale) {
flags |= vk::ImageCreateFlagBits::eMutableFormat; flags |= vk::ImageCreateFlagBits::eMutableFormat;
} }
handles[1] = handles[1] = MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type,
MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type, traits.native, vk::SampleCountFlagBits::e1, traits.usage, flags,
traits.native, traits.usage, flags, traits.aspect, false, DebugName(true)); traits.aspect, false, DebugName(true));
runtime->renderpass_cache.EndRendering(); runtime->renderpass_cache.EndRendering();
scheduler->Record( scheduler->Record(
@ -1152,9 +1173,9 @@ vk::ImageView Surface::CopyImageView() noexcept {
if (texture_type == VideoCore::TextureType::CubeMap) { if (texture_type == VideoCore::TextureType::CubeMap) {
flags |= vk::ImageCreateFlagBits::eCubeCompatible; flags |= vk::ImageCreateFlagBits::eCubeCompatible;
} }
copy_handle = copy_handle = MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels,
MakeHandle(instance, GetScaledWidth(), GetScaledHeight(), levels, texture_type, texture_type, traits.native, vk::SampleCountFlagBits::e1,
traits.native, traits.usage, flags, traits.aspect, false); traits.usage, flags, traits.aspect, false);
copy_layout = vk::ImageLayout::eUndefined; copy_layout = vk::ImageLayout::eUndefined;
} }
@ -1346,8 +1367,12 @@ vk::Framebuffer Surface::Framebuffer() noexcept {
const auto color_format = is_depth ? PixelFormat::Invalid : pixel_format; const auto color_format = is_depth ? PixelFormat::Invalid : pixel_format;
const auto depth_format = is_depth ? pixel_format : PixelFormat::Invalid; const auto depth_format = is_depth ? pixel_format : PixelFormat::Invalid;
const auto render_pass = const auto render_pass =
runtime->renderpass_cache.GetRenderpass(color_format, depth_format, false); runtime->renderpass_cache.GetRenderpass(color_format, depth_format, false, sample_count);
const auto attachments = std::array{ImageView()}; boost::container::static_vector<vk::ImageView, 2> attachments;
attachments.emplace_back(ImageView());
if (sample_count > 1) {
attachments.emplace_back(ImageView(3));
}
framebuffers[index] = MakeFramebuffer(instance->GetDevice(), render_pass, GetScaledWidth(), framebuffers[index] = MakeFramebuffer(instance->GetDevice(), render_pass, GetScaledWidth(),
GetScaledHeight(), attachments); GetScaledHeight(), attachments);
return framebuffers[index].get(); return framebuffers[index].get();

View file

@ -181,8 +181,8 @@ public:
const Instance* instance; const Instance* instance;
Scheduler* scheduler; Scheduler* scheduler;
FormatTraits traits; FormatTraits traits;
std::array<Handle, 3> handles{}; std::array<Handle, 4> handles{};
std::array<vk::UniqueFramebuffer, 2> framebuffers{}; std::array<vk::UniqueFramebuffer, 3> framebuffers{};
Handle copy_handle; Handle copy_handle;
vk::UniqueImageView depth_view; vk::UniqueImageView depth_view;
vk::UniqueImageView stencil_view; vk::UniqueImageView stencil_view;