renderer_vulkan: Move framebuffer handling to the renderpass cache
This commit is contained in:
@@ -216,13 +216,25 @@ void RendererVulkan::BeginRendering() {
|
|||||||
{});
|
{});
|
||||||
});
|
});
|
||||||
|
|
||||||
const RenderpassState renderpass_info = {
|
renderpass_cache.ExitRenderpass();
|
||||||
.renderpass = renderpass_cache.GetPresentRenderpass(),
|
|
||||||
.framebuffer = swapchain.GetFramebuffer(),
|
|
||||||
.render_area = vk::Rect2D{.offset = {0, 0}, .extent = swapchain.GetExtent()},
|
|
||||||
.clear = vk::ClearValue{.color = clear_color}};
|
|
||||||
|
|
||||||
renderpass_cache.EnterRenderpass(renderpass_info);
|
scheduler.Record([this, framebuffer = swapchain.GetFramebuffer(),
|
||||||
|
extent = swapchain.GetExtent()](vk::CommandBuffer cmdbuf) {
|
||||||
|
const vk::ClearValue clear{.color = clear_color};
|
||||||
|
const vk::RenderPassBeginInfo renderpass_begin_info = {
|
||||||
|
.renderPass = renderpass_cache.GetPresentRenderpass(),
|
||||||
|
.framebuffer = framebuffer,
|
||||||
|
.renderArea =
|
||||||
|
vk::Rect2D{
|
||||||
|
.offset = {0, 0},
|
||||||
|
.extent = extent,
|
||||||
|
},
|
||||||
|
.clearValueCount = 1,
|
||||||
|
.pClearValues = &clear,
|
||||||
|
};
|
||||||
|
|
||||||
|
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
|
void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
|
||||||
@@ -896,7 +908,7 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderpass_cache.ExitRenderpass();
|
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.endRenderPass(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererVulkan::SwapBuffers() {
|
void RendererVulkan::SwapBuffers() {
|
||||||
|
@@ -144,10 +144,6 @@ RasterizerVulkan::~RasterizerVulkan() {
|
|||||||
device.destroySampler(sampler);
|
device.destroySampler(sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [key, framebuffer] : framebuffers) {
|
|
||||||
device.destroyFramebuffer(framebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
device.destroySampler(default_sampler);
|
device.destroySampler(default_sampler);
|
||||||
device.destroyBufferView(texture_lf_view);
|
device.destroyBufferView(texture_lf_view);
|
||||||
device.destroyBufferView(texture_rg_view);
|
device.destroyBufferView(texture_rg_view);
|
||||||
@@ -674,48 +670,18 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
|||||||
|
|
||||||
// NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will
|
// NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will
|
||||||
// cause issues as the rasterizer cache might cause a scheduler switch and invalidate our state
|
// cause issues as the rasterizer cache might cause a scheduler switch and invalidate our state
|
||||||
|
const vk::Rect2D render_area = {
|
||||||
// Sometimes the dimentions of the color and depth framebuffers might not be the same
|
.offset{
|
||||||
// In that case select the minimum one to abide by the spec
|
.x = static_cast<s32>(draw_rect.left),
|
||||||
u32 width = 0;
|
.y = static_cast<s32>(draw_rect.bottom),
|
||||||
u32 height = 0;
|
},
|
||||||
if (color_surface && depth_surface) {
|
.extent{
|
||||||
width = std::min(color_surface->GetScaledWidth(), depth_surface->GetScaledWidth());
|
.width = draw_rect.GetWidth(),
|
||||||
height = std::min(color_surface->GetScaledHeight(), depth_surface->GetScaledHeight());
|
.height = draw_rect.GetHeight(),
|
||||||
} 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.attachments.color_format,
|
|
||||||
pipeline_info.attachments.depth_format, false),
|
|
||||||
.width = width,
|
|
||||||
.height = height,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info, vk::Framebuffer{});
|
renderpass_cache.EnterRenderpass(color_surface.get(), depth_surface.get(), render_area);
|
||||||
if (new_framebuffer) {
|
|
||||||
it->second = CreateFramebuffer(framebuffer_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
const RenderpassState renderpass_info = {
|
|
||||||
.renderpass = framebuffer_info.renderpass,
|
|
||||||
.framebuffer = it->second,
|
|
||||||
.render_area =
|
|
||||||
vk::Rect2D{
|
|
||||||
.offset = {static_cast<s32>(draw_rect.left), static_cast<s32>(draw_rect.bottom)},
|
|
||||||
.extent = {draw_rect.GetWidth(), draw_rect.GetHeight()},
|
|
||||||
},
|
|
||||||
.clear = {},
|
|
||||||
};
|
|
||||||
|
|
||||||
renderpass_cache.EnterRenderpass(renderpass_info);
|
|
||||||
|
|
||||||
// Sync and bind the shader
|
// Sync and bind the shader
|
||||||
if (shader_dirty) {
|
if (shader_dirty) {
|
||||||
@@ -1110,31 +1076,6 @@ vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
|
|||||||
return device.createSampler(sampler_info);
|
return device.createSampler(sampler_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Framebuffer RasterizerVulkan::CreateFramebuffer(const FramebufferInfo& info) {
|
|
||||||
u32 attachment_count = 0;
|
|
||||||
std::array<vk::ImageView, 2> attachments;
|
|
||||||
|
|
||||||
if (info.color) {
|
|
||||||
attachments[attachment_count++] = info.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.depth) {
|
|
||||||
attachments[attachment_count++] = info.depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
const vk::FramebufferCreateInfo framebuffer_info = {
|
|
||||||
.renderPass = info.renderpass,
|
|
||||||
.attachmentCount = attachment_count,
|
|
||||||
.pAttachments = attachments.data(),
|
|
||||||
.width = info.width,
|
|
||||||
.height = info.height,
|
|
||||||
.layers = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::Device device = instance.GetDevice();
|
|
||||||
return device.createFramebuffer(framebuffer_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerVulkan::SyncClipEnabled() {
|
void RasterizerVulkan::SyncClipEnabled() {
|
||||||
bool clip_enabled = Pica::g_state.regs.rasterizer.clip_enable != 0;
|
bool clip_enabled = Pica::g_state.regs.rasterizer.clip_enable != 0;
|
||||||
if (clip_enabled != uniform_block_data.data.enable_clip1) {
|
if (clip_enabled != uniform_block_data.data.enable_clip1) {
|
||||||
|
@@ -41,16 +41,6 @@ struct SamplerInfo {
|
|||||||
auto operator<=>(const SamplerInfo&) const noexcept = default;
|
auto operator<=>(const SamplerInfo&) const noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FramebufferInfo {
|
|
||||||
vk::ImageView color;
|
|
||||||
vk::ImageView depth;
|
|
||||||
vk::RenderPass renderpass;
|
|
||||||
u32 width = 1;
|
|
||||||
u32 height = 1;
|
|
||||||
|
|
||||||
auto operator<=>(const FramebufferInfo&) const noexcept = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
@@ -60,13 +50,6 @@ struct hash<Vulkan::SamplerInfo> {
|
|||||||
return Common::ComputeHash64(&info, sizeof(Vulkan::SamplerInfo));
|
return Common::ComputeHash64(&info, sizeof(Vulkan::SamplerInfo));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
struct hash<Vulkan::FramebufferInfo> {
|
|
||||||
std::size_t operator()(const Vulkan::FramebufferInfo& info) const noexcept {
|
|
||||||
return Common::ComputeHash64(&info, sizeof(Vulkan::FramebufferInfo));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
@@ -167,9 +150,6 @@ private:
|
|||||||
/// Creates a new sampler object
|
/// Creates a new sampler object
|
||||||
vk::Sampler CreateSampler(const SamplerInfo& info);
|
vk::Sampler CreateSampler(const SamplerInfo& info);
|
||||||
|
|
||||||
/// Creates a new Vulkan framebuffer object
|
|
||||||
vk::Framebuffer CreateFramebuffer(const FramebufferInfo& info);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Instance& instance;
|
const Instance& instance;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
@@ -190,7 +170,6 @@ private:
|
|||||||
std::array<SamplerInfo, 3> texture_samplers;
|
std::array<SamplerInfo, 3> texture_samplers;
|
||||||
SamplerInfo texture_cube_sampler;
|
SamplerInfo texture_cube_sampler;
|
||||||
std::unordered_map<SamplerInfo, vk::Sampler> samplers;
|
std::unordered_map<SamplerInfo, vk::Sampler> samplers;
|
||||||
std::unordered_map<FramebufferInfo, vk::Framebuffer> framebuffers;
|
|
||||||
PipelineInfo pipeline_info;
|
PipelineInfo pipeline_info;
|
||||||
|
|
||||||
StreamBuffer stream_buffer; ///< Vertex+Index+Uniform buffer
|
StreamBuffer stream_buffer; ///< Vertex+Index+Uniform buffer
|
||||||
|
@@ -2,10 +2,12 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
|
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_texture_runtime.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
@@ -26,12 +28,61 @@ RenderpassCache::~RenderpassCache() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& [key, framebuffer] : framebuffers) {
|
||||||
|
device.destroyFramebuffer(framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
device.destroyRenderPass(present_renderpass);
|
device.destroyRenderPass(present_renderpass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderpassCache::EnterRenderpass(const RenderpassState& state) {
|
void RenderpassCache::EnterRenderpass(Surface* const color, Surface* const depth_stencil,
|
||||||
|
vk::Rect2D render_area, bool do_clear, vk::ClearValue clear) {
|
||||||
|
ASSERT(color || depth_stencil);
|
||||||
|
|
||||||
|
u32 width = UINT32_MAX;
|
||||||
|
u32 height = UINT32_MAX;
|
||||||
|
u32 cursor = 0;
|
||||||
|
std::array<VideoCore::PixelFormat, 2> formats{};
|
||||||
|
std::array<vk::ImageView, 2> views{};
|
||||||
|
|
||||||
|
const auto Prepare = [&](Surface* const surface) {
|
||||||
|
if (!surface) {
|
||||||
|
formats[cursor++] = VideoCore::PixelFormat::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
width = std::min(width, surface->GetScaledWidth());
|
||||||
|
height = std::min(height, surface->GetScaledHeight());
|
||||||
|
formats[cursor] = surface->pixel_format;
|
||||||
|
views[cursor++] = surface->GetFramebufferView();
|
||||||
|
};
|
||||||
|
|
||||||
|
Prepare(color);
|
||||||
|
Prepare(depth_stencil);
|
||||||
|
|
||||||
|
const vk::RenderPass renderpass = GetRenderpass(formats[0], formats[1], do_clear);
|
||||||
|
|
||||||
|
const FramebufferInfo framebuffer_info = {
|
||||||
|
.color = views[0],
|
||||||
|
.depth = views[1],
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto [it, new_framebuffer] = framebuffers.try_emplace(framebuffer_info);
|
||||||
|
if (new_framebuffer) {
|
||||||
|
it->second = CreateFramebuffer(framebuffer_info, renderpass);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderpassState new_state = {
|
||||||
|
.renderpass = renderpass,
|
||||||
|
.framebuffer = it->second,
|
||||||
|
.render_area = render_area,
|
||||||
|
.clear = clear,
|
||||||
|
};
|
||||||
|
|
||||||
const bool is_dirty = scheduler.IsStateDirty(StateFlags::Renderpass);
|
const bool is_dirty = scheduler.IsStateDirty(StateFlags::Renderpass);
|
||||||
if (current_state == state && !is_dirty) {
|
if (current_state == new_state && !is_dirty) {
|
||||||
cmd_count++;
|
cmd_count++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -40,23 +91,20 @@ void RenderpassCache::EnterRenderpass(const RenderpassState& state) {
|
|||||||
ExitRenderpass();
|
ExitRenderpass();
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.Record([state](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([new_state](vk::CommandBuffer cmdbuf) {
|
||||||
const vk::RenderPassBeginInfo renderpass_begin_info = {
|
const vk::RenderPassBeginInfo renderpass_begin_info = {
|
||||||
.renderPass = state.renderpass,
|
.renderPass = new_state.renderpass,
|
||||||
.framebuffer = state.framebuffer,
|
.framebuffer = new_state.framebuffer,
|
||||||
.renderArea = state.render_area,
|
.renderArea = new_state.render_area,
|
||||||
.clearValueCount = 1,
|
.clearValueCount = 1,
|
||||||
.pClearValues = &state.clear,
|
.pClearValues = &new_state.clear,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
|
cmdbuf.beginRenderPass(renderpass_begin_info, vk::SubpassContents::eInline);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (is_dirty) {
|
scheduler.MarkStateNonDirty(StateFlags::Renderpass);
|
||||||
scheduler.MarkStateNonDirty(StateFlags::Renderpass);
|
current_state = new_state;
|
||||||
}
|
|
||||||
|
|
||||||
current_state = state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderpassCache::ExitRenderpass() {
|
void RenderpassCache::ExitRenderpass() {
|
||||||
@@ -178,8 +226,32 @@ vk::RenderPass RenderpassCache::CreateRenderPass(vk::Format color, vk::Format de
|
|||||||
.pDependencies = nullptr,
|
.pDependencies = nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
const vk::Device device = instance.GetDevice();
|
return instance.GetDevice().createRenderPass(renderpass_info);
|
||||||
return device.createRenderPass(renderpass_info);
|
}
|
||||||
|
|
||||||
|
vk::Framebuffer RenderpassCache::CreateFramebuffer(const FramebufferInfo& info,
|
||||||
|
vk::RenderPass renderpass) {
|
||||||
|
u32 attachment_count = 0;
|
||||||
|
std::array<vk::ImageView, 2> attachments;
|
||||||
|
|
||||||
|
if (info.color) {
|
||||||
|
attachments[attachment_count++] = info.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.depth) {
|
||||||
|
attachments[attachment_count++] = info.depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vk::FramebufferCreateInfo framebuffer_info = {
|
||||||
|
.renderPass = renderpass,
|
||||||
|
.attachmentCount = attachment_count,
|
||||||
|
.pAttachments = attachments.data(),
|
||||||
|
.width = info.width,
|
||||||
|
.height = info.height,
|
||||||
|
.layers = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return instance.GetDevice().createFramebuffer(framebuffer_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include "common/hash.h"
|
||||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||||
#include "video_core/renderer_vulkan/vk_common.h"
|
#include "video_core/renderer_vulkan/vk_common.h"
|
||||||
|
|
||||||
@@ -12,17 +13,29 @@ namespace Vulkan {
|
|||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
class Scheduler;
|
class Scheduler;
|
||||||
|
class Surface;
|
||||||
|
|
||||||
struct RenderpassState {
|
struct FramebufferInfo {
|
||||||
vk::RenderPass renderpass;
|
vk::ImageView color;
|
||||||
vk::Framebuffer framebuffer;
|
vk::ImageView depth;
|
||||||
vk::Rect2D render_area;
|
u32 width = 1;
|
||||||
vk::ClearValue clear;
|
u32 height = 1;
|
||||||
|
|
||||||
[[nodiscard]] bool operator==(const RenderpassState& other) const {
|
auto operator<=>(const FramebufferInfo&) const noexcept = default;
|
||||||
return std::memcmp(this, &other, sizeof(RenderpassState)) == 0;
|
};
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<Vulkan::FramebufferInfo> {
|
||||||
|
std::size_t operator()(const Vulkan::FramebufferInfo& info) const noexcept {
|
||||||
|
return Common::ComputeStructHash64(info);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
class RenderpassCache {
|
class RenderpassCache {
|
||||||
static constexpr u32 MAX_COLOR_FORMATS = 5;
|
static constexpr u32 MAX_COLOR_FORMATS = 5;
|
||||||
@@ -33,7 +46,8 @@ public:
|
|||||||
~RenderpassCache();
|
~RenderpassCache();
|
||||||
|
|
||||||
/// Begins a new renderpass only when no other renderpass is currently active
|
/// Begins a new renderpass only when no other renderpass is currently active
|
||||||
void EnterRenderpass(const RenderpassState& state);
|
void EnterRenderpass(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
|
/// Exits from any currently active renderpass instance
|
||||||
void ExitRenderpass();
|
void ExitRenderpass();
|
||||||
@@ -56,12 +70,27 @@ private:
|
|||||||
vk::AttachmentLoadOp load_op, vk::ImageLayout initial_layout,
|
vk::AttachmentLoadOp load_op, vk::ImageLayout initial_layout,
|
||||||
vk::ImageLayout final_layout) const;
|
vk::ImageLayout final_layout) const;
|
||||||
|
|
||||||
|
/// Creates a new Vulkan framebuffer object
|
||||||
|
vk::Framebuffer CreateFramebuffer(const FramebufferInfo& info, vk::RenderPass renderpass);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct RenderpassState {
|
||||||
|
vk::RenderPass renderpass;
|
||||||
|
vk::Framebuffer framebuffer;
|
||||||
|
vk::Rect2D render_area;
|
||||||
|
vk::ClearValue clear;
|
||||||
|
|
||||||
|
[[nodiscard]] bool operator==(const RenderpassState& other) const {
|
||||||
|
return std::memcmp(this, &other, sizeof(RenderpassState)) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const Instance& instance;
|
const Instance& instance;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
RenderpassState current_state{};
|
RenderpassState current_state{};
|
||||||
vk::RenderPass present_renderpass{};
|
vk::RenderPass present_renderpass{};
|
||||||
vk::RenderPass cached_renderpasses[MAX_COLOR_FORMATS + 1][MAX_DEPTH_FORMATS + 1][2];
|
vk::RenderPass cached_renderpasses[MAX_COLOR_FORMATS + 1][MAX_DEPTH_FORMATS + 1][2];
|
||||||
|
std::unordered_map<FramebufferInfo, vk::Framebuffer> framebuffers;
|
||||||
u32 cmd_count{};
|
u32 cmd_count{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -102,7 +102,7 @@ constexpr u64 DOWNLOAD_BUFFER_SIZE = 32 * 1024 * 1024;
|
|||||||
TextureRuntime::TextureRuntime(const Instance& instance, Scheduler& scheduler,
|
TextureRuntime::TextureRuntime(const Instance& instance, Scheduler& scheduler,
|
||||||
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager)
|
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager)
|
||||||
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache},
|
: instance{instance}, scheduler{scheduler}, renderpass_cache{renderpass_cache},
|
||||||
desc_manager{desc_manager}, blit_helper{instance, scheduler, desc_manager, renderpass_cache},
|
blit_helper{instance, scheduler, desc_manager, renderpass_cache},
|
||||||
upload_buffer{instance, scheduler, vk::BufferUsageFlagBits::eTransferSrc, UPLOAD_BUFFER_SIZE},
|
upload_buffer{instance, scheduler, vk::BufferUsageFlagBits::eTransferSrc, UPLOAD_BUFFER_SIZE},
|
||||||
download_buffer{instance, scheduler, vk::BufferUsageFlagBits::eTransferDst,
|
download_buffer{instance, scheduler, vk::BufferUsageFlagBits::eTransferDst,
|
||||||
DOWNLOAD_BUFFER_SIZE, true} {
|
DOWNLOAD_BUFFER_SIZE, true} {
|
||||||
@@ -137,10 +137,6 @@ TextureRuntime::~TextureRuntime() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [key, framebuffer] : clear_framebuffers) {
|
|
||||||
device.destroyFramebuffer(framebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture_recycler.clear();
|
texture_recycler.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,41 +445,6 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
|
|||||||
is_color ? vk::PipelineStageFlagBits::eColorAttachmentOutput
|
is_color ? vk::PipelineStageFlagBits::eColorAttachmentOutput
|
||||||
: vk::PipelineStageFlagBits::eEarlyFragmentTests;
|
: vk::PipelineStageFlagBits::eEarlyFragmentTests;
|
||||||
|
|
||||||
const vk::RenderPass clear_renderpass =
|
|
||||||
is_color ? renderpass_cache.GetRenderpass(surface.pixel_format,
|
|
||||||
VideoCore::PixelFormat::Invalid, true)
|
|
||||||
: renderpass_cache.GetRenderpass(VideoCore::PixelFormat::Invalid,
|
|
||||||
surface.pixel_format, true);
|
|
||||||
|
|
||||||
const vk::ImageView framebuffer_view = surface.GetFramebufferView();
|
|
||||||
|
|
||||||
auto [it, new_framebuffer] =
|
|
||||||
clear_framebuffers.try_emplace(framebuffer_view, vk::Framebuffer{});
|
|
||||||
if (new_framebuffer) {
|
|
||||||
const vk::FramebufferCreateInfo framebuffer_info = {
|
|
||||||
.renderPass = clear_renderpass,
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = &framebuffer_view,
|
|
||||||
.width = surface.GetScaledWidth(),
|
|
||||||
.height = surface.GetScaledHeight(),
|
|
||||||
.layers = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
it->second = instance.GetDevice().createFramebuffer(framebuffer_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
const RenderpassState clear_info = {
|
|
||||||
.renderpass = clear_renderpass,
|
|
||||||
.framebuffer = it->second,
|
|
||||||
.render_area =
|
|
||||||
vk::Rect2D{
|
|
||||||
.offset = {static_cast<s32>(clear.texture_rect.left),
|
|
||||||
static_cast<s32>(clear.texture_rect.bottom)},
|
|
||||||
.extent = {clear.texture_rect.GetWidth(), clear.texture_rect.GetHeight()},
|
|
||||||
},
|
|
||||||
.clear = MakeClearValue(value),
|
|
||||||
};
|
|
||||||
|
|
||||||
const RecordParams params = {
|
const RecordParams params = {
|
||||||
.aspect = surface.alloc.aspect,
|
.aspect = surface.alloc.aspect,
|
||||||
.pipeline_flags = surface.PipelineStageFlags(),
|
.pipeline_flags = surface.PipelineStageFlags(),
|
||||||
@@ -513,7 +474,27 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
|
|||||||
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
|
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
|
||||||
});
|
});
|
||||||
|
|
||||||
renderpass_cache.EnterRenderpass(clear_info);
|
Surface* color_surface{};
|
||||||
|
Surface* depth_surface{};
|
||||||
|
if (is_color) {
|
||||||
|
color_surface = &surface;
|
||||||
|
} else {
|
||||||
|
depth_surface = &surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vk::Rect2D render_area = {
|
||||||
|
.offset{
|
||||||
|
.x = static_cast<s32>(clear.texture_rect.left),
|
||||||
|
.y = static_cast<s32>(clear.texture_rect.bottom),
|
||||||
|
},
|
||||||
|
.extent{
|
||||||
|
.width = clear.texture_rect.GetWidth(),
|
||||||
|
.height = clear.texture_rect.GetHeight(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderpass_cache.EnterRenderpass(color_surface, depth_surface, render_area, true,
|
||||||
|
MakeClearValue(value));
|
||||||
renderpass_cache.ExitRenderpass();
|
renderpass_cache.ExitRenderpass();
|
||||||
|
|
||||||
scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([params, access_flag, pipeline_flags](vk::CommandBuffer cmdbuf) {
|
||||||
|
@@ -44,6 +44,7 @@ struct ImageAlloc {
|
|||||||
vk::ImageUsageFlags usage;
|
vk::ImageUsageFlags usage;
|
||||||
vk::Format format;
|
vk::Format format;
|
||||||
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
|
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
|
||||||
|
vk::ImageLayout layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HostTextureTag {
|
struct HostTextureTag {
|
||||||
@@ -152,13 +153,11 @@ private:
|
|||||||
const Instance& instance;
|
const Instance& instance;
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
RenderpassCache& renderpass_cache;
|
RenderpassCache& renderpass_cache;
|
||||||
DescriptorManager& desc_manager;
|
|
||||||
BlitHelper blit_helper;
|
BlitHelper blit_helper;
|
||||||
StreamBuffer upload_buffer;
|
StreamBuffer upload_buffer;
|
||||||
StreamBuffer download_buffer;
|
StreamBuffer download_buffer;
|
||||||
std::array<ReinterpreterList, VideoCore::PIXEL_FORMAT_COUNT> reinterpreters;
|
std::array<ReinterpreterList, VideoCore::PIXEL_FORMAT_COUNT> reinterpreters;
|
||||||
std::unordered_multimap<HostTextureTag, ImageAlloc> texture_recycler;
|
std::unordered_multimap<HostTextureTag, ImageAlloc> texture_recycler;
|
||||||
std::unordered_map<vk::ImageView, vk::Framebuffer> clear_framebuffers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Surface : public VideoCore::SurfaceBase<Surface> {
|
class Surface : public VideoCore::SurfaceBase<Surface> {
|
||||||
|
Reference in New Issue
Block a user