//-------------------------------------------------------------------------------------- // File: SharedResourcePool.h // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // // http://go.microsoft.com/fwlink/?LinkId=248929 //-------------------------------------------------------------------------------------- #pragma once #include #include #include "PlatformHelpers.h" namespace DirectX { // Pool manager ensures that only a single TData instance is created for each unique TKey. // This is used to avoid duplicate resource creation, so that for instance a caller can // create any number of SpriteBatch instances, but these can internally share shaders and // vertex buffer if more than one SpriteBatch uses the same underlying D3D device. template class SharedResourcePool { public: SharedResourcePool() : mResourceMap(std::make_shared()) { } // Allocates or looks up the shared TData instance for the specified key. std::shared_ptr DemandCreate(TKey key) { std::lock_guard lock(mResourceMap->mutex); // Return an existing instance? auto pos = mResourceMap->find(key); if (pos != mResourceMap->end()) { auto existingValue = pos->second.lock(); if (existingValue) return existingValue; else mResourceMap->erase(pos); } // Allocate a new instance. auto newValue = std::make_shared(key, mResourceMap); mResourceMap->insert(std::make_pair(key, newValue)); return newValue; } private: // Keep track of all allocated TData instances. struct ResourceMap : public std::map> { std::mutex mutex; }; std::shared_ptr mResourceMap; // Wrap TData with our own subclass, so we can hook the destructor // to remove instances from our pool before they are freed. struct WrappedData : public TData { WrappedData(TKey key, std::shared_ptr const& resourceMap) : mKey(key), mResourceMap(resourceMap), TData(key) { } ~WrappedData() { std::lock_guard lock(mResourceMap->mutex); auto pos = mResourceMap->find(mKey); // Check for weak reference expiry before erasing, in case DemandCreate runs on // a different thread at the same time as a previous instance is being destroyed. // We mustn't erase replacement objects that have just been added! if (pos != mResourceMap->end() && pos->second.expired()) { mResourceMap->erase(pos); } } TKey mKey; std::shared_ptr mResourceMap; }; // Prevent copying. SharedResourcePool(SharedResourcePool const&) DIRECTX_CTOR_DELETE SharedResourcePool& operator= (SharedResourcePool const&) DIRECTX_CTOR_DELETE }; }