graphics: migrate drawables to shared ownership

- introduce DrawablePtr and per-consumer createInstance() semantics
  - add TextureDrawable wrappers backed by shared TexturePtr handles
  - migrate regions, sprites, nine-patches, state lists, skins, groups, gradients,
    UI widgets, tools, modules, ecode, and eeiv to shared drawable ownership
  - remove ownIt flags, manual drawable deletion, and unload-based lifetime handling
  - replace drawable callback IDs with RAII change connections
  - move Variant drawable storage outside its scalar union
  - split UIIcon source lookup from explicit drawable instance creation
  - retain icon instances used by rendering loops instead of cloning per frame
  - avoid shared source mutation in texture-region consumers
  - use drawable type tags instead of RTTI casts
  - fix nearest-size UIIcon lookup
  - document the drawable source/instance contract and add ownership tests
This commit is contained in:
Martín Lucas Golini
2026-07-20 01:09:36 -03:00
parent 04f600bef5
commit dc377335b9
131 changed files with 1747 additions and 1178 deletions

View File

@@ -7,7 +7,9 @@
#include <eepp/graphics/fonttruetype.hpp>
#include <eepp/graphics/image.hpp>
#include <eepp/graphics/renderer/renderer.hpp>
#include <eepp/graphics/texturedrawable.hpp>
#include <eepp/graphics/texturefactory.hpp>
#include <eepp/graphics/textureregion.hpp>
#include <eepp/scene/keyevent.hpp>
#include <eepp/scene/scenemanager.hpp>
#include <eepp/system/filesystem.hpp>
@@ -54,6 +56,25 @@ using namespace EE::Scene;
using namespace EE::UI;
using namespace EE::UI::Tools;
static Texture* getDrawableTexture( Drawable* drawable ) {
if ( !drawable )
return nullptr;
switch ( drawable->getDrawableType() ) {
case Drawable::TEXTURE:
return static_cast<Texture*>( drawable );
case Drawable::TEXTUREDRAWABLE:
return static_cast<TextureDrawable*>( drawable )->getTexture().get();
case Drawable::TEXTUREREGION:
return static_cast<TextureRegion*>( drawable )->getTexture().get();
default:
return nullptr;
}
}
static Texture* getDrawableTexture( const DrawablePtr& drawable ) {
return getDrawableTexture( drawable.get() );
}
static void init_ui_test() {
Engine::instance()->createWindow( WindowSettings( 1024, 650, "HTML Tables Test",
WindowStyle::Default, WindowBackend::Default,
@@ -3843,8 +3864,11 @@ UTEST( UIBackground, RemoteImageReusesCachedTexture ) {
ASSERT_TRUE( second->getBackground() != nullptr );
ASSERT_TRUE( first->getBackground()->getLayer( 0 ) != nullptr );
ASSERT_TRUE( second->getBackground()->getLayer( 0 ) != nullptr );
EXPECT_EQ( cached.get(), first->getBackground()->getLayer( 0 )->getDrawable() );
EXPECT_EQ( cached.get(), second->getBackground()->getLayer( 0 )->getDrawable() );
const DrawablePtr& firstDrawable = first->getBackground()->getLayer( 0 )->getDrawable();
const DrawablePtr& secondDrawable = second->getBackground()->getLayer( 0 )->getDrawable();
EXPECT_EQ( cached.get(), getDrawableTexture( firstDrawable ) );
EXPECT_EQ( cached.get(), getDrawableTexture( secondDrawable ) );
EXPECT_NE( firstDrawable.get(), secondDrawable.get() );
cached.reset();
Engine::destroySingleton();
@@ -5118,7 +5142,7 @@ UTEST( UIHTML, DeferredFileImageReusesCachedTexture ) {
sceneNode->setURI( URI( "file://" + processPath ) );
URI imageURI = sceneNode->solveRelativePath( URI( "../assets/icon/ee.png" ) );
ASSERT_TRUE( FileSystem::fileExists( imageURI.getFSPath() ) );
Drawable* cached = DrawableSearcher::searchByName(
DrawablePtr cached = DrawableSearcher::searchByName(
imageURI.toString(), false, sceneNode->getReferer(), sceneNode->getResourceScope().get() );
ASSERT_TRUE( cached != nullptr );
@@ -5145,9 +5169,11 @@ UTEST( UIHTML, DeferredFileImageReusesCachedTexture ) {
auto* second = secondNode->asType<UIHTMLImage>();
ASSERT_TRUE( first != nullptr );
ASSERT_TRUE( second != nullptr );
EXPECT_EQ( cached, first->getDrawable() );
EXPECT_EQ( cached, second->getDrawable() );
EXPECT_EQ( getDrawableTexture( cached ), getDrawableTexture( first->getDrawable() ) );
EXPECT_EQ( getDrawableTexture( cached ), getDrawableTexture( second->getDrawable() ) );
EXPECT_NE( first->getDrawable().get(), second->getDrawable().get() );
cached.reset();
Engine::destroySingleton();
}
@@ -5187,8 +5213,9 @@ UTEST( UIHTML, RemoteImageReusesCachedTexture ) {
auto* second = secondNode->asType<UIHTMLImage>();
ASSERT_TRUE( first != nullptr );
ASSERT_TRUE( second != nullptr );
EXPECT_EQ( cached.get(), first->getDrawable() );
EXPECT_EQ( cached.get(), second->getDrawable() );
EXPECT_EQ( cached.get(), getDrawableTexture( first->getDrawable() ) );
EXPECT_EQ( cached.get(), getDrawableTexture( second->getDrawable() ) );
EXPECT_NE( first->getDrawable().get(), second->getDrawable().get() );
cached.reset();
Engine::destroySingleton();