video_core: Fix destruction sequence

Rejoice! Vulkan no longer leaks memory
This commit is contained in:
emufan4568
2022-08-12 15:36:09 +03:00
parent a2ca75bff4
commit 734077642e
12 changed files with 52 additions and 22 deletions

View File

@@ -19,7 +19,7 @@ endif()
# Install a package using the command line interface
function(vcpkg_add_package PKG_NAME)
# Run the executable to install dependencies
set(VCPKG_TARGET_TRIPLET_FLAG "--triplet=${VCPKG_TARGET_TRIPLET}")
set(VCPKG_TARGET_TRIPLET_FLAG "--triplet=x64-windows-static")
message(STATUS "VCPKG: Installing ${PKG_NAME}")
execute_process(COMMAND ${VCPKG_EXECUTABLE} ${VCPKG_TARGET_TRIPLET_FLAG} ${VCPKG_RECURSE_REBUILD_FLAG} --disable-metrics install "${PKG_NAME}" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE VCPKG_INSTALL_OK)
if (NOT VCPKG_INSTALL_OK EQUAL "0")

View File

@@ -32,6 +32,9 @@ public:
// Triggers a swapchain buffer swap
virtual void EndPresent() = 0;
// Submits any pending work and blocks the host until it completes
virtual void Flush() = 0;
// Returns the framebuffer created from the swapchain images
virtual FramebufferHandle GetWindowFramebuffer() = 0;

View File

@@ -56,7 +56,8 @@ layout (std140, push_constant) uniform PresentUniformData {
};
void main() {
color = texture(sampler2D(top_screen, screen_sampler), frag_tex_coord);
//color = texture(sampler2D(top_screen, screen_sampler), frag_tex_coord);
color = vec4(1.f, 0.f, 0.f, 1.f);
}
)";
@@ -158,7 +159,7 @@ DisplayRenderer::DisplayRenderer(Frontend::EmuWindow& window) : render_window(wi
// Create vertex buffer for the screen rectangle
const BufferInfo vertex_info = {
.capacity = sizeof(ScreenRectVertex) * 10,
.capacity = sizeof(ScreenRectVertex) * 16,
.usage = BufferUsage::Vertex
};
@@ -207,6 +208,11 @@ DisplayRenderer::DisplayRenderer(Frontend::EmuWindow& window) : render_window(wi
present_pipelines[0]->BindSampler(1, 0, screen_sampler);
}
DisplayRenderer::~DisplayRenderer() {
// Must flush the backend before destroying any pipelines!
backend->Flush();
}
void DisplayRenderer::PrepareRendertarget() {
for (int i = 0; i < 3; i++) {
int fb_id = i == 2 ? 1 : 0;
@@ -387,8 +393,8 @@ void DisplayRenderer::DrawSingleScreen(u32 screen, bool rotate, float x, float y
}
const u32 size = sizeof(ScreenRectVertex) * vertices.size();
const u64 mapped_offset = vertex_buffer->GetCurrentOffset();
auto vertex_data = vertex_buffer->Map(size);
const u64 mapped_offset = vertex_buffer->GetCurrentOffset();
// Copy vertex data
std::memcpy(vertex_data.data(), vertices.data(), size);

View File

@@ -67,7 +67,7 @@ constexpr u32 PRESENT_PIPELINES = 3;
class DisplayRenderer {
public:
DisplayRenderer(Frontend::EmuWindow& window);
~DisplayRenderer() = default;
~DisplayRenderer();
void SwapBuffers();
void TryPresent(int timeout_ms) {}
@@ -121,8 +121,8 @@ private:
void LoadColorToActiveTexture(u8 color_r, u8 color_g, u8 color_b, const ScreenInfo& screen);
private:
std::unique_ptr<VideoCore::Rasterizer> rasterizer;
std::unique_ptr<BackendBase> backend;
std::unique_ptr<VideoCore::Rasterizer> rasterizer;
Frontend::EmuWindow& render_window;
Common::Vec4f clear_color;
f32 m_current_fps = 0.0f;

View File

@@ -81,7 +81,11 @@ Backend::Backend(Frontend::EmuWindow& window) : BackendBase(window),
}
Backend::~Backend() {
// Wait for all GPU operations to finish before continuing
vk::Device device = instance.GetDevice();
device.waitIdle();
device.destroyPipelineCache(pipeline_cache);
for (u32 pool = 0; pool < SCHEDULER_COMMAND_COUNT; pool++) {
@@ -100,10 +104,14 @@ bool Backend::BeginPresent() {
}
void Backend::EndPresent() {
scheduler.Submit(false, swapchain.GetAvailableSemaphore(), swapchain.GetPresentSemaphore());
scheduler.Submit(false, true, swapchain.GetAvailableSemaphore(), swapchain.GetPresentSemaphore());
swapchain.Present();
}
void Backend::Flush() {
scheduler.Submit(true);
}
FramebufferHandle Backend::GetWindowFramebuffer() {
auto framebuffer = swapchain.GetCurrentFramebuffer();
auto extent = swapchain.GetExtent();

View File

@@ -21,11 +21,10 @@ public:
bool BeginPresent() override;
void EndPresent() override;
void Flush() override;
FramebufferHandle GetWindowFramebuffer() override;
u64 QueryDriver(Query query) override { return 0; }
u64 PipelineInfoHash(const PipelineInfo& info) override;
BufferHandle CreateBuffer(BufferInfo info) override;
@@ -40,10 +39,8 @@ public:
void Draw(PipelineHandle pipeline, FramebufferHandle draw_framebuffer,
u32 base_vertex, u32 num_vertices) override;
void DrawIndexed(PipelineHandle pipeline, FramebufferHandle draw_framebuffer,
u32 base_index, u32 num_indices, u32 base_vertex) override;
void DispatchCompute(PipelineHandle pipeline, Common::Vec3<u32> groupsize,
Common::Vec3<u32> groups) override {}

View File

@@ -148,7 +148,7 @@ void Buffer::Commit(u32 size) {
if (info.usage == BufferUsage::Staging && size > 0) {
vmaFlushAllocation(allocator, allocation, buffer_offset, size);
} else {
vk::CommandBuffer command_buffer = scheduler.GetUploadCommandBuffer();
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
Buffer& staging = scheduler.GetCommandUploadBuffer();
const vk::BufferCopy copy_region = {
@@ -158,6 +158,7 @@ void Buffer::Commit(u32 size) {
};
// Copy staging buffer to device local buffer
staging.Commit(size);
command_buffer.copyBuffer(staging.GetHandle(), buffer, copy_region);
vk::AccessFlags access_mask;
@@ -184,6 +185,8 @@ void Buffer::Commit(u32 size) {
const vk::BufferMemoryBarrier buffer_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = access_mask,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffer,
.offset = buffer_offset,
.size = size

View File

@@ -60,7 +60,9 @@ Instance::Instance(Frontend::EmuWindow& window) {
Instance::~Instance() {
device.waitIdle();
vmaDestroyAllocator(allocator);
device.destroy();
instance.destroySurfaceKHR(surface);
instance.destroy();
}

View File

@@ -183,7 +183,7 @@ PipelineOwner::~PipelineOwner() {
u32 i = 0;
while (set_layouts[i] && update_templates[i]) {
device.destroyDescriptorSetLayout(set_layouts[i]);
device.destroyDescriptorUpdateTemplate(update_templates[i]);
device.destroyDescriptorUpdateTemplate(update_templates[i++]);
}
}

View File

@@ -36,7 +36,7 @@ private:
// Special renderpass used for rendering to the swapchain
vk::RenderPass present_renderpass;
// [color_format][depth_format][is_clear_pass]
vk::RenderPass cached_renderpasses[MAX_COLOR_FORMATS][MAX_DEPTH_FORMATS][2];
vk::RenderPass cached_renderpasses[MAX_COLOR_FORMATS+1][MAX_DEPTH_FORMATS+1][2];
};
} // namespace VideoCore::Vulkan

View File

@@ -64,6 +64,9 @@ CommandScheduler::~CommandScheduler() {
vk::Device device = instance.GetDevice();
VmaAllocator allocator = instance.GetAllocator();
// Submit any remaining work
Submit(true, false);
for (auto& command : commands) {
device.destroyFence(command.fence);
@@ -110,10 +113,11 @@ void CommandScheduler::SetSwitchCallback(std::function<void(u32)> callback) {
switch_callback = callback;
}
void CommandScheduler::Submit(bool wait_completion, vk::Semaphore wait_semaphore, vk::Semaphore signal_semaphore) {
const CommandSlot& command = commands[current_command];
void CommandScheduler::Submit(bool wait_completion, bool begin_next,
vk::Semaphore wait_semaphore, vk::Semaphore signal_semaphore) {
// End command buffers
const CommandSlot& command = commands[current_command];
command.render_command_buffer.end();
if (command.use_upload_buffer) {
command.upload_command_buffer.end();
@@ -126,9 +130,14 @@ void CommandScheduler::Submit(bool wait_completion, vk::Semaphore wait_semaphore
const u32 signal_semaphore_count = signal_semaphore ? 1u : 0u;
const u32 wait_semaphore_count = wait_semaphore ? 1u : 0u;
const u32 command_buffer_count = command.use_upload_buffer ? 2u : 1u;
const std::array command_buffers = { command.render_command_buffer,
command.upload_command_buffer };
u32 command_buffer_count = 0;
std::array<vk::CommandBuffer, 2> command_buffers;
if (command.use_upload_buffer) {
command_buffers[command_buffer_count++] = command.upload_command_buffer;
}
command_buffers[command_buffer_count++] = command.render_command_buffer;
// Prepeare submit info
const vk::SubmitInfo submit_info = {
@@ -151,7 +160,9 @@ void CommandScheduler::Submit(bool wait_completion, vk::Semaphore wait_semaphore
}
// Switch to next cmdbuffer.
SwitchSlot();
if (begin_next) {
SwitchSlot();
}
}
void CommandScheduler::Schedule(std::function<void(vk::Device, VmaAllocator)>&& func) {

View File

@@ -37,8 +37,8 @@ public:
void Schedule(std::function<void(vk::Device, VmaAllocator)>&& func);
// Submits the current command to the graphics queue
void Submit(bool wait_completion = false, vk::Semaphore wait = VK_NULL_HANDLE,
vk::Semaphore signal = VK_NULL_HANDLE);
void Submit(bool wait_completion = false, bool begin_next = true,
vk::Semaphore wait = VK_NULL_HANDLE, vk::Semaphore signal = VK_NULL_HANDLE);
// Returns the command buffer used for early upload operations.
// This is useful for vertex/uniform buffer uploads that happen once per frame