diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index ccc39ddfe..22ddbf7bc 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -257,7 +257,6 @@ static std::shared_ptr s_fallback_disc_texture; static std::shared_ptr s_fallback_exe_texture; static std::shared_ptr s_fallback_psf_texture; static std::shared_ptr s_fallback_playlist_texture; -static std::vector> s_cleanup_textures; ////////////////////////////////////////////////////////////////////////// // Landing @@ -745,9 +744,6 @@ void FullscreenUI::Render() if (!s_initialized) return; - for (std::unique_ptr& tex : s_cleanup_textures) - tex.reset(); - s_cleanup_textures.clear(); ImGuiFullscreen::UploadAsyncTextures(); ImGuiFullscreen::BeginLayout(); @@ -867,8 +863,6 @@ void FullscreenUI::DestroyResources() s_fallback_disc_texture.reset(); for (auto& tex : s_game_compatibility_textures) tex.reset(); - for (auto& tex : s_cleanup_textures) - tex.reset(); } ////////////////////////////////////////////////////////////////////////// @@ -5089,16 +5083,15 @@ void FullscreenUI::PopulateSaveStateScreenshot(SaveStateListEntry* li, const Ext li->preview_texture.reset(); if (ssi && !ssi->screenshot_data.empty()) { - li->preview_texture = g_gpu_device->CreateTexture( + li->preview_texture = g_gpu_device->FetchTexture( ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, - ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false); + ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width); } else { - li->preview_texture = g_gpu_device->CreateTexture( + li->preview_texture = g_gpu_device->FetchTexture( Resources::PLACEHOLDER_ICON_WIDTH, Resources::PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH, - false); + GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH); } if (!li->preview_texture) @@ -5110,7 +5103,7 @@ void FullscreenUI::ClearSaveStateEntryList() for (SaveStateListEntry& entry : s_save_state_selector_slots) { if (entry.preview_texture) - s_cleanup_textures.push_back(std::move(entry.preview_texture)); + g_gpu_device->RecycleTexture(std::move(entry.preview_texture)); } s_save_state_selector_slots.clear(); } diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 7dfde3390..bc09e3293 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -2054,8 +2054,8 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const Common::Rectangl const GPUTexture::Format hdformat = g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8; - std::unique_ptr render_texture = - g_gpu_device->CreateTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat); + auto render_texture = + g_gpu_device->FetchAutoRecycleTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat); if (!render_texture) return false; diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index f43e147d1..678f7f7c4 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -290,8 +290,8 @@ bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di tex = g_gpu_device - ->CreateTexture(m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1, 1, m_vram_texture->GetSamples(), - GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8, nullptr, 0, false) + ->FetchTexture(m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1, 1, m_vram_texture->GetSamples(), + GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8, nullptr, 0) .release(); *host_texture = tex; if (!tex) @@ -627,18 +627,18 @@ bool GPU_HW::CreateBuffers() GPUTexture::Type::RWTexture : GPUTexture::Type::Texture; - if (!(m_vram_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, samples, - GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) || - !(m_vram_depth_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, samples, - GPUTexture::Type::DepthStencil, VRAM_DS_FORMAT)) || + if (!(m_vram_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples, + GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) || + !(m_vram_depth_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples, + GPUTexture::Type::DepthStencil, VRAM_DS_FORMAT)) || !(m_vram_read_texture = - g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, 1, read_texture_type, VRAM_RT_FORMAT)) || - !(m_display_private_texture = g_gpu_device->CreateTexture( + g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1, read_texture_type, VRAM_RT_FORMAT)) || + !(m_display_private_texture = g_gpu_device->FetchTexture( ((m_downsample_mode == GPUDownsampleMode::Adaptive) ? VRAM_WIDTH : GPU_MAX_DISPLAY_WIDTH) * m_resolution_scale, GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, 1, 1, 1, GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) || - !(m_vram_readback_texture = g_gpu_device->CreateTexture(VRAM_WIDTH / 2, VRAM_HEIGHT, 1, 1, 1, - GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT))) + !(m_vram_readback_texture = g_gpu_device->FetchTexture(VRAM_WIDTH / 2, VRAM_HEIGHT, 1, 1, 1, + GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT))) { return false; } @@ -661,13 +661,13 @@ bool GPU_HW::CreateBuffers() { const u32 levels = GetAdaptiveDownsamplingMipLevels(); - if (!(m_downsample_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, levels, 1, - GPUTexture::Type::Texture, VRAM_RT_FORMAT)) || - !(m_downsample_render_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, 1, - GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) || + if (!(m_downsample_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, levels, 1, + GPUTexture::Type::Texture, VRAM_RT_FORMAT)) || + !(m_downsample_render_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1, + GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) || !(m_downsample_weight_texture = - g_gpu_device->CreateTexture(texture_width >> (levels - 1), texture_height >> (levels - 1), 1, 1, 1, - GPUTexture::Type::RenderTarget, GPUTexture::Format::R8))) + g_gpu_device->FetchTexture(texture_width >> (levels - 1), texture_height >> (levels - 1), 1, 1, 1, + GPUTexture::Type::RenderTarget, GPUTexture::Format::R8))) { return false; } @@ -676,8 +676,8 @@ bool GPU_HW::CreateBuffers() { const u32 downsample_scale = GetBoxDownsampleScale(m_resolution_scale); if (!(m_downsample_render_texture = - g_gpu_device->CreateTexture(VRAM_WIDTH * downsample_scale, VRAM_HEIGHT * downsample_scale, 1, 1, 1, - GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT))) + g_gpu_device->FetchTexture(VRAM_WIDTH * downsample_scale, VRAM_HEIGHT * downsample_scale, 1, 1, 1, + GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT))) { return false; } @@ -702,14 +702,14 @@ void GPU_HW::DestroyBuffers() ClearDisplayTexture(); m_vram_upload_buffer.reset(); - m_downsample_weight_texture.reset(); - m_downsample_render_texture.reset(); - m_downsample_texture.reset(); - m_vram_read_texture.reset(); - m_vram_depth_texture.reset(); - m_vram_texture.reset(); - m_vram_readback_texture.reset(); - m_display_private_texture.reset(); + g_gpu_device->RecycleTexture(std::move(m_downsample_weight_texture)); + g_gpu_device->RecycleTexture(std::move(m_downsample_render_texture)); + g_gpu_device->RecycleTexture(std::move(m_downsample_texture)); + g_gpu_device->RecycleTexture(std::move(m_vram_read_texture)); + g_gpu_device->RecycleTexture(std::move(m_vram_depth_texture)); + g_gpu_device->RecycleTexture(std::move(m_vram_texture)); + g_gpu_device->RecycleTexture(std::move(m_vram_readback_texture)); + g_gpu_device->RecycleTexture(std::move(m_display_private_texture)); } bool GPU_HW::CompilePipelines() @@ -2018,11 +2018,11 @@ bool GPU_HW::BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u3 if (!m_vram_replacement_texture || m_vram_replacement_texture->GetWidth() < tex->GetWidth() || m_vram_replacement_texture->GetHeight() < tex->GetHeight()) { - m_vram_replacement_texture.reset(); + g_gpu_device->RecycleTexture(std::move(m_vram_replacement_texture)); if (!(m_vram_replacement_texture = - g_gpu_device->CreateTexture(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, tex->GetPixels(), tex->GetPitch(), true))) + g_gpu_device->FetchTexture(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GPUTexture::Type::DynamicTexture, + GPUTexture::Format::RGBA8, tex->GetPixels(), tex->GetPitch()))) { return false; } diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp index c3bdc2b7d..6ab034f30 100644 --- a/src/core/gpu_sw.cpp +++ b/src/core/gpu_sw.cpp @@ -31,6 +31,7 @@ GPU_SW::GPU_SW() GPU_SW::~GPU_SW() { + g_gpu_device->RecycleTexture(std::move(m_private_display_texture)); m_backend.Shutdown(); } @@ -98,9 +99,9 @@ GPUTexture* GPU_SW::GetDisplayTexture(u32 width, u32 height, GPUTexture::Format m_private_display_texture->GetHeight() != height || m_private_display_texture->GetFormat() != format) { ClearDisplayTexture(); - m_private_display_texture.reset(); + g_gpu_device->RecycleTexture(std::move(m_private_display_texture)); m_private_display_texture = - g_gpu_device->CreateTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, format, nullptr, 0, true); + g_gpu_device->FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::DynamicTexture, format, nullptr, 0); if (!m_private_display_texture) Log_ErrorPrintf("Failed to create %ux%u %u texture", width, height, static_cast(format)); } diff --git a/src/core/imgui_overlays.cpp b/src/core/imgui_overlays.cpp index 7ebd53e2b..4347cac2d 100644 --- a/src/core/imgui_overlays.cpp +++ b/src/core/imgui_overlays.cpp @@ -717,7 +717,13 @@ void SaveStateSelectorUI::Close(bool reset_slot) void SaveStateSelectorUI::RefreshList() { + for (ListEntry& entry : s_slots) + { + if (entry.preview_texture) + g_gpu_device->RecycleTexture(std::move(entry.preview_texture)); + } s_slots.clear(); + if (System::IsShutdown()) return; @@ -761,7 +767,10 @@ void SaveStateSelectorUI::DestroyTextures() Close(); for (ListEntry& entry : s_slots) - entry.preview_texture.reset(); + { + if (entry.preview_texture) + g_gpu_device->RecycleTexture(std::move(entry.preview_texture)); + } } void SaveStateSelectorUI::RefreshHotkeyLegend() @@ -815,23 +824,22 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn li->slot = slot; li->global = global; - li->preview_texture.reset(); - // Might not have a display yet, we're called at startup.. if (g_gpu_device) { + g_gpu_device->RecycleTexture(std::move(li->preview_texture)); + if (ssi && !ssi->screenshot_data.empty()) { - li->preview_texture = g_gpu_device->CreateTexture( + li->preview_texture = g_gpu_device->FetchTexture( ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, - ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width, false); + ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width); } else { - li->preview_texture = g_gpu_device->CreateTexture( + li->preview_texture = g_gpu_device->FetchTexture( Resources::PLACEHOLDER_ICON_WIDTH, Resources::PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH, - false); + GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH); } if (!li->preview_texture) @@ -850,10 +858,11 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, std::str if (g_gpu_device) { - li->preview_texture = g_gpu_device->CreateTexture( + g_gpu_device->RecycleTexture(std::move(li->preview_texture)); + + li->preview_texture = g_gpu_device->FetchTexture( Resources::PLACEHOLDER_ICON_WIDTH, Resources::PLACEHOLDER_ICON_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH, - false); + GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH); if (!li->preview_texture) Log_ErrorPrintf("Failed to upload save state image to GPU"); } diff --git a/src/core/system.cpp b/src/core/system.cpp index 1f731bd39..0a4a90b26 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -3894,6 +3894,7 @@ bool System::LoadRewindState(u32 skip_saves /*= 0*/, bool consume_state /*=true { while (skip_saves > 0 && !s_rewind_states.empty()) { + g_gpu_device->RecycleTexture(std::move(s_rewind_states.front().vram_texture)); s_rewind_states.pop_back(); skip_saves--; } diff --git a/src/util/d3d11_device.cpp b/src/util/d3d11_device.cpp index 460aa0445..a4eaaa329 100644 --- a/src/util/d3d11_device.cpp +++ b/src/util/d3d11_device.cpp @@ -601,6 +601,7 @@ bool D3D11Device::BeginPresent(bool skip_present) { // Note: Really slow on Intel... m_context->Flush(); + TrimTexturePool(); return false; } @@ -611,6 +612,7 @@ bool D3D11Device::BeginPresent(bool skip_present) (FAILED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) || !is_fullscreen)) { Host::SetFullscreen(false); + TrimTexturePool(); return false; } @@ -644,6 +646,8 @@ void D3D11Device::EndPresent() if (m_gpu_timing_enabled) KickTimestampQuery(); + + TrimTexturePool(); } GPUDevice::AdapterAndModeList D3D11Device::StaticGetAdapterAndModeList() diff --git a/src/util/d3d11_device.h b/src/util/d3d11_device.h index d41c3deb3..900d5cbd1 100644 --- a/src/util/d3d11_device.h +++ b/src/util/d3d11_device.h @@ -49,8 +49,7 @@ public: std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data = nullptr, u32 data_stride = 0, - bool dynamic = false) override; + const void* data = nullptr, u32 data_stride = 0) override; std::unique_ptr CreateSampler(const GPUSampler::Config& config) override; std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override; diff --git a/src/util/d3d11_texture.cpp b/src/util/d3d11_texture.cpp index e5b280e3d..a67a49342 100644 --- a/src/util/d3d11_texture.cpp +++ b/src/util/d3d11_texture.cpp @@ -21,10 +21,10 @@ Log_SetChannel(D3D11Device); std::unique_ptr D3D11Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data, u32 data_stride, bool dynamic /* = false */) + const void* data, u32 data_stride) { std::unique_ptr tex = std::make_unique(); - if (!tex->Create(m_device.Get(), width, height, layers, levels, samples, type, format, data, data_stride, dynamic)) + if (!tex->Create(m_device.Get(), width, height, layers, levels, samples, type, format, data, data_stride)) tex.reset(); return tex; @@ -199,7 +199,7 @@ bool D3D11Texture::IsValid() const bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/, u32 level /*= 0*/) { - if (m_dynamic) + if (m_type == Type::DynamicTexture) { void* map; u32 map_stride; @@ -225,8 +225,8 @@ bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, bool D3D11Texture::Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer /*= 0*/, u32 level /*= 0*/) { - if (!m_dynamic || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) || layer > m_layers || - level > m_levels) + if (m_type != Type::DynamicTexture || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) || + layer > m_layers || level > m_levels) { return false; } @@ -269,13 +269,14 @@ DXGI_FORMAT D3D11Texture::GetDXGIFormat() const } bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, - Format format, const void* initial_data /* = nullptr */, u32 initial_data_stride /* = 0 */, - bool dynamic /* = false */) + Format format, const void* initial_data /* = nullptr */, u32 initial_data_stride /* = 0 */) { if (!ValidateConfig(width, height, layers, layers, samples, type, format)) return false; u32 bind_flags = 0; + D3D11_USAGE usage = D3D11_USAGE_DEFAULT; + u32 cpu_access = 0; switch (type) { case Type::RenderTarget: @@ -287,6 +288,11 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer case Type::Texture: bind_flags = D3D11_BIND_SHADER_RESOURCE; break; + case Type::DynamicTexture: + bind_flags = D3D11_BIND_SHADER_RESOURCE; + usage = D3D11_USAGE_DYNAMIC; + cpu_access = D3D11_CPU_ACCESS_WRITE; + break; case Type::RWTexture: bind_flags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; break; @@ -296,9 +302,8 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format); - CD3D11_TEXTURE2D_DESC desc(fm.resource_format, width, height, layers, levels, bind_flags, - dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0, - samples, 0, 0); + CD3D11_TEXTURE2D_DESC desc(fm.resource_format, width, height, layers, levels, bind_flags, usage, cpu_access, samples, + 0, 0); D3D11_SUBRESOURCE_DATA srd; srd.pSysMem = initial_data; @@ -373,7 +378,6 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer m_samples = static_cast(samples); m_type = type; m_format = format; - m_dynamic = dynamic; return true; } @@ -383,7 +387,6 @@ void D3D11Texture::Destroy() m_rtv_dsv.Reset(); m_srv.Reset(); m_texture.Reset(); - m_dynamic = false; ClearBaseProperties(); } diff --git a/src/util/d3d11_texture.h b/src/util/d3d11_texture.h index 97c8c025a..4d6815d98 100644 --- a/src/util/d3d11_texture.h +++ b/src/util/d3d11_texture.h @@ -61,7 +61,6 @@ public: { return reinterpret_cast(m_rtv_dsv.GetAddressOf()); } - ALWAYS_INLINE bool IsDynamic() const { return m_dynamic; } DXGI_FORMAT GetDXGIFormat() const; ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); } @@ -77,7 +76,7 @@ public: ALWAYS_INLINE operator bool() const { return static_cast(m_texture); } bool Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, - Format format, const void* initial_data = nullptr, u32 initial_data_stride = 0, bool dynamic = false); + Format format, const void* initial_data = nullptr, u32 initial_data_stride = 0); void Destroy(); @@ -97,7 +96,6 @@ private: ComPtr m_srv; ComPtr m_rtv_dsv; u32 m_mapped_subresource = 0; - bool m_dynamic = false; }; class D3D11TextureBuffer final : public GPUTextureBuffer diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index c51c5b53e..ad59933fa 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -1067,6 +1067,7 @@ bool D3D12Device::BeginPresent(bool frame_skip) if (!m_swap_chain) { SubmitCommandList(false); + TrimTexturePool(); return false; } @@ -1079,6 +1080,7 @@ bool D3D12Device::BeginPresent(bool frame_skip) (FAILED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) || !is_fullscreen)) { Host::RunOnCPUThread([]() { Host::SetFullscreen(false); }); + TrimTexturePool(); return false; } @@ -1104,6 +1106,8 @@ void D3D12Device::EndPresent() m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING); else m_swap_chain->Present(static_cast(m_vsync_enabled), 0); + + TrimTexturePool(); } #ifdef _DEBUG diff --git a/src/util/d3d12_device.h b/src/util/d3d12_device.h index 177ccd5cb..8040ae1ac 100644 --- a/src/util/d3d12_device.h +++ b/src/util/d3d12_device.h @@ -70,8 +70,7 @@ public: std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data = nullptr, u32 data_stride = 0, - bool dynamic = false) override; + const void* data = nullptr, u32 data_stride = 0) override; std::unique_ptr CreateSampler(const GPUSampler::Config& config) override; std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override; diff --git a/src/util/d3d12_texture.cpp b/src/util/d3d12_texture.cpp index 3528adcef..0d7e4868a 100644 --- a/src/util/d3d12_texture.cpp +++ b/src/util/d3d12_texture.cpp @@ -36,8 +36,7 @@ D3D12Texture::~D3D12Texture() std::unique_ptr D3D12Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data /* = nullptr */, u32 data_stride /* = 0 */, - bool dynamic /* = false */) + const void* data /* = nullptr */, u32 data_stride /* = 0 */) { if (!GPUTexture::ValidateConfig(width, height, layers, levels, samples, type, format)) return {}; @@ -66,6 +65,7 @@ std::unique_ptr D3D12Device::CreateTexture(u32 width, u32 height, u3 switch (type) { case GPUTexture::Type::Texture: + case GPUTexture::Type::DynamicTexture: { desc.Flags = D3D12_RESOURCE_FLAG_NONE; state = D3D12_RESOURCE_STATE_COPY_DEST; @@ -329,7 +329,8 @@ ID3D12GraphicsCommandList4* D3D12Texture::GetCommandBufferForUpdate() if (m_type != Type::Texture || m_use_fence_counter == dev.GetCurrentFenceValue()) { // Console.WriteLn("Texture update within frame, can't use do beforehand"); - dev.EndRenderPass(); + if (dev.InRenderPass()) + dev.EndRenderPass(); return dev.GetCommandList(); } diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index ac47d96fa..5ec980b23 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -289,6 +289,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& void GPUDevice::Destroy() { + PurgeTexturePool(); if (HasSurface()) DestroySurface(); DestroyResources(); @@ -726,10 +727,11 @@ bool GPUDevice::UpdateImGuiFontTexture() } std::unique_ptr new_font = - CreateTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, pixels, pitch); + FetchTexture(width, height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, pixels, pitch); if (!new_font) return false; + RecycleTexture(std::move(m_imgui_font_texture)); m_imgui_font_texture = std::move(new_font); io.Fonts->SetTexID(m_imgui_font_texture.get()); return true; @@ -741,6 +743,108 @@ bool GPUDevice::UsesLowerLeftOrigin() const return (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES); } +std::unique_ptr GPUDevice::FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Type type, GPUTexture::Format format, + const void* data /*= nullptr*/, u32 data_stride /*= 0*/) +{ + std::unique_ptr ret; + + const TexturePoolKey key = {static_cast(width), + static_cast(height), + static_cast(layers), + static_cast(levels), + static_cast(samples), + type, + format, + 0u}; + + for (auto it = m_texture_pool.begin(); it != m_texture_pool.end(); ++it) + { + if (it->key == key) + { + if (data && !it->texture->Update(0, 0, width, height, data, data_stride, 0, 0)) + { + // This shouldn't happen... + Log_ErrorFmt("Failed to upload {}x{} to pooled texture", width, height); + break; + } + + ret = std::move(it->texture); + m_texture_pool.erase(it); + return ret; + } + } + + ret = CreateTexture(width, height, layers, levels, samples, type, format, data, data_stride); + return ret; +} + +std::unique_ptr +GPUDevice::FetchAutoRecycleTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, + GPUTexture::Format format, const void* data /*= nullptr*/, u32 data_stride /*= 0*/, + bool dynamic /*= false*/) +{ + std::unique_ptr ret = + FetchTexture(width, height, layers, levels, samples, type, format, data, data_stride); + return std::unique_ptr(ret.release()); +} + +void GPUDevice::RecycleTexture(std::unique_ptr texture) +{ + if (!texture) + return; + + u32 remove_count = m_texture_pool_counter + POOL_PURGE_DELAY; + if (remove_count < m_texture_pool_counter) + { + // wrapped around, handle it + if (m_texture_pool.empty()) + { + m_texture_pool_counter = 0; + remove_count = POOL_PURGE_DELAY; + } + else + { + const u32 reduce = m_texture_pool.front().remove_count; + m_texture_pool_counter -= reduce; + remove_count -= reduce; + } + } + + const TexturePoolKey key = {static_cast(texture->GetWidth()), + static_cast(texture->GetHeight()), + static_cast(texture->GetLayers()), + static_cast(texture->GetLevels()), + static_cast(texture->GetSamples()), + texture->GetType(), + texture->GetFormat(), + 0u}; + + m_texture_pool.push_back({std::move(texture), remove_count, key}); +} + +void GPUDevice::PurgeTexturePool() +{ + m_texture_pool_counter = 0; + m_texture_pool.clear(); +} + +void GPUDevice::TrimTexturePool() +{ + if (m_texture_pool.empty()) + return; + + const u32 counter = m_texture_pool_counter++; + for (auto it = m_texture_pool.begin(); it != m_texture_pool.end();) + { + if (counter < it->remove_count) + break; + + Log_ProfileFmt("Trim {}x{} texture from pool", it->texture->GetWidth(), it->texture->GetHeight()); + it = m_texture_pool.erase(it); + } +} + void GPUDevice::SetDisplayMaxFPS(float max_fps) { m_display_frame_interval = (max_fps > 0.0f) ? (1.0f / max_fps) : 0.0f; diff --git a/src/util/gpu_device.h b/src/util/gpu_device.h index dbd841d1b..6af36d9b6 100644 --- a/src/util/gpu_device.h +++ b/src/util/gpu_device.h @@ -13,6 +13,8 @@ #include "common/small_string.h" #include "common/types.h" +#include +#include #include #include #include @@ -457,6 +459,11 @@ public: std::vector fullscreen_modes; }; + struct PooledTextureDeleter + { + void operator()(GPUTexture* const tex); + }; + static constexpr u32 MAX_TEXTURE_SAMPLERS = 8; static constexpr u32 MIN_TEXEL_BUFFER_ELEMENTS = 4 * 1024 * 512; static constexpr u32 MAX_RENDER_TARGETS = 4; @@ -541,15 +548,24 @@ public: virtual std::string GetDriverInfo() const = 0; - /// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below. virtual std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data = nullptr, u32 data_stride = 0, - bool dynamic = false) = 0; + const void* data = nullptr, u32 data_stride = 0) = 0; virtual std::unique_ptr CreateSampler(const GPUSampler::Config& config) = 0; virtual std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) = 0; + // Texture pooling. + std::unique_ptr FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Type type, GPUTexture::Format format, const void* data = nullptr, + u32 data_stride = 0); + std::unique_ptr + FetchAutoRecycleTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, + GPUTexture::Format format, const void* data = nullptr, u32 data_stride = 0, + bool dynamic = false); + void RecycleTexture(std::unique_ptr texture); + void PurgeTexturePool(); + virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride) = 0; virtual void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src, @@ -644,6 +660,8 @@ protected: bool AcquireWindow(bool recreate_window); + void TrimTexturePool(); + Features m_features = {}; u32 m_max_texture_size = 0; u32 m_max_multisamples = 0; @@ -655,26 +673,64 @@ protected: std::unique_ptr m_nearest_sampler; std::unique_ptr m_linear_sampler; - bool m_gpu_timing_enabled = false; - bool m_vsync_enabled = false; - bool m_debug_device = false; - private: + static constexpr u32 POOL_PURGE_DELAY = 60; + + struct TexturePoolKey + { + u16 width; + u16 height; + u8 layers; + u8 levels; + u8 samples; + GPUTexture::Type type; + GPUTexture::Format format; + u8 pad; + + ALWAYS_INLINE bool operator==(const TexturePoolKey& rhs) const + { + return std::memcmp(this, &rhs, sizeof(TexturePoolKey)) == 0; + } + ALWAYS_INLINE bool operator!=(const TexturePoolKey& rhs) const + { + return std::memcmp(this, &rhs, sizeof(TexturePoolKey)) != 0; + } + }; + struct TexturePoolEntry + { + std::unique_ptr texture; + u32 remove_count; + TexturePoolKey key; + }; + void OpenShaderCache(const std::string_view& base_path, u32 version); void CloseShaderCache(); bool CreateResources(); void DestroyResources(); + std::unique_ptr m_imgui_pipeline; + std::unique_ptr m_imgui_font_texture; + + std::deque m_texture_pool; + u32 m_texture_pool_counter = 0; + // TODO: Move out. u64 m_last_frame_displayed_time = 0; float m_display_frame_interval = 0.0f; - std::unique_ptr m_imgui_pipeline; - std::unique_ptr m_imgui_font_texture; +protected: + bool m_gpu_timing_enabled = false; + bool m_vsync_enabled = false; + bool m_debug_device = false; }; extern std::unique_ptr g_gpu_device; +ALWAYS_INLINE void GPUDevice::PooledTextureDeleter::operator()(GPUTexture* const tex) +{ + g_gpu_device->RecycleTexture(std::unique_ptr(tex)); +} + namespace Host { /// Called when the core is creating a render device. /// This could also be fullscreen transition. diff --git a/src/util/gpu_texture.cpp b/src/util/gpu_texture.cpp index ea3126cf1..d1b10a146 100644 --- a/src/util/gpu_texture.cpp +++ b/src/util/gpu_texture.cpp @@ -126,13 +126,13 @@ bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u return false; } - if (layers > 1 && type != Type::Texture) + if (layers > 1 && type != Type::Texture && type != Type::DynamicTexture) { Log_ErrorPrintf("Texture arrays are not supported on targets."); return false; } - if (levels > 1 && type != Type::Texture) + if (levels > 1 && type != Type::Texture && type != Type::DynamicTexture) { Log_ErrorPrintf("Mipmaps are not supported on targets."); return false; diff --git a/src/util/gpu_texture.h b/src/util/gpu_texture.h index 1f81ca0d1..8fbc22ed0 100644 --- a/src/util/gpu_texture.h +++ b/src/util/gpu_texture.h @@ -28,6 +28,7 @@ public: RenderTarget, DepthStencil, Texture, + DynamicTexture, RWTexture, }; @@ -100,7 +101,8 @@ public: } ALWAYS_INLINE bool IsRenderTarget() const { return (m_type == Type::RenderTarget); } ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); } - ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture); } + ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture || m_type == Type::DynamicTexture); } + ALWAYS_INLINE bool IsDynamicTexture() const { return (m_type == Type::DynamicTexture); } ALWAYS_INLINE const ClearValue& GetClearValue() const { return m_clear_value; } ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; } @@ -152,6 +154,7 @@ protected: u8 m_samples = 0; Type m_type = Type::Unknown; Format m_format = Format::Unknown; + State m_state = State::Dirty; ClearValue m_clear_value = {}; diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index fb1b5b1b3..e21af5f4f 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -281,8 +281,8 @@ std::optional ImGuiFullscreen::LoadTextureImage(const char* std::shared_ptr ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image) { std::unique_ptr texture = - g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); + g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, + GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); if (!texture) { Log_ErrorPrintf("failed to create %ux%u texture for resource", image.GetWidth(), image.GetHeight()); @@ -290,7 +290,7 @@ std::shared_ptr ImGuiFullscreen::UploadTexture(const char* path, con } Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight()); - return std::shared_ptr(std::move(texture)); + return std::shared_ptr(texture.release(), GPUDevice::PooledTextureDeleter()); } std::shared_ptr ImGuiFullscreen::LoadTexture(const std::string_view& path) diff --git a/src/util/imgui_manager.cpp b/src/util/imgui_manager.cpp index d5f8721b4..53762ad79 100644 --- a/src/util/imgui_manager.cpp +++ b/src/util/imgui_manager.cpp @@ -1035,8 +1035,9 @@ void ImGuiManager::UpdateSoftwareCursorTexture(u32 index) Log_ErrorPrintf("Failed to load software cursor %u image '%s'", index, sc.image_path.c_str()); return; } - sc.texture = g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); + g_gpu_device->RecycleTexture(std::move(sc.texture)); + sc.texture = g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, + GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); if (!sc.texture) { Log_ErrorPrintf("Failed to upload %ux%u software cursor %u image '%s'", image.GetWidth(), image.GetHeight(), index, diff --git a/src/util/metal_device.h b/src/util/metal_device.h index 186bcaa60..b121cbcd5 100644 --- a/src/util/metal_device.h +++ b/src/util/metal_device.h @@ -187,8 +187,7 @@ public: std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data = nullptr, u32 data_stride = 0, - bool dynamic = false) override; + const void* data = nullptr, u32 data_stride = 0) override; std::unique_ptr CreateSampler(const GPUSampler::Config& config) override; std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override; diff --git a/src/util/metal_device.mm b/src/util/metal_device.mm index 16d1c0bf1..effce55ca 100644 --- a/src/util/metal_device.mm +++ b/src/util/metal_device.mm @@ -1043,7 +1043,7 @@ void MetalTexture::Destroy() std::unique_ptr MetalDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data, u32 data_stride, bool dynamic /* = false */) + const void* data, u32 data_stride) { if (!GPUTexture::ValidateConfig(width, height, layers, layers, samples, type, format)) return {}; @@ -1073,6 +1073,7 @@ std::unique_ptr MetalDevice::CreateTexture(u32 width, u32 height, u3 switch (type) { case GPUTexture::Type::Texture: + case GPUTexture::Type::DynamicTexture: desc.usage = MTLTextureUsageShaderRead; break; @@ -1977,14 +1978,23 @@ bool MetalDevice::BeginPresent(bool skip_present) { @autoreleasepool { - if (skip_present || m_layer == nil) + if (skip_present) return false; + if (m_layer == nil) + { + TrimTexturePool(); + return false; + } + EndAnyEncoding(); m_layer_drawable = [[m_layer nextDrawable] retain]; if (m_layer_drawable == nil) + { + TrimTexturePool(); return false; + } SetViewportAndScissor(0, 0, m_window_info.surface_width, m_window_info.surface_height); @@ -2012,6 +2022,7 @@ void MetalDevice::EndPresent() [m_layer_drawable release]; m_layer_drawable = nil; SubmitCommandBuffer(); + TrimTexturePool(); } void MetalDevice::CreateCommandBuffer() diff --git a/src/util/opengl_device.cpp b/src/util/opengl_device.cpp index 2199415ae..7a408db78 100644 --- a/src/util/opengl_device.cpp +++ b/src/util/opengl_device.cpp @@ -50,7 +50,7 @@ RenderAPI OpenGLDevice::GetRenderAPI() const std::unique_ptr OpenGLDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data, u32 data_stride, bool dynamic /* = false */) + const void* data, u32 data_stride) { std::unique_ptr tex(std::make_unique()); if (!tex->Create(width, height, layers, levels, samples, type, format, data, data_stride)) @@ -764,7 +764,11 @@ bool OpenGLDevice::BeginPresent(bool skip_present) if (skip_present || m_window_info.type == WindowInfo::Type::Surfaceless) { if (!skip_present) + { glFlush(); + TrimTexturePool(); + } + return false; } @@ -802,6 +806,8 @@ void OpenGLDevice::EndPresent() if (m_gpu_timing_enabled) KickTimestampQuery(); + + TrimTexturePool(); } void OpenGLDevice::CreateTimestampQueries() diff --git a/src/util/opengl_device.h b/src/util/opengl_device.h index e609d109d..47b2d73e4 100644 --- a/src/util/opengl_device.h +++ b/src/util/opengl_device.h @@ -49,8 +49,7 @@ public: std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data = nullptr, u32 data_stride = 0, - bool dynamic = false) override; + const void* data = nullptr, u32 data_stride = 0) override; std::unique_ptr CreateSampler(const GPUSampler::Config& config) override; std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override; diff --git a/src/util/postprocessing.cpp b/src/util/postprocessing.cpp index fdb164c07..0acaea9d8 100644 --- a/src/util/postprocessing.cpp +++ b/src/util/postprocessing.cpp @@ -588,7 +588,7 @@ bool PostProcessing::ReloadShaders() void PostProcessing::Shutdown() { - s_dummy_texture.reset(); + g_gpu_device->RecycleTexture(std::move(s_dummy_texture)); s_samplers.clear(); s_enabled = false; decltype(s_stages)().swap(s_stages); @@ -625,8 +625,8 @@ GPUTexture* PostProcessing::GetDummyTexture() return s_dummy_texture.get(); const u32 zero = 0; - s_dummy_texture = g_gpu_device->CreateTexture(1, 1, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, - &zero, sizeof(zero)); + s_dummy_texture = g_gpu_device->FetchTexture(1, 1, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8, + &zero, sizeof(zero)); if (!s_dummy_texture) Log_ErrorPrint("Failed to create dummy texture."); @@ -641,10 +641,10 @@ bool PostProcessing::CheckTargets(GPUTexture::Format target_format, u32 target_w // In case any allocs fail. DestroyTextures(); - if (!(s_input_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1, - GPUTexture::Type::RenderTarget, target_format)) || - !(s_output_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1, - GPUTexture::Type::RenderTarget, target_format))) + if (!(s_input_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, + GPUTexture::Type::RenderTarget, target_format)) || + !(s_output_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1, + GPUTexture::Type::RenderTarget, target_format))) { return false; } @@ -675,8 +675,8 @@ void PostProcessing::DestroyTextures() s_target_width = 0; s_target_height = 0; - s_output_texture.reset(); - s_input_texture.reset(); + g_gpu_device->RecycleTexture(std::move(s_output_texture)); + g_gpu_device->RecycleTexture(std::move(s_input_texture)); } bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, diff --git a/src/util/postprocessing_shader_fx.cpp b/src/util/postprocessing_shader_fx.cpp index ebe0c2fd6..8a5c2f88e 100644 --- a/src/util/postprocessing_shader_fx.cpp +++ b/src/util/postprocessing_shader_fx.cpp @@ -273,7 +273,11 @@ static GPUPipeline::Primitive MapPrimitive(reshadefx::primitive_topology topolog PostProcessing::ReShadeFXShader::ReShadeFXShader() = default; -PostProcessing::ReShadeFXShader::~ReShadeFXShader() = default; +PostProcessing::ReShadeFXShader::~ReShadeFXShader() +{ + for (Texture& tex : m_textures) + g_gpu_device->RecycleTexture(std::move(tex.texture)); +} bool PostProcessing::ReShadeFXShader::LoadFromFile(std::string name, std::string filename, bool only_config, Error* error) @@ -936,8 +940,8 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer } tex.rt_scale = 0.0f; - tex.texture = g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, - GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); + tex.texture = g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture, + GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); if (!tex.texture) { Error::SetString( @@ -1249,11 +1253,11 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3 if (tex.rt_scale == 0.0f) continue; - tex.texture.reset(); + g_gpu_device->RecycleTexture(std::move(tex.texture)); const u32 t_width = std::max(static_cast(static_cast(width) * tex.rt_scale), 1u); const u32 t_height = std::max(static_cast(static_cast(height) * tex.rt_scale), 1u); - tex.texture = g_gpu_device->CreateTexture(t_width, t_height, 1, 1, 1, GPUTexture::Type::RenderTarget, tex.format); + tex.texture = g_gpu_device->FetchTexture(t_width, t_height, 1, 1, 1, GPUTexture::Type::RenderTarget, tex.format); if (!tex.texture) { Log_ErrorPrintf("Failed to create %ux%u texture", t_width, t_height); diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 4add90897..0a37fa7b9 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -2184,6 +2184,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip) if (!m_swap_chain) { SubmitCommandBuffer(false); + TrimTexturePool(); return false; } @@ -2194,6 +2195,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip) if (CheckLastSubmitFail()) { Panic("Fixme"); // TODO + TrimTexturePool(); return false; } @@ -2214,6 +2216,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip) { Log_ErrorPrintf("Failed to recreate surface after loss"); SubmitCommandBuffer(false); + TrimTexturePool(); return false; } @@ -2227,6 +2230,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip) // Still submit the command buffer, otherwise we'll end up with several frames waiting. LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: "); SubmitCommandBuffer(false); + TrimTexturePool(); return false; } } @@ -2247,6 +2251,7 @@ void VulkanDevice::EndPresent() SubmitCommandBuffer(m_swap_chain.get(), !m_swap_chain->IsPresentModeSynchronizing()); MoveToNextCommandBuffer(); InvalidateCachedState(); + TrimTexturePool(); } #ifdef _DEBUG diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index 06f6cb0e2..26f946b13 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -72,8 +72,7 @@ public: std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data = nullptr, u32 data_stride = 0, - bool dynamic = false) override; + const void* data = nullptr, u32 data_stride = 0) override; std::unique_ptr CreateSampler(const GPUSampler::Config& config) override; std::unique_ptr CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override; diff --git a/src/util/vulkan_texture.cpp b/src/util/vulkan_texture.cpp index 74593d801..b50c3fa48 100644 --- a/src/util/vulkan_texture.cpp +++ b/src/util/vulkan_texture.cpp @@ -100,6 +100,7 @@ std::unique_ptr VulkanTexture::Create(u32 width, u32 height, u32 switch (type) { case Type::Texture: + case Type::DynamicTexture: { ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; } @@ -716,8 +717,7 @@ void VulkanTexture::MakeReadyForSampling() std::unique_ptr VulkanDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, - const void* data /* = nullptr */, u32 data_stride /* = 0 */, - bool dynamic /* = false */) + const void* data /* = nullptr */, u32 data_stride /* = 0 */) { const VkFormat vk_format = VulkanDevice::TEXTURE_FORMAT_MAPPING[static_cast(format)]; std::unique_ptr tex =