From 69a0349214a0c919a29deb20e4e231cbece2ad52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon?= <95319163+wpsimon09@users.noreply.github.com> Date: Sat, 5 Sep 2026 18:15:49 +0200 Subject: [PATCH 1/5] Fixed small bug with RefCount since `refCounts` member contains object with type `Resource` calling: `refCount[id]++` was incorrect. This PR fixes this issue. However it also rises a question if we want to keep ref count within the `Resource` object or simply use `int` as a value of the `refCounts` member variable. --- .../Engine_Architecture/04_resource_management.adoc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc index f48645e5e..05538f501 100644 --- a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc +++ b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc @@ -134,6 +134,10 @@ private: struct ResourceData { std::shared_ptr resource; // The actual resource int refCount; // Reference count for this resource + + // Utility functions + void IncreaseRefCount() { refCount++; } + void DecreaseRefCount() { refCount--; } }; std::unordered_map> refCounts; @@ -158,11 +162,13 @@ public: // Step 3a: Check existing resource cache to avoid redundant loading auto& typeResources = resources[std::type_index(typeid(T))]; + auto& typeRefCount = refCounts[std::type_index(typeid(T))]; + auto it = typeResources.find(resourceId); if (it != typeResources.end()) { // Resource exists in cache - increment reference count and return handle - refCounts[resourceId]++; + typeRefCount[resourceId].IncreaseRefCount(); return ResourceHandle(resourceId, this); } @@ -175,7 +181,7 @@ public: // Step 3c: Cache successful resource and initialize reference tracking typeResources[resourceId] = resource; - refCounts[resourceId] = 1; + typeRefCount[resourceId] = {resource, 1}; return ResourceHandle(resourceId, this); } From d555cacd2428c286b2983ffc31f347de59b1d2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon?= <95319163+wpsimon09@users.noreply.github.com> Date: Sun, 6 Sep 2026 07:52:39 +0200 Subject: [PATCH 2/5] Fix resource existence check in HasResource method Update resource existence check to verify resource ID. --- .../Engine_Architecture/04_resource_management.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc index 05538f501..aad37d9bd 100644 --- a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc +++ b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc @@ -218,7 +218,7 @@ After that, we provide the interface for safely accessing cached resources with bool HasResource(const std::string& resourceId) { // Efficient existence check without resource access overhead auto resourceIt = resources.find(std::type_index(typeid(T))); - return resourceIt != resources.end(); + return resourceIt->second.find(id) != resourceIt->second.end(); } ---- From a79f68c43699a3a73ffa5fcb057938363ca45977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon?= <95319163+wpsimon09@users.noreply.github.com> Date: Sun, 6 Sep 2026 08:51:08 +0200 Subject: [PATCH 3/5] Refactor resource management for type safety and reference counting Updated resource management implementation to improve type safety and reference counting. Made the code more coherent and cleared some ambiguities --- .../04_resource_management.adoc | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc index aad37d9bd..1137067a3 100644 --- a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc +++ b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc @@ -70,6 +70,8 @@ Using handles instead of direct pointers provides several benefits: 2. *Validation* - Handles can be checked for validity before use. 3. *Automatic Resource Management* - The resource manager can track which resources are in use. +Note, that if you are implementing `ResourceHandle` in a separate header file, make sure that the function definitions reside in the same file as the `ResourceManager` definitions. This prevents circular dependencies, since ResourceManager depends on ResourceHandle and vice versa. + === Basic Resource Manager Let's implement a basic resource manager that can handle different types of resources. This implementation involves several key steps that work together to provide efficient resource management for a rendering engine. @@ -107,7 +109,7 @@ public: protected: virtual bool doLoad() = 0; - virtual bool doUnload() = 0; + virtual void doUnload() = 0; }; ---- @@ -139,8 +141,8 @@ private: void IncreaseRefCount() { refCount++; } void DecreaseRefCount() { refCount--; } }; - std::unordered_map> refCounts; + + std::unordered_map refCounts; ---- The storage architecture uses a sophisticated two-level mapping system that solves several critical problems in resource management. The outer map keyed by `std::type_index` ensures complete type separation, preventing name collisions between different resource types. For example, you could have both a texture named "stone" and a sound effect named "stone" without conflicts, as they're stored in separate type-specific containers. @@ -162,13 +164,11 @@ public: // Step 3a: Check existing resource cache to avoid redundant loading auto& typeResources = resources[std::type_index(typeid(T))]; - auto& typeRefCount = refCounts[std::type_index(typeid(T))]; - auto it = typeResources.find(resourceId); if (it != typeResources.end()) { // Resource exists in cache - increment reference count and return handle - typeRefCount[resourceId].IncreaseRefCount(); + refCounts[resourceId].IncreaseRefCount(); return ResourceHandle(resourceId, this); } @@ -181,7 +181,7 @@ public: // Step 3c: Cache successful resource and initialize reference tracking typeResources[resourceId] = resource; - typeRefCount[resourceId] = {resource, 1}; + refCounts[resourceId] = {resource, 1}; return ResourceHandle(resourceId, this); } @@ -195,10 +195,12 @@ Error handling follows the principle of graceful degradation, where loading fail === Resource Manager: Resource Access and Validation Interface -After that, we provide the interface for safely accessing cached resources with proper validation and type checking throughout the resource lifecycle. +After that, we provide the interface for safely accessing cached resources with proper validation and type checking throughout the resource lifecycle. Users of the `ResourceManager` should not use these methods directly, instead they should use `Load` which returns safe `ResrourceHandle` object instead of the raw pointer. [source,cpp] ---- +private: + template T* GetResource(const std::string& resourceId) { // Access type-specific resource container using compile-time type information @@ -322,7 +324,7 @@ Next, we implement the texture loading pipeline that transforms disk-based image [source,cpp] ---- - bool Load() override { + bool doLoad() override { // Step 2a: Construct file path using resource ID and expected format std::string filePath = "textures/" + GetId() + ".ktx"; @@ -354,7 +356,7 @@ Then, we implement comprehensive resource cleanup that ensures all GPU resources [source,cpp] ---- - void Unload() override { + void doUnload() override { // Only perform cleanup if resource is currently loaded if (IsLoaded()) { // Step 3a: Obtain device handle for resource destruction From 1005adc8aa33be5b652e7f22b73ea7524abfc3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon?= <95319163+wpsimon09@users.noreply.github.com> Date: Sun, 6 Sep 2026 08:54:44 +0200 Subject: [PATCH 4/5] Fix formatting of code references in documentation --- .../Engine_Architecture/04_resource_management.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc index 1137067a3..5eb013f78 100644 --- a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc +++ b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc @@ -70,7 +70,7 @@ Using handles instead of direct pointers provides several benefits: 2. *Validation* - Handles can be checked for validity before use. 3. *Automatic Resource Management* - The resource manager can track which resources are in use. -Note, that if you are implementing `ResourceHandle` in a separate header file, make sure that the function definitions reside in the same file as the `ResourceManager` definitions. This prevents circular dependencies, since ResourceManager depends on ResourceHandle and vice versa. +Note, that if you are implementing `ResourceHandle` in a separate header file, make sure that the function definitions reside in the same file as the `ResourceManager` definitions. This prevents circular dependencies, since `ResourceManager` depends on `ResourceHandle` and vice versa. === Basic Resource Manager From c782abc89f599ad774d92dea1ba251ee668da7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon?= <95319163+wpsimon09@users.noreply.github.com> Date: Sun, 6 Sep 2026 08:57:09 +0200 Subject: [PATCH 5/5] Update resource release to use DecreaseRefCount Refactor resource release logic to use DecreaseRefCount method. --- .../Engine_Architecture/04_resource_management.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc index 5eb013f78..0290edd14 100644 --- a/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc +++ b/en/Building_a_Simple_Engine/Engine_Architecture/04_resource_management.adoc @@ -238,7 +238,7 @@ Finally, we implement intelligent resource lifecycle management through referenc // Locate reference count entry for this resource auto it = refCounts.find(resourceId); if (it != refCounts.end()) { - it->second--; + it->second.DecreaseRefCount(); // Check if resource has no remaining references if (it->second <= 0) {