renderer_vulkan: Use intermediate copy when framebuffer is used both as attachment and shader input

This commit is contained in:
emufan4568
2022-10-16 17:38:41 +03:00
parent 46ae192c05
commit b7fa091db0
4 changed files with 51 additions and 21 deletions

View File

@ -48,6 +48,7 @@ class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this<S>
using Watcher = SurfaceWatcher<S>;
public:
SurfaceBase() = default;
SurfaceBase(const SurfaceParams& params) : SurfaceParams{params} {}
virtual ~SurfaceBase() = default;

View File

@ -663,17 +663,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
uniform_block_data.dirty = true;
}
auto CheckBarrier = [this, &color_surface = color_surface](vk::ImageView image_view,
u32 texture_index) {
if (color_surface && color_surface->alloc.image_view == image_view) {
// auto temp_tex = backend->CreateTexture(texture->GetInfo());
// temp_tex->CopyFrom(texture);
pipeline_cache.BindTexture(texture_index, image_view);
} else {
pipeline_cache.BindTexture(texture_index, image_view);
}
};
const auto BindCubeFace = [&](Pica::TexturingRegs::CubeFace face,
Pica::Texture::TextureInfo& info) {
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
@ -715,7 +704,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// Sync and bind the texture surfaces
const auto pica_textures = regs.texturing.GetTextures();
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
for (u32 texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
const auto& texture = pica_textures[texture_index];
if (texture.enabled) {
@ -724,7 +713,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
switch (texture.config.type.Value()) {
case TextureType::Shadow2D: {
auto surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) {
if (surface) {
pipeline_cache.BindStorageImage(0, surface->GetImageView());
} else {
pipeline_cache.BindStorageImage(0, null_storage_surface.GetImageView());
@ -756,7 +745,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
.format = texture.format};
auto surface = res_cache.GetTextureCube(config);
if (surface != nullptr) {
if (surface) {
surface->Transition(vk::ImageLayout::eShaderReadOnlyOptimal, 0,
surface->alloc.levels);
pipeline_cache.BindTexture(3, surface->GetImageView());
@ -776,10 +765,29 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
BindSampler(texture_index, texture_samplers[texture_index], texture.config);
auto surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) {
if (surface) {
if (color_surface && color_surface->GetImageView() == surface->GetImageView()) {
Surface temp{*color_surface, runtime};
const VideoCore::TextureCopy copy = {
.src_level = 0,
.dst_level = 0,
.src_layer = 0,
.dst_layer = 0,
.src_offset = VideoCore::Offset{0, 0},
.dst_offset = VideoCore::Offset{0, 0},
.extent = VideoCore::Extent{temp.GetScaledWidth(),
temp.GetScaledHeight()}};
runtime.CopyTextures(*color_surface, temp, copy);
temp.Transition(vk::ImageLayout::eShaderReadOnlyOptimal, 0, temp.alloc.levels);
pipeline_cache.BindTexture(texture_index, temp.GetImageView());
} else {
surface->Transition(vk::ImageLayout::eShaderReadOnlyOptimal, 0,
surface->alloc.levels);
CheckBarrier(surface->alloc.image_view, texture_index);
pipeline_cache.BindTexture(texture_index, surface->GetImageView());
}
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
// HACK: In this case, the correct behaviour for the PICA is to use the last
@ -823,14 +831,28 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(),
draw_rect.GetHeight());
auto valid_surface = color_surface ? color_surface : depth_surface;
// Sometimes the dimentions of the color and depth framebuffers might not be the same
// In that case select the minimum one to abide by the spec
u32 width = 0;
u32 height = 0;
if (color_surface && depth_surface) {
width = std::min(color_surface->GetScaledWidth(), depth_surface->GetScaledWidth());
height = std::min(color_surface->GetScaledHeight(), depth_surface->GetScaledHeight());
} else if (color_surface) {
width = color_surface->GetScaledWidth();
height = color_surface->GetScaledHeight();
} else if (depth_surface) {
width = depth_surface->GetScaledWidth();
height = depth_surface->GetScaledHeight();
}
const FramebufferInfo framebuffer_info = {
.color = color_surface ? color_surface->GetFramebufferView() : VK_NULL_HANDLE,
.depth = depth_surface ? depth_surface->GetFramebufferView() : VK_NULL_HANDLE,
.renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
pipeline_info.depth_attachment, false),
.width = valid_surface->GetScaledWidth(),
.height = valid_surface->GetScaledHeight()};
.width = width,
.height = height};
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
if (new_framebuffer) {

View File

@ -551,6 +551,9 @@ void TextureRuntime::Transition(vk::CommandBuffer command_buffer, ImageAlloc& al
}
}
Surface::Surface(TextureRuntime& runtime)
: runtime{runtime}, instance{runtime.GetInstance()}, scheduler{runtime.GetScheduler()} {}
Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime)
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, instance{runtime.GetInstance()},
scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} {

View File

@ -166,11 +166,15 @@ class Surface : public VideoCore::SurfaceBase<Surface> {
friend class RasterizerVulkan;
public:
Surface(TextureRuntime& runtime);
Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime);
Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage,
TextureRuntime& runtime);
~Surface() override;
Surface(Surface&&) = default;
Surface& operator=(Surface&&) = default;
/// Transitions the mip level range of the surface to new_layout
void Transition(vk::ImageLayout new_layout, u32 level, u32 level_count);