From 751d81eff09aee276038dd23f24647eb699e3058 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Mon, 14 Apr 2025 21:39:44 +1000 Subject: [PATCH] GPU/TextureCache: Handle FetchTexture() fails --- src/core/gpu_hw.cpp | 2 + src/core/gpu_hw_texture_cache.cpp | 77 ++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 64ba4c49f..0f0b5a17b 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -3854,6 +3854,8 @@ void GPU_HW::FlushRender() m_batch.transparency_mode != GPUTransparencyMode::Disabled ? GPUTextureCache::PaletteRecordFlags::HasSemiTransparentDraws : GPUTextureCache::PaletteRecordFlags::None); + if (!texture) [[unlikely]] + m_batch.texture_mode = static_cast(m_texture_cache_key.mode); } if (m_batch_ubo_dirty) diff --git a/src/core/gpu_hw_texture_cache.cpp b/src/core/gpu_hw_texture_cache.cpp index 90ad31f69..50a54380f 100644 --- a/src/core/gpu_hw_texture_cache.cpp +++ b/src/core/gpu_hw_texture_cache.cpp @@ -260,6 +260,10 @@ static void SetHashCacheTextureFormat(); static bool CompilePipelines(Error* error); static void DestroyPipelines(); +static std::unique_ptr FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Type type, GPUTexture::Format format, + GPUTexture::Flags flags, const void* data = nullptr, + u32 data_stride = 0); static const Source* ReturnSource(Source* source, const GSVector4i uv_rect, PaletteRecordFlags flags); static Source* CreateSource(SourceKey key); @@ -1419,6 +1423,26 @@ void GPUTextureCache::DecodeTexture(u8 page, GPUTexturePaletteReg palette, GPUTe texture->Update(0, 0, TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, tex_map, tex_stride); } +std::unique_ptr GPUTextureCache::FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + GPUTexture::Type type, GPUTexture::Format format, + GPUTexture::Flags flags, const void* data /* = nullptr */, + u32 data_stride /* = 0 */) +{ + Error error; + std::unique_ptr tex = + g_gpu_device->FetchTexture(width, height, layers, levels, samples, type, format, flags, data, data_stride, &error); + if (!tex) [[unlikely]] + { + ERROR_LOG("Failed to create {}x{} texture for cache: {}", width, height, error.GetDescription()); + Host::AddIconOSDWarning("TCFetchTextureFailed", ICON_EMOJI_WARNING, + fmt::format(TRANSLATE_FS("GPU_HW", "Failed to allocate {}x{} texture for cache:\n{}"), + width, height, error.GetDescription()), + Host::OSD_ERROR_DURATION); + } + + return tex; +} + const GPUTextureCache::Source* GPUTextureCache::LookupSource(SourceKey key, const GSVector4i rect, PaletteRecordFlags flags) { @@ -1441,31 +1465,34 @@ const GPUTextureCache::Source* GPUTextureCache::LookupSource(SourceKey key, cons const GPUTextureCache::Source* GPUTextureCache::ReturnSource(Source* source, const GSVector4i uv_rect, PaletteRecordFlags flags) { -#if defined(_DEBUG) || defined(_DEVEL) - // GL_INS_FMT("Tex hash: {:016X}", source->texture_hash); - // GL_INS_FMT("Palette hash: {:016X}", source->palette_hash); - if (!uv_rect.eq(INVALID_RECT)) + if (source) [[likely]] { - LoopXWrappedPages(source->key.page, TexturePageCountForMode(source->key.mode), [&uv_rect](u32 pn) { - const PageEntry& pe = s_state.pages[pn]; - ListIterate(pe.writes, [&uv_rect](const VRAMWrite* vrw) { - if (const GSVector4i intersection = uv_rect.rintersect(vrw->write_rect); !intersection.rempty()) - GL_INS_FMT("TC: VRAM write was {:016X} ({})", vrw->hash, intersection); +#if defined(_DEBUG) || defined(_DEVEL) + // GL_INS_FMT("Tex hash: {:016X}", source->texture_hash); + // GL_INS_FMT("Palette hash: {:016X}", source->palette_hash); + if (!uv_rect.eq(INVALID_RECT)) + { + LoopXWrappedPages(source->key.page, TexturePageCountForMode(source->key.mode), [&uv_rect](u32 pn) { + const PageEntry& pe = s_state.pages[pn]; + ListIterate(pe.writes, [&uv_rect](const VRAMWrite* vrw) { + if (const GSVector4i intersection = uv_rect.rintersect(vrw->write_rect); !intersection.rempty()) + GL_INS_FMT("TC: VRAM write was {:016X} ({})", vrw->hash, intersection); + }); }); - }); - if (TextureModeHasPalette(source->key.mode)) - GL_INS_FMT("TC: Palette was {:016X}", source->palette_hash); - } + if (TextureModeHasPalette(source->key.mode)) + GL_INS_FMT("TC: Palette was {:016X}", source->palette_hash); + } #endif - DebugAssert(source->from_hash_cache); - source->from_hash_cache->last_used_frame = System::GetFrameNumber(); + DebugAssert(source->from_hash_cache); + source->from_hash_cache->last_used_frame = System::GetFrameNumber(); - // TODO: Cache var. - if (g_gpu_settings.texture_replacements.dump_textures) - { - source->active_uv_rect = source->active_uv_rect.runion(uv_rect); - source->palette_record_flags |= flags; + // TODO: Cache var. + if (g_gpu_settings.texture_replacements.dump_textures) + { + source->active_uv_rect = source->active_uv_rect.runion(uv_rect); + source->palette_record_flags |= flags; + } } return source; @@ -2274,14 +2301,10 @@ GPUTextureCache::HashCacheEntry* GPUTextureCache::LookupHashCache(SourceKey key, entry.ref_count = 0; entry.last_used_frame = 0; entry.sources = {}; - entry.texture = - g_gpu_device->FetchTexture(TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture, + entry.texture = FetchTexture(TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, 1, 1, 1, GPUTexture::Type::Texture, s_state.hash_cache_texture_format, GPUTexture::Flags::None); if (!entry.texture) - { - ERROR_LOG("Failed to create texture."); return nullptr; - } DecodeTexture(key.page, key.palette, key.mode, entry.texture.get()); @@ -3738,8 +3761,8 @@ void GPUTextureCache::ApplyTextureReplacements(SourceKey key, HashType tex_hash, } // Grab the actual texture beforehand, in case we OOM. - std::unique_ptr replacement_tex = g_gpu_device->FetchTexture( - new_width, new_height, 1, 1, 1, GPUTexture::Type::Texture, REPLACEMENT_TEXTURE_FORMAT, GPUTexture::Flags::None); + std::unique_ptr replacement_tex = FetchTexture(new_width, new_height, 1, 1, 1, GPUTexture::Type::Texture, + REPLACEMENT_TEXTURE_FORMAT, GPUTexture::Flags::None); if (!replacement_tex) { ERROR_LOG("Failed to create {}x{} texture.", new_width, new_height);