video_core: Fix destruction sequence
Rejoice! Vulkan no longer leaks memory
This commit is contained in:
@@ -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")
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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 {}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -60,7 +60,9 @@ Instance::Instance(Frontend::EmuWindow& window) {
|
||||
|
||||
Instance::~Instance() {
|
||||
device.waitIdle();
|
||||
vmaDestroyAllocator(allocator);
|
||||
device.destroy();
|
||||
instance.destroySurfaceKHR(surface);
|
||||
instance.destroy();
|
||||
}
|
||||
|
||||
|
@@ -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++]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user