vk_renderpass_cache: Commonize setup between renderpass and dynamic rendering implementations

* Also fix small issue that caused broken rendering on the latter
This commit is contained in:
GPUCode
2023-03-03 16:24:10 +02:00
parent c34bc45bf1
commit c26cb68a0c
9 changed files with 99 additions and 120 deletions

View File

@ -236,7 +236,7 @@ void RendererVulkan::BeginRendering(Frame* frame) {
instance.GetDevice().updateDescriptorSetWithTemplate(set, present_update_template,
present_textures[0]);
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
scheduler.Record([this, framebuffer = frame->framebuffer, width = frame->width,
height = frame->height, set,
pipeline_index = current_pipeline](vk::CommandBuffer cmdbuf) {
@ -569,7 +569,7 @@ void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color
},
};
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
scheduler.Record([image = texture.image, clear_color](vk::CommandBuffer cmdbuf) {
const vk::ImageSubresourceRange range = {
.aspectMask = vk::ImageAspectFlagBits::eColor,

View File

@ -331,7 +331,7 @@ bool BlitHelper::BlitDepthStencil(Surface& source, Surface& dest,
vk::DescriptorSet set = desc_manager.AllocateSet(two_textures_descriptor_layout);
device.updateDescriptorSetWithTemplate(set, two_textures_update_template, textures[0]);
renderpass_cache.EnterRenderpass(nullptr, &dest, dst_render_area);
renderpass_cache.BeginRendering(nullptr, &dest, dst_render_area);
scheduler.Record([blit, set, this](vk::CommandBuffer cmdbuf) {
const vk::PipelineLayout layout = two_textures_pipeline_layout;
@ -364,7 +364,7 @@ void BlitHelper::BlitD24S8ToR32(Surface& source, Surface& dest,
vk::DescriptorSet set = desc_manager.AllocateSet(compute_descriptor_layout);
device.updateDescriptorSetWithTemplate(set, compute_update_template, textures[0]);
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
scheduler.Record([this, set, blit, src_image = source.Image(),
dst_image = dest.Image()](vk::CommandBuffer cmdbuf) {
const std::array pre_barriers = {

View File

@ -163,7 +163,7 @@ void D24S8toRGBA8::Reinterpret(Surface& source, VideoCore::Rect2D src_rect, Surf
vk::DescriptorSet set = desc_manager.AllocateSet(descriptor_layout);
device.updateDescriptorSetWithTemplate(set, update_template, textures[0]);
runtime.GetRenderpassCache().ExitRenderpass();
runtime.GetRenderpassCache().EndRendering();
scheduler.Record([this, set, src_rect, src_image = source.Image(),
dst_image = dest.Image()](vk::CommandBuffer cmdbuf) {
const std::array pre_barriers = {

View File

@ -496,7 +496,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
UploadUniforms(accelerate);
// Begin the renderpass
renderpass_cache.EnterRenderpass(framebuffer);
renderpass_cache.BeginRendering(framebuffer);
// Sync the viewport
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect.

View File

@ -43,17 +43,13 @@ void RenderpassCache::ClearFramebuffers() {
framebuffers.clear();
}
void RenderpassCache::EnterRenderpass(Surface* const color, Surface* const depth_stencil,
void RenderpassCache::BeginRendering(Surface* const color, Surface* const depth_stencil,
vk::Rect2D render_area, bool do_clear, vk::ClearValue clear) {
return EnterRenderpass(Framebuffer{color, depth_stencil, render_area}, do_clear, clear);
return BeginRendering(Framebuffer{color, depth_stencil, render_area}, do_clear, clear);
}
void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_clear,
void RenderpassCache::BeginRendering(const Framebuffer& framebuffer, bool do_clear,
vk::ClearValue clear) {
if (dynamic_rendering) {
return BeginRendering(framebuffer, do_clear, clear);
}
RenderingInfo new_info = {
.color{
.aspect = vk::ImageAspectFlagBits::eColor,
@ -63,30 +59,84 @@ void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_cl
.depth{
.aspect = vk::ImageAspectFlagBits::eDepth,
.image = framebuffer.Image(SurfaceType::DepthStencil),
.image_view = framebuffer.ImageView(SurfaceType::Color),
.image_view = framebuffer.ImageView(SurfaceType::DepthStencil),
},
.render_area = framebuffer.RenderArea(),
.clear = clear,
.do_clear = do_clear,
};
const PixelFormat color_format = framebuffer.Format(SurfaceType::Color);
const PixelFormat depth_format = framebuffer.Format(SurfaceType::DepthStencil);
if (depth_format == PixelFormat::D24S8) {
if (framebuffer.HasStencil()) {
new_info.depth.aspect |= vk::ImageAspectFlagBits::eStencil;
}
const bool is_dirty = scheduler.IsStateDirty(StateFlags::Renderpass);
if (info == new_info && rendering && !is_dirty) {
// If the provided rendering context is active we are done
if (info == new_info && rendering) {
cmd_count++;
return;
}
const vk::RenderPass renderpass = GetRenderpass(color_format, depth_format, do_clear);
EndRendering();
info = new_info;
rendering = true;
// Begin the render scope
if (dynamic_rendering) {
DynamicRendering(framebuffer);
} else {
EnterRenderpass(framebuffer);
}
}
void RenderpassCache::DynamicRendering(const Framebuffer& framebuffer) {
const bool has_stencil = framebuffer.HasStencil();
scheduler.Record([info = info, has_stencil](vk::CommandBuffer cmdbuf) {
u32 cursor = 0;
std::array<vk::RenderingAttachmentInfoKHR, 2> infos{};
const auto Prepare = [&](vk::ImageView image_view) {
if (!image_view) {
cursor++;
return;
}
infos[cursor++] = vk::RenderingAttachmentInfoKHR{
.imageView = image_view,
.imageLayout = vk::ImageLayout::eGeneral,
.loadOp =
info.do_clear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad,
.storeOp = vk::AttachmentStoreOp::eStore,
.clearValue = info.clear,
};
};
Prepare(info.color.image_view);
Prepare(info.depth.image_view);
const u32 color_attachment_count = info.color ? 1u : 0u;
const vk::RenderingAttachmentInfoKHR* depth_info = info.depth ? &infos[1] : nullptr;
const vk::RenderingAttachmentInfoKHR* stencil_info = has_stencil ? &infos[1] : nullptr;
const vk::RenderingInfoKHR rendering_info = {
.renderArea = info.render_area,
.layerCount = 1,
.colorAttachmentCount = color_attachment_count,
.pColorAttachments = &infos[0],
.pDepthAttachment = depth_info,
.pStencilAttachment = stencil_info,
};
cmdbuf.beginRenderingKHR(rendering_info);
});
}
void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer) {
const PixelFormat color_format = framebuffer.Format(SurfaceType::Color);
const PixelFormat depth_format = framebuffer.Format(SurfaceType::DepthStencil);
const vk::RenderPass renderpass = GetRenderpass(color_format, depth_format, info.do_clear);
const FramebufferInfo framebuffer_info = {
.color = new_info.color.image_view,
.depth = new_info.depth.image_view,
.color = info.color.image_view,
.depth = info.depth.image_view,
.width = framebuffer.Width(),
.height = framebuffer.Height(),
};
@ -96,10 +146,7 @@ void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_cl
it->second = CreateFramebuffer(framebuffer_info, renderpass);
}
if (rendering) {
ExitRenderpass();
}
scheduler.Record([render_area = new_info.render_area, clear, renderpass,
scheduler.Record([render_area = info.render_area, clear = info.clear, renderpass,
framebuffer = it->second](vk::CommandBuffer cmdbuf) {
const vk::RenderPassBeginInfo renderpass_begin_info = {
.renderPass = renderpass,
@ -111,13 +158,9 @@ void RenderpassCache::EnterRenderpass(const Framebuffer& framebuffer, bool do_cl
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
});
scheduler.MarkStateNonDirty(StateFlags::Renderpass);
info = new_info;
rendering = true;
}
void RenderpassCache::ExitRenderpass() {
void RenderpassCache::EndRendering() {
if (!rendering) {
return;
}
@ -191,81 +234,6 @@ void RenderpassCache::ExitRenderpass() {
}
}
void RenderpassCache::BeginRendering(const Framebuffer& framebuffer, bool do_clear,
vk::ClearValue clear) {
RenderingInfo new_info = {
.color{
.aspect = vk::ImageAspectFlagBits::eColor,
.image = framebuffer.Image(SurfaceType::Color),
.image_view = framebuffer.ImageView(SurfaceType::Color),
},
.depth{
.aspect = vk::ImageAspectFlagBits::eDepth,
.image = framebuffer.Image(SurfaceType::DepthStencil),
.image_view = framebuffer.ImageView(SurfaceType::DepthStencil),
},
.render_area = framebuffer.RenderArea(),
.clear = clear,
.do_clear = do_clear,
};
const bool has_stencil = framebuffer.Format(SurfaceType::DepthStencil) == PixelFormat::D24S8;
if (has_stencil) {
new_info.depth.aspect |= vk::ImageAspectFlagBits::eStencil;
}
const bool is_dirty = scheduler.IsStateDirty(StateFlags::Renderpass);
if (info == new_info && rendering && !is_dirty) {
cmd_count++;
return;
}
if (rendering) {
ExitRenderpass();
}
scheduler.Record([new_info, has_stencil](vk::CommandBuffer cmdbuf) {
u32 cursor = 0;
std::array<vk::RenderingAttachmentInfoKHR, 2> infos{};
const auto Prepare = [&](vk::ImageView image_view) {
if (!image_view) {
cursor++;
return;
}
infos[cursor++] = vk::RenderingAttachmentInfoKHR{
.imageView = image_view,
.imageLayout = vk::ImageLayout::eGeneral,
.loadOp =
new_info.do_clear ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad,
.storeOp = vk::AttachmentStoreOp::eStore,
.clearValue = new_info.clear,
};
};
Prepare(new_info.color.image_view);
Prepare(new_info.depth.image_view);
const u32 color_attachment_count = new_info.color ? 1u : 0u;
const vk::RenderingAttachmentInfoKHR* depth_info = new_info.depth ? &infos[1] : nullptr;
const vk::RenderingAttachmentInfoKHR* stencil_info = has_stencil ? &infos[1] : nullptr;
const vk::RenderingInfoKHR rendering_info = {
.renderArea = new_info.render_area,
.layerCount = 1,
.colorAttachmentCount = color_attachment_count,
.pColorAttachments = &infos[0],
.pDepthAttachment = depth_info,
.pStencilAttachment = stencil_info,
};
cmdbuf.beginRenderingKHR(rendering_info);
});
scheduler.MarkStateNonDirty(StateFlags::Renderpass);
info = new_info;
rendering = true;
}
void RenderpassCache::CreatePresentRenderpass(vk::Format format) {
if (!present_renderpass) {
present_renderpass =
@ -276,6 +244,8 @@ void RenderpassCache::CreatePresentRenderpass(vk::Format format) {
vk::RenderPass RenderpassCache::GetRenderpass(VideoCore::PixelFormat color,
VideoCore::PixelFormat depth, bool is_clear) {
std::scoped_lock lock{cache_mutex};
const u32 color_index =
color == VideoCore::PixelFormat::Invalid ? MAX_COLOR_FORMATS : static_cast<u32>(color);
const u32 depth_index = depth == VideoCore::PixelFormat::Invalid

View File

@ -6,6 +6,7 @@
#include <compare>
#include <cstring>
#include <mutex>
#include <variant>
#include "common/hash.h"
#include "video_core/rasterizer_cache/pixel_format.h"
@ -53,13 +54,13 @@ public:
void ClearFramebuffers();
/// Begins a new renderpass only when no other renderpass is currently active
void EnterRenderpass(const Framebuffer& framebuffer, bool do_clear = false,
void BeginRendering(const Framebuffer& framebuffer, bool do_clear = false,
vk::ClearValue clear = {});
void EnterRenderpass(Surface* const color, Surface* const depth_stencil, vk::Rect2D render_area,
void BeginRendering(Surface* const color, Surface* const depth_stencil, vk::Rect2D render_area,
bool do_clear = false, vk::ClearValue clear = {});
/// Exits from any currently active renderpass instance
void ExitRenderpass();
void EndRendering();
/// Creates the renderpass used when rendering to the swapchain
void CreatePresentRenderpass(vk::Format format);
@ -75,7 +76,10 @@ public:
private:
/// Begins a new rendering scope using dynamic rendering
void BeginRendering(const Framebuffer& framebuffer, bool do_clear, vk::ClearValue clear);
void DynamicRendering(const Framebuffer& framebuffer);
/// Begins a new rendering scope using renderpasses
void EnterRenderpass(const Framebuffer& framebuffer);
/// Creates a renderpass configured appropriately and stores it in cached_renderpasses
vk::RenderPass CreateRenderPass(vk::Format color, vk::Format depth,
@ -123,6 +127,7 @@ private:
bool rendering = false;
bool dynamic_rendering = false;
u32 cmd_count{};
std::mutex cache_mutex;
};
} // namespace Vulkan

View File

@ -121,7 +121,7 @@ void Scheduler::SubmitExecution(vk::Semaphore signal_semaphore, vk::Semaphore wa
const u64 signal_value = master_semaphore.NextTick();
state = StateFlags::AllDirty;
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
Record(
[signal_semaphore, wait_semaphore, handle, signal_value, this](vk::CommandBuffer cmdbuf) {
MICROPROFILE_SCOPE(Vulkan_Submit);

View File

@ -263,7 +263,7 @@ Allocation TextureRuntime::Allocate(u32 width, u32 height, u32 levels, bool is_m
vk::Device device = instance.GetDevice();
vk::UniqueImageView image_view = device.createImageViewUnique(view_info);
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
scheduler.Record([image, aspect](vk::CommandBuffer cmdbuf) {
const vk::ImageMemoryBarrier init_barrier = {
.srcAccessMask = vk::AccessFlagBits::eNone,
@ -305,7 +305,7 @@ void TextureRuntime::Recycle(const HostTextureTag tag, Allocation&& alloc) {
}
bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClear& clear) {
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
const RecordParams params = {
.aspect = surface.alloc.aspect,
@ -445,9 +445,9 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
},
};
renderpass_cache.EnterRenderpass(color_surface, depth_surface, render_area, true,
renderpass_cache.BeginRendering(color_surface, depth_surface, render_area, true,
MakeClearValue(clear.value));
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) {
const vk::ImageMemoryBarrier post_barrier = {
@ -474,7 +474,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
const VideoCore::TextureCopy& copy) {
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
const RecordParams params = {
.aspect = source.alloc.aspect,
@ -603,7 +603,7 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
return blit_helper.BlitDepthStencil(source, dest, blit);
}
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
const RecordParams params = {
.aspect = source.alloc.aspect,
@ -735,7 +735,7 @@ void TextureRuntime::GenerateMipmaps(Surface& surface) {
return;
}
renderpass_cache.ExitRenderpass();
renderpass_cache.EndRendering();
// Always use the allocation width on custom textures
u32 current_width = surface.alloc.width;
@ -823,7 +823,7 @@ Surface::~Surface() {
}
void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
runtime->renderpass_cache.ExitRenderpass();
runtime->renderpass_cache.EndRendering();
const bool is_scaled = res_scale != 1;
if (is_scaled) {
@ -919,7 +919,7 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
}
void Surface::Download(const VideoCore::BufferTextureCopy& download, const StagingData& staging) {
runtime->renderpass_cache.ExitRenderpass();
runtime->renderpass_cache.EndRendering();
// For depth stencil downloads always use the compute shader fallback
// to avoid having the interleave the data later. These should(?) be

View File

@ -263,6 +263,10 @@ public:
return static_cast<bool>(image_views[Index(type)]);
}
bool HasStencil() const noexcept {
return Format(VideoCore::SurfaceType::DepthStencil) == VideoCore::PixelFormat::D24S8;
}
u32 Width() const noexcept {
return width;
}