Plasma Engine  2.0
Loading...
Searching...
No Matches
ResourceManager_inl.h
1#pragma once
2
3#include <Foundation/Logging/Log.h>
4
5template <typename ResourceType>
6ResourceType* plResourceManager::GetResource(plStringView sResourceID, bool bIsReloadable)
7{
8 return static_cast<ResourceType*>(GetResource(plGetStaticRTTI<ResourceType>(), sResourceID, bIsReloadable));
9}
10
11template <typename ResourceType>
13{
14 // the mutex here is necessary to prevent a race between resource unloading and storing the pointer in the handle
15 PL_LOCK(s_ResourceMutex);
16 return plTypedResourceHandle<ResourceType>(GetResource<ResourceType>(sResourceID, true));
17}
18
19template <typename ResourceType>
21{
23 {
24 // the mutex here is necessary to prevent a race between resource unloading and storing the pointer in the handle
25 PL_LOCK(s_ResourceMutex);
26 hResource = plTypedResourceHandle<ResourceType>(GetResource<ResourceType>(sResourceID, true));
27 }
28
29 if (hLoadingFallback.IsValid())
30 {
31 hResource.m_pResource->SetLoadingFallbackResource(hLoadingFallback);
32 }
33
34 return hResource;
35}
36
37template <typename ResourceType>
39{
40 plResource* pResource = nullptr;
41
42 const plTempHashedString sResourceHash(sResourceID);
43
44 PL_LOCK(s_ResourceMutex);
45
46 const plRTTI* pRtti = FindResourceTypeOverride(plGetStaticRTTI<ResourceType>(), sResourceID);
47
48 if (GetLoadedResources()[pRtti].m_Resources.TryGetValue(sResourceHash, pResource))
49 return plTypedResourceHandle<ResourceType>((ResourceType*)pResource);
50
52}
53
54template <typename ResourceType, typename DescriptorType>
55plTypedResourceHandle<ResourceType> plResourceManager::CreateResource(plStringView sResourceID, DescriptorType&& descriptor, plStringView sResourceDescription)
56{
57 static_assert(std::is_rvalue_reference<DescriptorType&&>::value, "Please std::move the descriptor into this function");
58
59 PL_LOG_BLOCK("plResourceManager::CreateResource", sResourceID);
60
61 PL_LOCK(s_ResourceMutex);
62
63 plTypedResourceHandle<ResourceType> hResource(GetResource<ResourceType>(sResourceID, false));
64
65 ResourceType* pResource = BeginAcquireResource(hResource, plResourceAcquireMode::PointerOnly);
66 pResource->SetResourceDescription(sResourceDescription);
67 pResource->m_Flags.Add(plResourceFlags::IsCreatedResource);
68
69 PL_ASSERT_DEV(pResource->GetLoadingState() == plResourceState::Unloaded, "CreateResource was called on a resource that is already created");
70
71 // If this does not compile, you either passed in the wrong descriptor type for the given resource type
72 // or you forgot to std::move the descriptor when calling CreateResource
73 {
74 auto localDescriptor = std::move(descriptor);
75 plResourceLoadDesc ld = pResource->CreateResource(std::move(localDescriptor));
76 pResource->VerifyAfterCreateResource(ld);
77 }
78
79 PL_ASSERT_DEV(pResource->GetLoadingState() != plResourceState::Unloaded, "CreateResource did not set the loading state properly.");
80
81 EndAcquireResource(pResource);
82
83 return hResource;
84}
85
86template <typename ResourceType, typename DescriptorType>
88plResourceManager::GetOrCreateResource(plStringView sResourceID, DescriptorType&& descriptor, plStringView sResourceDescription)
89{
90 PL_LOCK(s_ResourceMutex);
92 if (!hResource.IsValid())
93 {
94 hResource = CreateResource<ResourceType, DescriptorType>(sResourceID, std::move(descriptor), sResourceDescription);
95 }
96
97 return hResource;
98}
99
101{
102 PL_ASSERT_DEV(hResource.IsValid(), "Cannot acquire a resource through an invalid handle!");
103
104 plResource* pResource = (plResource*)hResource.m_pResource;
105
106 PL_ASSERT_DEBUG(pResource->GetDynamicRTTI()->IsDerivedFrom(pType),
107 "The requested resource does not have the same type ('{0}') as the resource handle ('{1}').", pResource->GetDynamicRTTI()->GetTypeName(),
108 pType->GetTypeName());
109
110 // pResource->m_iLockCount.Increment();
111 return pResource;
112}
113
114template <typename ResourceType>
115ResourceType* plResourceManager::BeginAcquireResource(const plTypedResourceHandle<ResourceType>& hResource, plResourceAcquireMode mode,
116 const plTypedResourceHandle<ResourceType>& hFallbackResource, plResourceAcquireResult* out_pAcquireResult /*= nullptr*/)
117{
118 PL_ASSERT_DEV(hResource.IsValid(), "Cannot acquire a resource through an invalid handle!");
119
120#if PL_ENABLED(PL_COMPILE_FOR_DEVELOPMENT)
121 const plResource* pCurrentlyUpdatingContent = plResource::GetCurrentlyUpdatingContent();
122 if (pCurrentlyUpdatingContent != nullptr)
123 {
124 PL_LOCK(s_ResourceMutex);
125 PL_ASSERT_DEV(mode == plResourceAcquireMode::PointerOnly || IsResourceTypeAcquireDuringUpdateContentAllowed(pCurrentlyUpdatingContent->GetDynamicRTTI(), plGetStaticRTTI<ResourceType>()),
126 "Trying to acquire a resource of type '{0}' during '{1}::UpdateContent()'. This has to be enabled by calling "
127 "plResourceManager::AllowResourceTypeAcquireDuringUpdateContent<{1}, {0}>(); at engine startup, for example in "
128 "plGameApplication::Init_SetupDefaultResources().",
129 plGetStaticRTTI<ResourceType>()->GetTypeName(), pCurrentlyUpdatingContent->GetDynamicRTTI()->GetTypeName());
130 }
131#endif
132
133 ResourceType* pResource = (ResourceType*)hResource.m_hTypeless.m_pResource;
134
135 // PL_ASSERT_DEV(pResource->m_iLockCount < 20, "You probably forgot somewhere to call 'EndAcquireResource' in sync with 'BeginAcquireResource'.");
136 PL_ASSERT_DEBUG(pResource->GetDynamicRTTI()->template IsDerivedFrom<ResourceType>(),
137 "The requested resource does not have the same type ('{0}') as the resource handle ('{1}').", pResource->GetDynamicRTTI()->GetTypeName(),
138 plGetStaticRTTI<ResourceType>()->GetTypeName());
139
140 if (mode == plResourceAcquireMode::AllowLoadingFallback && GetForceNoFallbackAcquisition() > 0)
141 {
142 mode = plResourceAcquireMode::BlockTillLoaded;
143 }
144
145 if (mode == plResourceAcquireMode::PointerOnly)
146 {
147 if (out_pAcquireResult)
148 *out_pAcquireResult = plResourceAcquireResult::Final;
149
150 // pResource->m_iLockCount.Increment();
151 return pResource;
152 }
153
154 // only set the last accessed time stamp, if it is actually needed, pointer-only access might not mean that the resource is used
155 // productively
156 pResource->m_LastAcquire = GetLastFrameUpdate();
157
158 if (pResource->GetLoadingState() != plResourceState::LoadedResourceMissing)
159 {
160 if (pResource->GetLoadingState() != plResourceState::Loaded)
161 {
162 // if BlockTillLoaded is specified, it will prepended to the preload array, thus will be loaded immediately
163 InternalPreloadResource(pResource, mode >= plResourceAcquireMode::BlockTillLoaded);
164
165 if (mode == plResourceAcquireMode::AllowLoadingFallback &&
166 (pResource->m_hLoadingFallback.IsValid() || hFallbackResource.IsValid() || GetResourceTypeLoadingFallback<ResourceType>().IsValid()))
167 {
168 // return the fallback resource for now, if there is one
169 if (out_pAcquireResult)
170 *out_pAcquireResult = plResourceAcquireResult::LoadingFallback;
171
172 // Fallback order is as follows:
173 // 1) Prefer any resource specific fallback resource
174 // 2) If not available, use the fallback that is given to BeginAcquireResource, as that is at least specific to the situation
175 // 3) If nothing else is available, take the fallback for the whole resource type
176
177 if (pResource->m_hLoadingFallback.IsValid())
178 return (ResourceType*)BeginAcquireResource(pResource->m_hLoadingFallback, plResourceAcquireMode::BlockTillLoaded);
179 else if (hFallbackResource.IsValid())
180 return (ResourceType*)BeginAcquireResource(hFallbackResource, plResourceAcquireMode::BlockTillLoaded);
181 else
182 return (ResourceType*)BeginAcquireResource(GetResourceTypeLoadingFallback<ResourceType>(), plResourceAcquireMode::BlockTillLoaded);
183 }
184
185 EnsureResourceLoadingState(pResource, plResourceState::Loaded);
186 }
187 else
188 {
189 // as long as there are more quality levels available, schedule the resource for more loading
190 // accessing IsQueuedForLoading without a lock here is save because InternalPreloadResource() will lock and early out if necessary
191 // and accidentally skipping InternalPreloadResource() is no problem
192 if (IsQueuedForLoading(pResource) == false && pResource->GetNumQualityLevelsLoadable() > 0)
193 InternalPreloadResource(pResource, false);
194 }
195 }
196
197 if (pResource->GetLoadingState() == plResourceState::LoadedResourceMissing)
198 {
199 // When you get a crash with a stack overflow in this code path, then the resource to be used as the
200 // 'missing resource' replacement might be missing itself.
201
203 {
204 if (out_pAcquireResult)
205 *out_pAcquireResult = plResourceAcquireResult::MissingFallback;
206
207 return (ResourceType*)BeginAcquireResource(
208 plResourceManager::GetResourceTypeMissingFallback<ResourceType>(), plResourceAcquireMode::BlockTillLoaded);
209 }
210
211 if (mode != plResourceAcquireMode::AllowLoadingFallback_NeverFail && mode != plResourceAcquireMode::BlockTillLoaded_NeverFail)
212 {
213 PL_REPORT_FAILURE("The resource '{0}' of type '{1}' is missing and no fallback is available", pResource->GetResourceID(),
214 plGetStaticRTTI<ResourceType>()->GetTypeName());
215 }
216
217 if (out_pAcquireResult)
218 *out_pAcquireResult = plResourceAcquireResult::None;
219
220 return nullptr;
221 }
222
223 if (out_pAcquireResult)
224 *out_pAcquireResult = plResourceAcquireResult::Final;
225
226 // pResource->m_iLockCount.Increment();
227 return pResource;
228}
229
230template <typename ResourceType>
231void plResourceManager::EndAcquireResource(ResourceType* pResource)
232{
233 // PL_ASSERT_DEV(pResource->m_iLockCount > 0, "The resource lock counter is incorrect: {0}", (plInt32)pResource->m_iLockCount);
234 // pResource->m_iLockCount.Decrement();
235}
236
238{
239 // PL_ASSERT_DEV(pResource->m_iLockCount > 0, "The resource lock counter is incorrect: {0}", (plInt32)pResource->m_iLockCount);
240 // pResource->m_iLockCount.Decrement();
241}
242
243template <typename ResourceType>
245{
246 const plRTTI* pBaseType = plGetStaticRTTI<ResourceType>();
247
248 auto& container = GetLoadedResourceOfTypeTempContainer();
249
250 // We use a static container here to ensure its life-time is extended beyond
251 // calls to this function as the locked object does not own the passed-in object
252 // and thus does not extend the data life-time. It is safe to do this, as the
253 // locked object holding the container ensures the container will not be
254 // accessed concurrently.
255 plLockedObject<plMutex, plDynamicArray<plResource*>> loadedResourcesLock(s_ResourceMutex, &container);
256
257 container.Clear();
258
259 for (auto itType = GetLoadedResources().GetIterator(); itType.IsValid(); itType.Next())
260 {
261 const plRTTI* pDerivedType = itType.Key();
262
263 if (pDerivedType->IsDerivedFrom(pBaseType))
264 {
265 const LoadedResources& lr = GetLoadedResources()[pDerivedType];
266
267 container.Reserve(container.GetCount() + lr.m_Resources.GetCount());
268
269 for (auto itResource : lr.m_Resources)
270 {
271 container.PushBack(itResource.Value());
272 }
273 }
274 }
275
276 return loadedResourcesLock;
277}
278
279template <typename ResourceType>
281{
282 ResourceType* pResource = BeginAcquireResource(hResource, plResourceAcquireMode::PointerOnly);
283
284 bool res = ReloadResource(pResource, bForce);
285
286 EndAcquireResource(pResource);
287
288 return res;
289}
290
291PL_FORCE_INLINE bool plResourceManager::ReloadResource(const plRTTI* pType, const plTypelessResourceHandle& hResource, bool bForce)
292{
293 plResource* pResource = BeginAcquireResourcePointer(pType, hResource);
294
295 bool res = ReloadResource(pResource, bForce);
296
297 EndAcquireResourcePointer(pResource);
298
299 return res;
300}
301
302template <typename ResourceType>
304{
305 return ReloadResourcesOfType(plGetStaticRTTI<ResourceType>(), bForce);
306}
307
308template <typename ResourceType>
310{
311 PL_LOCK(s_ResourceMutex);
312
313 GetResourceTypeLoaders()[plGetStaticRTTI<ResourceType>()] = pCreator;
314}
315
316template <typename ResourceType>
318{
319 PL_ASSERT_DEV(IsExportModeEnabled(), "Export mode needs to be enabled");
320
321 return LoadResource<ResourceType>(sResourceID);
322}
323
324template <typename ResourceType>
326{
327 GetResourceTypeInfo(plGetStaticRTTI<ResourceType>()).m_bIncrementalUnload = bActive;
328}
plUInt32 GetCount() const
Returns the number of active entries in the table.
Definition HashTable_inl.h:343
Provides access to an object while managing a lock (e.g. a mutex) that ensures that during its lifeti...
Definition LockedObject.h:7
This class holds information about reflected types. Each instance represents one type that is known t...
Definition RTTI.h:30
PL_ALWAYS_INLINE plStringView GetTypeName() const
Returns the name of this type.
Definition RTTI.h:48
PL_ALWAYS_INLINE bool IsDerivedFrom(const plRTTI *pBaseType) const
Returns true if this type is derived from the given type (or of the same type).
Definition RTTI.h:60
The base class for all resources.
Definition Resource.h:10
static void EndAcquireResource(ResourceType *pResource)
Needs to be called in concert with BeginAcquireResource() after accessing a resource has been finishe...
Definition ResourceManager_inl.h:231
static bool IsExportModeEnabled()
Returns whether export mode is active.
Definition ResourceManager.cpp:902
static const plTypedResourceHandle< RESOURCE_TYPE > & GetResourceTypeMissingFallback()
Definition ResourceManager.h:391
static void SetResourceTypeLoader(plResourceTypeLoader *pCreator)
Sets the resource loader to use for the given resource type.
Definition ResourceManager_inl.h:309
static plLockedObject< plMutex, plDynamicArray< plResource * > > GetAllResourcesOfType()
Retrieves an array of pointers to resources of the indicated type which are loaded at the moment....
Definition ResourceManager_inl.h:244
static plTypedResourceHandle< ResourceType > GetResourceHandleForExport(plStringView sResourceID)
Creates a resource handle for the given resource ID. This method can only be used if export mode is e...
Definition ResourceManager_inl.h:317
static ResourceType * BeginAcquireResource(const plTypedResourceHandle< ResourceType > &hResource, plResourceAcquireMode mode, const plTypedResourceHandle< ResourceType > &hLoadingFallback=plTypedResourceHandle< ResourceType >(), plResourceAcquireResult *out_pAcquireResult=nullptr)
Acquires a resource pointer from a handle. Prefer to use plResourceLock, which wraps BeginAcquireReso...
Definition ResourceManager_inl.h:115
static plUInt32 GetForceNoFallbackAcquisition()
If the returned number is greater 0 the resource manager treats plResourceAcquireMode::AllowLoadingFa...
Definition ResourceManager.cpp:919
static bool ReloadResource(const plTypedResourceHandle< ResourceType > &hResource, bool bForce)
Reloads only the one specific resource. If bForce is true, it is updated, even if there is no indicat...
Definition ResourceManager_inl.h:280
static plResource * BeginAcquireResourcePointer(const plRTTI *pType, const plTypelessResourceHandle &hResource)
Same as BeginAcquireResource but only for the base resource pointer.
Definition ResourceManager_inl.h:100
static void SetIncrementalUnloadForResourceType(bool bActive)
If set to 'false' resources of the given type will not be incrementally unloaded in the background,...
Definition ResourceManager_inl.h:325
static plTypedResourceHandle< ResourceType > GetOrCreateResource(plStringView sResourceID, DescriptorType &&descriptor, plStringView sResourceDescription=nullptr)
Returns a handle to the resource with the given ID if it exists or creates it from a descriptor.
Definition ResourceManager_inl.h:88
static plTypedResourceHandle< ResourceType > LoadResource(plStringView sResourceID)
Returns a handle to the requested resource. szResourceID must uniquely identify the resource,...
Definition ResourceManager_inl.h:12
static plUInt32 ReloadResourcesOfType(bool bForce)
Goes through all resources of the given type and makes sure they are reloaded, if they have changed....
Definition ResourceManager_inl.h:303
static plTypedResourceHandle< ResourceType > GetExistingResource(plStringView sResourceID)
Returns a handle to the resource with the given ID. If the resource does not exist,...
Definition ResourceManager_inl.h:38
static const plTypedResourceHandle< RESOURCE_TYPE > & GetResourceTypeLoadingFallback()
Definition ResourceManager.h:375
static void EndAcquireResourcePointer(plResource *pResource)
Same as EndAcquireResource but without the template parameter. See also BeginAcquireResourcePointer.
Definition ResourceManager_inl.h:237
static plTypedResourceHandle< ResourceType > CreateResource(plStringView sResourceID, DescriptorType &&descriptor, plStringView sResourceDescription=nullptr)
Creates a resource from a descriptor.
Definition ResourceManager_inl.h:55
Base class for all resource loaders.
Definition ResourceTypeLoader.h:29
plStringView represent a read-only sub-string of a larger string, as it can store a dedicated string ...
Definition StringView.h:34
A class to use together with plHashedString for quick comparisons with temporary strings that need no...
Definition HashedString.h:151
The plTypedResourceHandle controls access to an plResource.
Definition ResourceHandle.h:136
PL_ALWAYS_INLINE bool IsValid() const
Returns whether the handle stores a valid pointer to a resource.
Definition ResourceHandle.h:206
The typeless implementation of resource handles. A typed interface is provided by plTypedResourceHand...
Definition ResourceHandle.h:32
@ IsCreatedResource
When this is set, the resource was created and not loaded from file.
Definition Declarations.h:70
Describes in which loading state a resource currently is, and how many different quality levels there...
Definition Declarations.h:102