mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 07:35:41 +00:00
GPUDevice: Pool textures
This commit is contained in:
parent
3b2c70cda5
commit
a907e1f550
|
@ -257,7 +257,6 @@ static std::shared_ptr<GPUTexture> s_fallback_disc_texture;
|
||||||
static std::shared_ptr<GPUTexture> s_fallback_exe_texture;
|
static std::shared_ptr<GPUTexture> s_fallback_exe_texture;
|
||||||
static std::shared_ptr<GPUTexture> s_fallback_psf_texture;
|
static std::shared_ptr<GPUTexture> s_fallback_psf_texture;
|
||||||
static std::shared_ptr<GPUTexture> s_fallback_playlist_texture;
|
static std::shared_ptr<GPUTexture> s_fallback_playlist_texture;
|
||||||
static std::vector<std::unique_ptr<GPUTexture>> s_cleanup_textures;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Landing
|
// Landing
|
||||||
|
@ -745,9 +744,6 @@ void FullscreenUI::Render()
|
||||||
if (!s_initialized)
|
if (!s_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (std::unique_ptr<GPUTexture>& tex : s_cleanup_textures)
|
|
||||||
tex.reset();
|
|
||||||
s_cleanup_textures.clear();
|
|
||||||
ImGuiFullscreen::UploadAsyncTextures();
|
ImGuiFullscreen::UploadAsyncTextures();
|
||||||
|
|
||||||
ImGuiFullscreen::BeginLayout();
|
ImGuiFullscreen::BeginLayout();
|
||||||
|
@ -867,8 +863,6 @@ void FullscreenUI::DestroyResources()
|
||||||
s_fallback_disc_texture.reset();
|
s_fallback_disc_texture.reset();
|
||||||
for (auto& tex : s_game_compatibility_textures)
|
for (auto& tex : s_game_compatibility_textures)
|
||||||
tex.reset();
|
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();
|
li->preview_texture.reset();
|
||||||
if (ssi && !ssi->screenshot_data.empty())
|
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_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
|
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,
|
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,
|
GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!li->preview_texture)
|
if (!li->preview_texture)
|
||||||
|
@ -5110,7 +5103,7 @@ void FullscreenUI::ClearSaveStateEntryList()
|
||||||
for (SaveStateListEntry& entry : s_save_state_selector_slots)
|
for (SaveStateListEntry& entry : s_save_state_selector_slots)
|
||||||
{
|
{
|
||||||
if (entry.preview_texture)
|
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();
|
s_save_state_selector_slots.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2054,8 +2054,8 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const Common::Rectangl
|
||||||
const GPUTexture::Format hdformat =
|
const GPUTexture::Format hdformat =
|
||||||
g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8;
|
g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8;
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> render_texture =
|
auto render_texture =
|
||||||
g_gpu_device->CreateTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat);
|
g_gpu_device->FetchAutoRecycleTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat);
|
||||||
if (!render_texture)
|
if (!render_texture)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -290,8 +290,8 @@ bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
|
||||||
|
|
||||||
tex =
|
tex =
|
||||||
g_gpu_device
|
g_gpu_device
|
||||||
->CreateTexture(m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1, 1, m_vram_texture->GetSamples(),
|
->FetchTexture(m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1, 1, m_vram_texture->GetSamples(),
|
||||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8, nullptr, 0, false)
|
GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8, nullptr, 0)
|
||||||
.release();
|
.release();
|
||||||
*host_texture = tex;
|
*host_texture = tex;
|
||||||
if (!tex)
|
if (!tex)
|
||||||
|
@ -627,17 +627,17 @@ bool GPU_HW::CreateBuffers()
|
||||||
GPUTexture::Type::RWTexture :
|
GPUTexture::Type::RWTexture :
|
||||||
GPUTexture::Type::Texture;
|
GPUTexture::Type::Texture;
|
||||||
|
|
||||||
if (!(m_vram_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, samples,
|
if (!(m_vram_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
||||||
!(m_vram_depth_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, samples,
|
!(m_vram_depth_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, samples,
|
||||||
GPUTexture::Type::DepthStencil, VRAM_DS_FORMAT)) ||
|
GPUTexture::Type::DepthStencil, VRAM_DS_FORMAT)) ||
|
||||||
!(m_vram_read_texture =
|
!(m_vram_read_texture =
|
||||||
g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, 1, read_texture_type, VRAM_RT_FORMAT)) ||
|
g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1, read_texture_type, VRAM_RT_FORMAT)) ||
|
||||||
!(m_display_private_texture = g_gpu_device->CreateTexture(
|
!(m_display_private_texture = g_gpu_device->FetchTexture(
|
||||||
((m_downsample_mode == GPUDownsampleMode::Adaptive) ? VRAM_WIDTH : GPU_MAX_DISPLAY_WIDTH) *
|
((m_downsample_mode == GPUDownsampleMode::Adaptive) ? VRAM_WIDTH : GPU_MAX_DISPLAY_WIDTH) *
|
||||||
m_resolution_scale,
|
m_resolution_scale,
|
||||||
GPU_MAX_DISPLAY_HEIGHT * m_resolution_scale, 1, 1, 1, GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
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,
|
!(m_vram_readback_texture = g_gpu_device->FetchTexture(VRAM_WIDTH / 2, VRAM_HEIGHT, 1, 1, 1,
|
||||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)))
|
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -661,12 +661,12 @@ bool GPU_HW::CreateBuffers()
|
||||||
{
|
{
|
||||||
const u32 levels = GetAdaptiveDownsamplingMipLevels();
|
const u32 levels = GetAdaptiveDownsamplingMipLevels();
|
||||||
|
|
||||||
if (!(m_downsample_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, levels, 1,
|
if (!(m_downsample_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, levels, 1,
|
||||||
GPUTexture::Type::Texture, VRAM_RT_FORMAT)) ||
|
GPUTexture::Type::Texture, VRAM_RT_FORMAT)) ||
|
||||||
!(m_downsample_render_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, 1,
|
!(m_downsample_render_texture = g_gpu_device->FetchTexture(texture_width, texture_height, 1, 1, 1,
|
||||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
||||||
!(m_downsample_weight_texture =
|
!(m_downsample_weight_texture =
|
||||||
g_gpu_device->CreateTexture(texture_width >> (levels - 1), texture_height >> (levels - 1), 1, 1, 1,
|
g_gpu_device->FetchTexture(texture_width >> (levels - 1), texture_height >> (levels - 1), 1, 1, 1,
|
||||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::R8)))
|
GPUTexture::Type::RenderTarget, GPUTexture::Format::R8)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -676,7 +676,7 @@ bool GPU_HW::CreateBuffers()
|
||||||
{
|
{
|
||||||
const u32 downsample_scale = GetBoxDownsampleScale(m_resolution_scale);
|
const u32 downsample_scale = GetBoxDownsampleScale(m_resolution_scale);
|
||||||
if (!(m_downsample_render_texture =
|
if (!(m_downsample_render_texture =
|
||||||
g_gpu_device->CreateTexture(VRAM_WIDTH * downsample_scale, VRAM_HEIGHT * downsample_scale, 1, 1, 1,
|
g_gpu_device->FetchTexture(VRAM_WIDTH * downsample_scale, VRAM_HEIGHT * downsample_scale, 1, 1, 1,
|
||||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)))
|
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -702,14 +702,14 @@ void GPU_HW::DestroyBuffers()
|
||||||
ClearDisplayTexture();
|
ClearDisplayTexture();
|
||||||
|
|
||||||
m_vram_upload_buffer.reset();
|
m_vram_upload_buffer.reset();
|
||||||
m_downsample_weight_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_downsample_weight_texture));
|
||||||
m_downsample_render_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_downsample_render_texture));
|
||||||
m_downsample_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_downsample_texture));
|
||||||
m_vram_read_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_vram_read_texture));
|
||||||
m_vram_depth_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_vram_depth_texture));
|
||||||
m_vram_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_vram_texture));
|
||||||
m_vram_readback_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_vram_readback_texture));
|
||||||
m_display_private_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_display_private_texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU_HW::CompilePipelines()
|
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() ||
|
if (!m_vram_replacement_texture || m_vram_replacement_texture->GetWidth() < tex->GetWidth() ||
|
||||||
m_vram_replacement_texture->GetHeight() < tex->GetHeight())
|
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 =
|
if (!(m_vram_replacement_texture =
|
||||||
g_gpu_device->CreateTexture(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
g_gpu_device->FetchTexture(tex->GetWidth(), tex->GetHeight(), 1, 1, 1, GPUTexture::Type::DynamicTexture,
|
||||||
GPUTexture::Format::RGBA8, tex->GetPixels(), tex->GetPitch(), true)))
|
GPUTexture::Format::RGBA8, tex->GetPixels(), tex->GetPitch())))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ GPU_SW::GPU_SW()
|
||||||
|
|
||||||
GPU_SW::~GPU_SW()
|
GPU_SW::~GPU_SW()
|
||||||
{
|
{
|
||||||
|
g_gpu_device->RecycleTexture(std::move(m_private_display_texture));
|
||||||
m_backend.Shutdown();
|
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)
|
m_private_display_texture->GetHeight() != height || m_private_display_texture->GetFormat() != format)
|
||||||
{
|
{
|
||||||
ClearDisplayTexture();
|
ClearDisplayTexture();
|
||||||
m_private_display_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(m_private_display_texture));
|
||||||
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)
|
if (!m_private_display_texture)
|
||||||
Log_ErrorPrintf("Failed to create %ux%u %u texture", width, height, static_cast<u32>(format));
|
Log_ErrorPrintf("Failed to create %ux%u %u texture", width, height, static_cast<u32>(format));
|
||||||
}
|
}
|
||||||
|
|
|
@ -717,7 +717,13 @@ void SaveStateSelectorUI::Close(bool reset_slot)
|
||||||
|
|
||||||
void SaveStateSelectorUI::RefreshList()
|
void SaveStateSelectorUI::RefreshList()
|
||||||
{
|
{
|
||||||
|
for (ListEntry& entry : s_slots)
|
||||||
|
{
|
||||||
|
if (entry.preview_texture)
|
||||||
|
g_gpu_device->RecycleTexture(std::move(entry.preview_texture));
|
||||||
|
}
|
||||||
s_slots.clear();
|
s_slots.clear();
|
||||||
|
|
||||||
if (System::IsShutdown())
|
if (System::IsShutdown())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -761,7 +767,10 @@ void SaveStateSelectorUI::DestroyTextures()
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
for (ListEntry& entry : s_slots)
|
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()
|
void SaveStateSelectorUI::RefreshHotkeyLegend()
|
||||||
|
@ -815,23 +824,22 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn
|
||||||
li->slot = slot;
|
li->slot = slot;
|
||||||
li->global = global;
|
li->global = global;
|
||||||
|
|
||||||
li->preview_texture.reset();
|
|
||||||
|
|
||||||
// Might not have a display yet, we're called at startup..
|
// Might not have a display yet, we're called at startup..
|
||||||
if (g_gpu_device)
|
if (g_gpu_device)
|
||||||
{
|
{
|
||||||
|
g_gpu_device->RecycleTexture(std::move(li->preview_texture));
|
||||||
|
|
||||||
if (ssi && !ssi->screenshot_data.empty())
|
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_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
|
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,
|
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,
|
GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!li->preview_texture)
|
if (!li->preview_texture)
|
||||||
|
@ -850,10 +858,11 @@ void SaveStateSelectorUI::InitializePlaceholderListEntry(ListEntry* li, std::str
|
||||||
|
|
||||||
if (g_gpu_device)
|
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,
|
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,
|
GPUTexture::Format::RGBA8, Resources::PLACEHOLDER_ICON_DATA, sizeof(u32) * Resources::PLACEHOLDER_ICON_WIDTH);
|
||||||
false);
|
|
||||||
if (!li->preview_texture)
|
if (!li->preview_texture)
|
||||||
Log_ErrorPrintf("Failed to upload save state image to GPU");
|
Log_ErrorPrintf("Failed to upload save state image to GPU");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3894,6 +3894,7 @@ bool System::LoadRewindState(u32 skip_saves /*= 0*/, bool consume_state /*=true
|
||||||
{
|
{
|
||||||
while (skip_saves > 0 && !s_rewind_states.empty())
|
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();
|
s_rewind_states.pop_back();
|
||||||
skip_saves--;
|
skip_saves--;
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,6 +601,7 @@ bool D3D11Device::BeginPresent(bool skip_present)
|
||||||
{
|
{
|
||||||
// Note: Really slow on Intel...
|
// Note: Really slow on Intel...
|
||||||
m_context->Flush();
|
m_context->Flush();
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,6 +612,7 @@ bool D3D11Device::BeginPresent(bool skip_present)
|
||||||
(FAILED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) || !is_fullscreen))
|
(FAILED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) || !is_fullscreen))
|
||||||
{
|
{
|
||||||
Host::SetFullscreen(false);
|
Host::SetFullscreen(false);
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,6 +646,8 @@ void D3D11Device::EndPresent()
|
||||||
|
|
||||||
if (m_gpu_timing_enabled)
|
if (m_gpu_timing_enabled)
|
||||||
KickTimestampQuery();
|
KickTimestampQuery();
|
||||||
|
|
||||||
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUDevice::AdapterAndModeList D3D11Device::StaticGetAdapterAndModeList()
|
GPUDevice::AdapterAndModeList D3D11Device::StaticGetAdapterAndModeList()
|
||||||
|
|
|
@ -49,8 +49,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0) override;
|
||||||
bool dynamic = false) override;
|
|
||||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ Log_SetChannel(D3D11Device);
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> D3D11Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> D3D11Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data, u32 data_stride, bool dynamic /* = false */)
|
const void* data, u32 data_stride)
|
||||||
{
|
{
|
||||||
std::unique_ptr<D3D11Texture> tex = std::make_unique<D3D11Texture>();
|
std::unique_ptr<D3D11Texture> tex = std::make_unique<D3D11Texture>();
|
||||||
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();
|
tex.reset();
|
||||||
|
|
||||||
return tex;
|
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*/,
|
bool D3D11Texture::Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer /*= 0*/,
|
||||||
u32 level /*= 0*/)
|
u32 level /*= 0*/)
|
||||||
{
|
{
|
||||||
if (m_dynamic)
|
if (m_type == Type::DynamicTexture)
|
||||||
{
|
{
|
||||||
void* map;
|
void* map;
|
||||||
u32 map_stride;
|
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*/,
|
bool D3D11Texture::Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer /*= 0*/,
|
||||||
u32 level /*= 0*/)
|
u32 level /*= 0*/)
|
||||||
{
|
{
|
||||||
if (!m_dynamic || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) || layer > m_layers ||
|
if (m_type != Type::DynamicTexture || (x + width) > GetMipWidth(level) || (y + height) > GetMipHeight(level) ||
|
||||||
level > m_levels)
|
layer > m_layers || level > m_levels)
|
||||||
{
|
{
|
||||||
return false;
|
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,
|
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 */,
|
Format format, const void* initial_data /* = nullptr */, u32 initial_data_stride /* = 0 */)
|
||||||
bool dynamic /* = false */)
|
|
||||||
{
|
{
|
||||||
if (!ValidateConfig(width, height, layers, layers, samples, type, format))
|
if (!ValidateConfig(width, height, layers, layers, samples, type, format))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u32 bind_flags = 0;
|
u32 bind_flags = 0;
|
||||||
|
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
||||||
|
u32 cpu_access = 0;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Type::RenderTarget:
|
case Type::RenderTarget:
|
||||||
|
@ -287,6 +288,11 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
case Type::Texture:
|
case Type::Texture:
|
||||||
bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
break;
|
break;
|
||||||
|
case Type::DynamicTexture:
|
||||||
|
bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
break;
|
||||||
case Type::RWTexture:
|
case Type::RWTexture:
|
||||||
bind_flags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
bind_flags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
||||||
break;
|
break;
|
||||||
|
@ -296,9 +302,8 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
|
|
||||||
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
|
const D3DCommon::DXGIFormatMapping& fm = D3DCommon::GetFormatMapping(format);
|
||||||
|
|
||||||
CD3D11_TEXTURE2D_DESC desc(fm.resource_format, width, height, layers, levels, bind_flags,
|
CD3D11_TEXTURE2D_DESC desc(fm.resource_format, width, height, layers, levels, bind_flags, usage, cpu_access, samples,
|
||||||
dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, dynamic ? D3D11_CPU_ACCESS_WRITE : 0,
|
0, 0);
|
||||||
samples, 0, 0);
|
|
||||||
|
|
||||||
D3D11_SUBRESOURCE_DATA srd;
|
D3D11_SUBRESOURCE_DATA srd;
|
||||||
srd.pSysMem = initial_data;
|
srd.pSysMem = initial_data;
|
||||||
|
@ -373,7 +378,6 @@ bool D3D11Texture::Create(ID3D11Device* device, u32 width, u32 height, u32 layer
|
||||||
m_samples = static_cast<u8>(samples);
|
m_samples = static_cast<u8>(samples);
|
||||||
m_type = type;
|
m_type = type;
|
||||||
m_format = format;
|
m_format = format;
|
||||||
m_dynamic = dynamic;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,7 +387,6 @@ void D3D11Texture::Destroy()
|
||||||
m_rtv_dsv.Reset();
|
m_rtv_dsv.Reset();
|
||||||
m_srv.Reset();
|
m_srv.Reset();
|
||||||
m_texture.Reset();
|
m_texture.Reset();
|
||||||
m_dynamic = false;
|
|
||||||
ClearBaseProperties();
|
ClearBaseProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ public:
|
||||||
{
|
{
|
||||||
return reinterpret_cast<ID3D11RenderTargetView* const*>(m_rtv_dsv.GetAddressOf());
|
return reinterpret_cast<ID3D11RenderTargetView* const*>(m_rtv_dsv.GetAddressOf());
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE bool IsDynamic() const { return m_dynamic; }
|
|
||||||
DXGI_FORMAT GetDXGIFormat() const;
|
DXGI_FORMAT GetDXGIFormat() const;
|
||||||
|
|
||||||
ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); }
|
ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); }
|
||||||
|
@ -77,7 +76,7 @@ public:
|
||||||
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
ALWAYS_INLINE operator bool() const { return static_cast<bool>(m_texture); }
|
||||||
|
|
||||||
bool Create(ID3D11Device* device, u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type,
|
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();
|
void Destroy();
|
||||||
|
|
||||||
|
@ -97,7 +96,6 @@ private:
|
||||||
ComPtr<ID3D11ShaderResourceView> m_srv;
|
ComPtr<ID3D11ShaderResourceView> m_srv;
|
||||||
ComPtr<ID3D11View> m_rtv_dsv;
|
ComPtr<ID3D11View> m_rtv_dsv;
|
||||||
u32 m_mapped_subresource = 0;
|
u32 m_mapped_subresource = 0;
|
||||||
bool m_dynamic = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class D3D11TextureBuffer final : public GPUTextureBuffer
|
class D3D11TextureBuffer final : public GPUTextureBuffer
|
||||||
|
|
|
@ -1067,6 +1067,7 @@ bool D3D12Device::BeginPresent(bool frame_skip)
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
SubmitCommandList(false);
|
SubmitCommandList(false);
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,6 +1080,7 @@ bool D3D12Device::BeginPresent(bool frame_skip)
|
||||||
(FAILED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) || !is_fullscreen))
|
(FAILED(m_swap_chain->GetFullscreenState(&is_fullscreen, nullptr)) || !is_fullscreen))
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([]() { Host::SetFullscreen(false); });
|
Host::RunOnCPUThread([]() { Host::SetFullscreen(false); });
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,6 +1106,8 @@ void D3D12Device::EndPresent()
|
||||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||||
else
|
else
|
||||||
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
||||||
|
|
||||||
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
|
@ -70,8 +70,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0) override;
|
||||||
bool dynamic = false) override;
|
|
||||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ D3D12Texture::~D3D12Texture()
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data /* = nullptr */, u32 data_stride /* = 0 */,
|
const void* data /* = nullptr */, u32 data_stride /* = 0 */)
|
||||||
bool dynamic /* = false */)
|
|
||||||
{
|
{
|
||||||
if (!GPUTexture::ValidateConfig(width, height, layers, levels, samples, type, format))
|
if (!GPUTexture::ValidateConfig(width, height, layers, levels, samples, type, format))
|
||||||
return {};
|
return {};
|
||||||
|
@ -66,6 +65,7 @@ std::unique_ptr<GPUTexture> D3D12Device::CreateTexture(u32 width, u32 height, u3
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GPUTexture::Type::Texture:
|
case GPUTexture::Type::Texture:
|
||||||
|
case GPUTexture::Type::DynamicTexture:
|
||||||
{
|
{
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
@ -329,6 +329,7 @@ ID3D12GraphicsCommandList4* D3D12Texture::GetCommandBufferForUpdate()
|
||||||
if (m_type != Type::Texture || m_use_fence_counter == dev.GetCurrentFenceValue())
|
if (m_type != Type::Texture || m_use_fence_counter == dev.GetCurrentFenceValue())
|
||||||
{
|
{
|
||||||
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||||
|
if (dev.InRenderPass())
|
||||||
dev.EndRenderPass();
|
dev.EndRenderPass();
|
||||||
return dev.GetCommandList();
|
return dev.GetCommandList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,6 +289,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view&
|
||||||
|
|
||||||
void GPUDevice::Destroy()
|
void GPUDevice::Destroy()
|
||||||
{
|
{
|
||||||
|
PurgeTexturePool();
|
||||||
if (HasSurface())
|
if (HasSurface())
|
||||||
DestroySurface();
|
DestroySurface();
|
||||||
DestroyResources();
|
DestroyResources();
|
||||||
|
@ -726,10 +727,11 @@ bool GPUDevice::UpdateImGuiFontTexture()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> new_font =
|
std::unique_ptr<GPUTexture> 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)
|
if (!new_font)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
RecycleTexture(std::move(m_imgui_font_texture));
|
||||||
m_imgui_font_texture = std::move(new_font);
|
m_imgui_font_texture = std::move(new_font);
|
||||||
io.Fonts->SetTexID(m_imgui_font_texture.get());
|
io.Fonts->SetTexID(m_imgui_font_texture.get());
|
||||||
return true;
|
return true;
|
||||||
|
@ -741,6 +743,108 @@ bool GPUDevice::UsesLowerLeftOrigin() const
|
||||||
return (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES);
|
return (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GPUTexture> 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<GPUTexture> ret;
|
||||||
|
|
||||||
|
const TexturePoolKey key = {static_cast<u16>(width),
|
||||||
|
static_cast<u16>(height),
|
||||||
|
static_cast<u8>(layers),
|
||||||
|
static_cast<u8>(levels),
|
||||||
|
static_cast<u8>(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<GPUTexture, GPUDevice::PooledTextureDeleter>
|
||||||
|
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<GPUTexture> ret =
|
||||||
|
FetchTexture(width, height, layers, levels, samples, type, format, data, data_stride);
|
||||||
|
return std::unique_ptr<GPUTexture, PooledTextureDeleter>(ret.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPUDevice::RecycleTexture(std::unique_ptr<GPUTexture> 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<u16>(texture->GetWidth()),
|
||||||
|
static_cast<u16>(texture->GetHeight()),
|
||||||
|
static_cast<u8>(texture->GetLayers()),
|
||||||
|
static_cast<u8>(texture->GetLevels()),
|
||||||
|
static_cast<u8>(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)
|
void GPUDevice::SetDisplayMaxFPS(float max_fps)
|
||||||
{
|
{
|
||||||
m_display_frame_interval = (max_fps > 0.0f) ? (1.0f / max_fps) : 0.0f;
|
m_display_frame_interval = (max_fps > 0.0f) ? (1.0f / max_fps) : 0.0f;
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "common/small_string.h"
|
#include "common/small_string.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
@ -457,6 +459,11 @@ public:
|
||||||
std::vector<std::string> fullscreen_modes;
|
std::vector<std::string> fullscreen_modes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PooledTextureDeleter
|
||||||
|
{
|
||||||
|
void operator()(GPUTexture* const tex);
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr u32 MAX_TEXTURE_SAMPLERS = 8;
|
static constexpr u32 MAX_TEXTURE_SAMPLERS = 8;
|
||||||
static constexpr u32 MIN_TEXEL_BUFFER_ELEMENTS = 4 * 1024 * 512;
|
static constexpr u32 MIN_TEXEL_BUFFER_ELEMENTS = 4 * 1024 * 512;
|
||||||
static constexpr u32 MAX_RENDER_TARGETS = 4;
|
static constexpr u32 MAX_RENDER_TARGETS = 4;
|
||||||
|
@ -541,15 +548,24 @@ public:
|
||||||
|
|
||||||
virtual std::string GetDriverInfo() const = 0;
|
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<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
virtual std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0) = 0;
|
||||||
bool dynamic = false) = 0;
|
|
||||||
virtual std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) = 0;
|
virtual std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) = 0;
|
||||||
virtual std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format,
|
virtual std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format,
|
||||||
u32 size_in_elements) = 0;
|
u32 size_in_elements) = 0;
|
||||||
|
|
||||||
|
// Texture pooling.
|
||||||
|
std::unique_ptr<GPUTexture> 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<GPUTexture, PooledTextureDeleter>
|
||||||
|
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<GPUTexture> texture);
|
||||||
|
void PurgeTexturePool();
|
||||||
|
|
||||||
virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||||
u32 out_data_stride) = 0;
|
u32 out_data_stride) = 0;
|
||||||
virtual void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
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);
|
bool AcquireWindow(bool recreate_window);
|
||||||
|
|
||||||
|
void TrimTexturePool();
|
||||||
|
|
||||||
Features m_features = {};
|
Features m_features = {};
|
||||||
u32 m_max_texture_size = 0;
|
u32 m_max_texture_size = 0;
|
||||||
u32 m_max_multisamples = 0;
|
u32 m_max_multisamples = 0;
|
||||||
|
@ -655,26 +673,64 @@ protected:
|
||||||
std::unique_ptr<GPUSampler> m_nearest_sampler;
|
std::unique_ptr<GPUSampler> m_nearest_sampler;
|
||||||
std::unique_ptr<GPUSampler> m_linear_sampler;
|
std::unique_ptr<GPUSampler> m_linear_sampler;
|
||||||
|
|
||||||
bool m_gpu_timing_enabled = false;
|
|
||||||
bool m_vsync_enabled = false;
|
|
||||||
bool m_debug_device = false;
|
|
||||||
|
|
||||||
private:
|
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<GPUTexture> texture;
|
||||||
|
u32 remove_count;
|
||||||
|
TexturePoolKey key;
|
||||||
|
};
|
||||||
|
|
||||||
void OpenShaderCache(const std::string_view& base_path, u32 version);
|
void OpenShaderCache(const std::string_view& base_path, u32 version);
|
||||||
void CloseShaderCache();
|
void CloseShaderCache();
|
||||||
bool CreateResources();
|
bool CreateResources();
|
||||||
void DestroyResources();
|
void DestroyResources();
|
||||||
|
|
||||||
|
std::unique_ptr<GPUPipeline> m_imgui_pipeline;
|
||||||
|
std::unique_ptr<GPUTexture> m_imgui_font_texture;
|
||||||
|
|
||||||
|
std::deque<TexturePoolEntry> m_texture_pool;
|
||||||
|
u32 m_texture_pool_counter = 0;
|
||||||
|
|
||||||
// TODO: Move out.
|
// TODO: Move out.
|
||||||
u64 m_last_frame_displayed_time = 0;
|
u64 m_last_frame_displayed_time = 0;
|
||||||
float m_display_frame_interval = 0.0f;
|
float m_display_frame_interval = 0.0f;
|
||||||
|
|
||||||
std::unique_ptr<GPUPipeline> m_imgui_pipeline;
|
protected:
|
||||||
std::unique_ptr<GPUTexture> m_imgui_font_texture;
|
bool m_gpu_timing_enabled = false;
|
||||||
|
bool m_vsync_enabled = false;
|
||||||
|
bool m_debug_device = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<GPUDevice> g_gpu_device;
|
extern std::unique_ptr<GPUDevice> g_gpu_device;
|
||||||
|
|
||||||
|
ALWAYS_INLINE void GPUDevice::PooledTextureDeleter::operator()(GPUTexture* const tex)
|
||||||
|
{
|
||||||
|
g_gpu_device->RecycleTexture(std::unique_ptr<GPUTexture>(tex));
|
||||||
|
}
|
||||||
|
|
||||||
namespace Host {
|
namespace Host {
|
||||||
/// Called when the core is creating a render device.
|
/// Called when the core is creating a render device.
|
||||||
/// This could also be fullscreen transition.
|
/// This could also be fullscreen transition.
|
||||||
|
|
|
@ -126,13 +126,13 @@ bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u
|
||||||
return false;
|
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.");
|
Log_ErrorPrintf("Texture arrays are not supported on targets.");
|
||||||
return false;
|
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.");
|
Log_ErrorPrintf("Mipmaps are not supported on targets.");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
RenderTarget,
|
RenderTarget,
|
||||||
DepthStencil,
|
DepthStencil,
|
||||||
Texture,
|
Texture,
|
||||||
|
DynamicTexture,
|
||||||
RWTexture,
|
RWTexture,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,7 +101,8 @@ public:
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE bool IsRenderTarget() const { return (m_type == Type::RenderTarget); }
|
ALWAYS_INLINE bool IsRenderTarget() const { return (m_type == Type::RenderTarget); }
|
||||||
ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); }
|
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 const ClearValue& GetClearValue() const { return m_clear_value; }
|
||||||
ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; }
|
ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; }
|
||||||
|
@ -152,6 +154,7 @@ protected:
|
||||||
u8 m_samples = 0;
|
u8 m_samples = 0;
|
||||||
Type m_type = Type::Unknown;
|
Type m_type = Type::Unknown;
|
||||||
Format m_format = Format::Unknown;
|
Format m_format = Format::Unknown;
|
||||||
|
|
||||||
State m_state = State::Dirty;
|
State m_state = State::Dirty;
|
||||||
|
|
||||||
ClearValue m_clear_value = {};
|
ClearValue m_clear_value = {};
|
||||||
|
|
|
@ -281,7 +281,7 @@ std::optional<Common::RGBA8Image> ImGuiFullscreen::LoadTextureImage(const char*
|
||||||
std::shared_ptr<GPUTexture> ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image)
|
std::shared_ptr<GPUTexture> ImGuiFullscreen::UploadTexture(const char* path, const Common::RGBA8Image& image)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUTexture> texture =
|
std::unique_ptr<GPUTexture> texture =
|
||||||
g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||||
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||||
if (!texture)
|
if (!texture)
|
||||||
{
|
{
|
||||||
|
@ -290,7 +290,7 @@ std::shared_ptr<GPUTexture> ImGuiFullscreen::UploadTexture(const char* path, con
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight());
|
Log_DevPrintf("Uploaded texture resource '%s' (%ux%u)", path, image.GetWidth(), image.GetHeight());
|
||||||
return std::shared_ptr<GPUTexture>(std::move(texture));
|
return std::shared_ptr<GPUTexture>(texture.release(), GPUDevice::PooledTextureDeleter());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<GPUTexture> ImGuiFullscreen::LoadTexture(const std::string_view& path)
|
std::shared_ptr<GPUTexture> ImGuiFullscreen::LoadTexture(const std::string_view& path)
|
||||||
|
|
|
@ -1035,7 +1035,8 @@ void ImGuiManager::UpdateSoftwareCursorTexture(u32 index)
|
||||||
Log_ErrorPrintf("Failed to load software cursor %u image '%s'", index, sc.image_path.c_str());
|
Log_ErrorPrintf("Failed to load software cursor %u image '%s'", index, sc.image_path.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sc.texture = g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
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());
|
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||||
if (!sc.texture)
|
if (!sc.texture)
|
||||||
{
|
{
|
||||||
|
|
|
@ -187,8 +187,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0) override;
|
||||||
bool dynamic = false) override;
|
|
||||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||||
|
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ void MetalTexture::Destroy()
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
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))
|
if (!GPUTexture::ValidateConfig(width, height, layers, layers, samples, type, format))
|
||||||
return {};
|
return {};
|
||||||
|
@ -1073,6 +1073,7 @@ std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u3
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GPUTexture::Type::Texture:
|
case GPUTexture::Type::Texture:
|
||||||
|
case GPUTexture::Type::DynamicTexture:
|
||||||
desc.usage = MTLTextureUsageShaderRead;
|
desc.usage = MTLTextureUsageShaderRead;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1977,14 +1978,23 @@ bool MetalDevice::BeginPresent(bool skip_present)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
if (skip_present || m_layer == nil)
|
if (skip_present)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (m_layer == nil)
|
||||||
|
{
|
||||||
|
TrimTexturePool();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
EndAnyEncoding();
|
EndAnyEncoding();
|
||||||
|
|
||||||
m_layer_drawable = [[m_layer nextDrawable] retain];
|
m_layer_drawable = [[m_layer nextDrawable] retain];
|
||||||
if (m_layer_drawable == nil)
|
if (m_layer_drawable == nil)
|
||||||
|
{
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
SetViewportAndScissor(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
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 release];
|
||||||
m_layer_drawable = nil;
|
m_layer_drawable = nil;
|
||||||
SubmitCommandBuffer();
|
SubmitCommandBuffer();
|
||||||
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetalDevice::CreateCommandBuffer()
|
void MetalDevice::CreateCommandBuffer()
|
||||||
|
|
|
@ -50,7 +50,7 @@ RenderAPI OpenGLDevice::GetRenderAPI() const
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> OpenGLDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> OpenGLDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data, u32 data_stride, bool dynamic /* = false */)
|
const void* data, u32 data_stride)
|
||||||
{
|
{
|
||||||
std::unique_ptr<OpenGLTexture> tex(std::make_unique<OpenGLTexture>());
|
std::unique_ptr<OpenGLTexture> tex(std::make_unique<OpenGLTexture>());
|
||||||
if (!tex->Create(width, height, layers, levels, samples, type, format, data, data_stride))
|
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 || m_window_info.type == WindowInfo::Type::Surfaceless)
|
||||||
{
|
{
|
||||||
if (!skip_present)
|
if (!skip_present)
|
||||||
|
{
|
||||||
glFlush();
|
glFlush();
|
||||||
|
TrimTexturePool();
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,6 +806,8 @@ void OpenGLDevice::EndPresent()
|
||||||
|
|
||||||
if (m_gpu_timing_enabled)
|
if (m_gpu_timing_enabled)
|
||||||
KickTimestampQuery();
|
KickTimestampQuery();
|
||||||
|
|
||||||
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDevice::CreateTimestampQueries()
|
void OpenGLDevice::CreateTimestampQueries()
|
||||||
|
|
|
@ -49,8 +49,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0) override;
|
||||||
bool dynamic = false) override;
|
|
||||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||||
|
|
||||||
|
|
|
@ -588,7 +588,7 @@ bool PostProcessing::ReloadShaders()
|
||||||
|
|
||||||
void PostProcessing::Shutdown()
|
void PostProcessing::Shutdown()
|
||||||
{
|
{
|
||||||
s_dummy_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(s_dummy_texture));
|
||||||
s_samplers.clear();
|
s_samplers.clear();
|
||||||
s_enabled = false;
|
s_enabled = false;
|
||||||
decltype(s_stages)().swap(s_stages);
|
decltype(s_stages)().swap(s_stages);
|
||||||
|
@ -625,7 +625,7 @@ GPUTexture* PostProcessing::GetDummyTexture()
|
||||||
return s_dummy_texture.get();
|
return s_dummy_texture.get();
|
||||||
|
|
||||||
const u32 zero = 0;
|
const u32 zero = 0;
|
||||||
s_dummy_texture = g_gpu_device->CreateTexture(1, 1, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
s_dummy_texture = g_gpu_device->FetchTexture(1, 1, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
|
||||||
&zero, sizeof(zero));
|
&zero, sizeof(zero));
|
||||||
if (!s_dummy_texture)
|
if (!s_dummy_texture)
|
||||||
Log_ErrorPrint("Failed to create dummy texture.");
|
Log_ErrorPrint("Failed to create dummy texture.");
|
||||||
|
@ -641,9 +641,9 @@ bool PostProcessing::CheckTargets(GPUTexture::Format target_format, u32 target_w
|
||||||
// In case any allocs fail.
|
// In case any allocs fail.
|
||||||
DestroyTextures();
|
DestroyTextures();
|
||||||
|
|
||||||
if (!(s_input_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1,
|
if (!(s_input_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1,
|
||||||
GPUTexture::Type::RenderTarget, target_format)) ||
|
GPUTexture::Type::RenderTarget, target_format)) ||
|
||||||
!(s_output_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1,
|
!(s_output_texture = g_gpu_device->FetchTexture(target_width, target_height, 1, 1, 1,
|
||||||
GPUTexture::Type::RenderTarget, target_format)))
|
GPUTexture::Type::RenderTarget, target_format)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -675,8 +675,8 @@ void PostProcessing::DestroyTextures()
|
||||||
s_target_width = 0;
|
s_target_width = 0;
|
||||||
s_target_height = 0;
|
s_target_height = 0;
|
||||||
|
|
||||||
s_output_texture.reset();
|
g_gpu_device->RecycleTexture(std::move(s_output_texture));
|
||||||
s_input_texture.reset();
|
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,
|
bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
|
||||||
|
|
|
@ -273,7 +273,11 @@ static GPUPipeline::Primitive MapPrimitive(reshadefx::primitive_topology topolog
|
||||||
|
|
||||||
PostProcessing::ReShadeFXShader::ReShadeFXShader() = default;
|
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,
|
bool PostProcessing::ReShadeFXShader::LoadFromFile(std::string name, std::string filename, bool only_config,
|
||||||
Error* error)
|
Error* error)
|
||||||
|
@ -936,7 +940,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
tex.rt_scale = 0.0f;
|
tex.rt_scale = 0.0f;
|
||||||
tex.texture = g_gpu_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
tex.texture = g_gpu_device->FetchTexture(image.GetWidth(), image.GetHeight(), 1, 1, 1, GPUTexture::Type::Texture,
|
||||||
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
|
||||||
if (!tex.texture)
|
if (!tex.texture)
|
||||||
{
|
{
|
||||||
|
@ -1249,11 +1253,11 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3
|
||||||
if (tex.rt_scale == 0.0f)
|
if (tex.rt_scale == 0.0f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tex.texture.reset();
|
g_gpu_device->RecycleTexture(std::move(tex.texture));
|
||||||
|
|
||||||
const u32 t_width = std::max(static_cast<u32>(static_cast<float>(width) * tex.rt_scale), 1u);
|
const u32 t_width = std::max(static_cast<u32>(static_cast<float>(width) * tex.rt_scale), 1u);
|
||||||
const u32 t_height = std::max(static_cast<u32>(static_cast<float>(height) * tex.rt_scale), 1u);
|
const u32 t_height = std::max(static_cast<u32>(static_cast<float>(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)
|
if (!tex.texture)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to create %ux%u texture", t_width, t_height);
|
Log_ErrorPrintf("Failed to create %ux%u texture", t_width, t_height);
|
||||||
|
|
|
@ -2184,6 +2184,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip)
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
SubmitCommandBuffer(false);
|
SubmitCommandBuffer(false);
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2194,6 +2195,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip)
|
||||||
if (CheckLastSubmitFail())
|
if (CheckLastSubmitFail())
|
||||||
{
|
{
|
||||||
Panic("Fixme"); // TODO
|
Panic("Fixme"); // TODO
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2214,6 +2216,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to recreate surface after loss");
|
Log_ErrorPrintf("Failed to recreate surface after loss");
|
||||||
SubmitCommandBuffer(false);
|
SubmitCommandBuffer(false);
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
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.
|
// Still submit the command buffer, otherwise we'll end up with several frames waiting.
|
||||||
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
|
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
|
||||||
SubmitCommandBuffer(false);
|
SubmitCommandBuffer(false);
|
||||||
|
TrimTexturePool();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2247,6 +2251,7 @@ void VulkanDevice::EndPresent()
|
||||||
SubmitCommandBuffer(m_swap_chain.get(), !m_swap_chain->IsPresentModeSynchronizing());
|
SubmitCommandBuffer(m_swap_chain.get(), !m_swap_chain->IsPresentModeSynchronizing());
|
||||||
MoveToNextCommandBuffer();
|
MoveToNextCommandBuffer();
|
||||||
InvalidateCachedState();
|
InvalidateCachedState();
|
||||||
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
|
@ -72,8 +72,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0) override;
|
||||||
bool dynamic = false) override;
|
|
||||||
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override;
|
||||||
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements) override;
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,7 @@ std::unique_ptr<VulkanTexture> VulkanTexture::Create(u32 width, u32 height, u32
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Type::Texture:
|
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;
|
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<GPUTexture> VulkanDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<GPUTexture> VulkanDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data /* = nullptr */, u32 data_stride /* = 0 */,
|
const void* data /* = nullptr */, u32 data_stride /* = 0 */)
|
||||||
bool dynamic /* = false */)
|
|
||||||
{
|
{
|
||||||
const VkFormat vk_format = VulkanDevice::TEXTURE_FORMAT_MAPPING[static_cast<u8>(format)];
|
const VkFormat vk_format = VulkanDevice::TEXTURE_FORMAT_MAPPING[static_cast<u8>(format)];
|
||||||
std::unique_ptr<VulkanTexture> tex =
|
std::unique_ptr<VulkanTexture> tex =
|
||||||
|
|
Loading…
Reference in a new issue