renderer_vulkan: Use intermediate copy when framebuffer is used both as attachment and shader input
This commit is contained in:
@ -48,6 +48,7 @@ class SurfaceBase : public SurfaceParams, public std::enable_shared_from_this<S>
|
|||||||
using Watcher = SurfaceWatcher<S>;
|
using Watcher = SurfaceWatcher<S>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
SurfaceBase() = default;
|
||||||
SurfaceBase(const SurfaceParams& params) : SurfaceParams{params} {}
|
SurfaceBase(const SurfaceParams& params) : SurfaceParams{params} {}
|
||||||
virtual ~SurfaceBase() = default;
|
virtual ~SurfaceBase() = default;
|
||||||
|
|
||||||
|
@ -663,17 +663,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
|||||||
uniform_block_data.dirty = true;
|
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,
|
const auto BindCubeFace = [&](Pica::TexturingRegs::CubeFace face,
|
||||||
Pica::Texture::TextureInfo& info) {
|
Pica::Texture::TextureInfo& info) {
|
||||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
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
|
// Sync and bind the texture surfaces
|
||||||
const auto pica_textures = regs.texturing.GetTextures();
|
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];
|
const auto& texture = pica_textures[texture_index];
|
||||||
|
|
||||||
if (texture.enabled) {
|
if (texture.enabled) {
|
||||||
@ -724,7 +713,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
|||||||
switch (texture.config.type.Value()) {
|
switch (texture.config.type.Value()) {
|
||||||
case TextureType::Shadow2D: {
|
case TextureType::Shadow2D: {
|
||||||
auto surface = res_cache.GetTextureSurface(texture);
|
auto surface = res_cache.GetTextureSurface(texture);
|
||||||
if (surface != nullptr) {
|
if (surface) {
|
||||||
pipeline_cache.BindStorageImage(0, surface->GetImageView());
|
pipeline_cache.BindStorageImage(0, surface->GetImageView());
|
||||||
} else {
|
} else {
|
||||||
pipeline_cache.BindStorageImage(0, null_storage_surface.GetImageView());
|
pipeline_cache.BindStorageImage(0, null_storage_surface.GetImageView());
|
||||||
@ -756,7 +745,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
|||||||
.format = texture.format};
|
.format = texture.format};
|
||||||
|
|
||||||
auto surface = res_cache.GetTextureCube(config);
|
auto surface = res_cache.GetTextureCube(config);
|
||||||
if (surface != nullptr) {
|
if (surface) {
|
||||||
surface->Transition(vk::ImageLayout::eShaderReadOnlyOptimal, 0,
|
surface->Transition(vk::ImageLayout::eShaderReadOnlyOptimal, 0,
|
||||||
surface->alloc.levels);
|
surface->alloc.levels);
|
||||||
pipeline_cache.BindTexture(3, surface->GetImageView());
|
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);
|
BindSampler(texture_index, texture_samplers[texture_index], texture.config);
|
||||||
|
|
||||||
auto surface = res_cache.GetTextureSurface(texture);
|
auto surface = res_cache.GetTextureSurface(texture);
|
||||||
if (surface != nullptr) {
|
if (surface) {
|
||||||
surface->Transition(vk::ImageLayout::eShaderReadOnlyOptimal, 0,
|
if (color_surface && color_surface->GetImageView() == surface->GetImageView()) {
|
||||||
surface->alloc.levels);
|
Surface temp{*color_surface, runtime};
|
||||||
CheckBarrier(surface->alloc.image_view, texture_index);
|
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);
|
||||||
|
pipeline_cache.BindTexture(texture_index, surface->GetImageView());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
// 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
|
// 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(),
|
pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(),
|
||||||
draw_rect.GetHeight());
|
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 = {
|
const FramebufferInfo framebuffer_info = {
|
||||||
.color = color_surface ? color_surface->GetFramebufferView() : VK_NULL_HANDLE,
|
.color = color_surface ? color_surface->GetFramebufferView() : VK_NULL_HANDLE,
|
||||||
.depth = depth_surface ? depth_surface->GetFramebufferView() : VK_NULL_HANDLE,
|
.depth = depth_surface ? depth_surface->GetFramebufferView() : VK_NULL_HANDLE,
|
||||||
.renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
|
.renderpass = renderpass_cache.GetRenderpass(pipeline_info.color_attachment,
|
||||||
pipeline_info.depth_attachment, false),
|
pipeline_info.depth_attachment, false),
|
||||||
.width = valid_surface->GetScaledWidth(),
|
.width = width,
|
||||||
.height = valid_surface->GetScaledHeight()};
|
.height = height};
|
||||||
|
|
||||||
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
|
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
|
||||||
if (new_framebuffer) {
|
if (new_framebuffer) {
|
||||||
|
@ -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)
|
Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime)
|
||||||
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, instance{runtime.GetInstance()},
|
: VideoCore::SurfaceBase<Surface>{params}, runtime{runtime}, instance{runtime.GetInstance()},
|
||||||
scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} {
|
scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} {
|
||||||
|
@ -166,11 +166,15 @@ class Surface : public VideoCore::SurfaceBase<Surface> {
|
|||||||
friend class RasterizerVulkan;
|
friend class RasterizerVulkan;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Surface(TextureRuntime& runtime);
|
||||||
Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime);
|
Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime);
|
||||||
Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage,
|
Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage,
|
||||||
TextureRuntime& runtime);
|
TextureRuntime& runtime);
|
||||||
~Surface() override;
|
~Surface() override;
|
||||||
|
|
||||||
|
Surface(Surface&&) = default;
|
||||||
|
Surface& operator=(Surface&&) = default;
|
||||||
|
|
||||||
/// Transitions the mip level range of the surface to new_layout
|
/// Transitions the mip level range of the surface to new_layout
|
||||||
void Transition(vk::ImageLayout new_layout, u32 level, u32 level_count);
|
void Transition(vk::ImageLayout new_layout, u32 level, u32 level_count);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user