ソースを参照

Project library dependant resource import (untested)

Marko Pintera 10 年 前
コミット
ecfe9ff397

+ 2 - 1
BansheeCore/Include/BsCorePrerequisites.h

@@ -326,7 +326,8 @@ namespace BansheeEngine
 		TID_ResourceMetaData = 1071,
 		TID_ShaderInclude = 1072,
 		TID_Viewport = 1073,
-		TID_ResourceDependencies = 1074
+		TID_ResourceDependencies = 1074,
+		TID_ShaderMetaData = 1075,
 	};
 }
 

+ 28 - 0
BansheeCore/Include/BsShader.h

@@ -3,6 +3,7 @@
 #include "BsCorePrerequisites.h"
 #include "BsResource.h"
 #include "BsStringID.h"
+#include "BsResourceMetaData.h"
 
 namespace BansheeEngine
 {
@@ -392,6 +393,15 @@ namespace BansheeEngine
 		 */
 		SPtr<ShaderCore> getCore() const;
 
+		/**
+		 * @brief	Sets a list include file paths that are referenced by this shader.
+		 *
+		 * @note	This is not used directly by the shader as includes are expected to be
+		 *			processed during GPU program and state creation, but it may be referenced 
+		 *			by higher layers for various purposes.
+		 */
+		void setIncludeFiles(const Vector<String>& includes);
+
 		/**
 		 * @brief	Checks is the provided object type a sampler.
 		 */
@@ -461,4 +471,22 @@ namespace BansheeEngine
 		static RTTITypeBase* getRTTIStatic();
 		virtual RTTITypeBase* getRTTI() const;	
 	};
+
+	/**
+	 * @brief	Shader specific resource meta-data containing information
+	 *			about referenced include files.
+	 */
+	class BS_CORE_EXPORT ShaderMetaData : public ResourceMetaData
+	{
+	public:
+		Vector<String> includes;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class ShaderMetaDataRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+	};
 }

+ 29 - 0
BansheeCore/Include/BsShaderRTTI.h

@@ -299,4 +299,33 @@ namespace BansheeEngine
 			return Shader::createEmpty();
 		}
 	};
+
+	class BS_CORE_EXPORT ShaderMetaDataRTTI : public RTTIType < ShaderMetaData, ResourceMetaData, ShaderMetaDataRTTI >
+	{
+	private:
+		Vector<String>& getIncludes(ShaderMetaData* obj) { return obj->includes; }
+		void setIncludes(ShaderMetaData* obj, Vector<String>& includes) { obj->includes = includes; }
+
+	public:
+		ShaderMetaDataRTTI()
+		{
+			addPlainField("includes", 0, &ShaderMetaDataRTTI::getIncludes, &ShaderMetaDataRTTI::setIncludes);
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "ShaderMetaData";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_ShaderMetaData;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return bs_shared_ptr<ShaderMetaData>();
+		}
+	};
 }

+ 18 - 2
BansheeCore/Source/BsShader.cpp

@@ -303,7 +303,7 @@ namespace BansheeEngine
 	ShaderCore::ShaderCore(const String& name, const SHADER_DESC_CORE& desc, const Vector<SPtr<TechniqueCore>>& techniques)
 		:TShader(name, desc, techniques)
 	{
-
+		
 	}
 
 	SPtr<ShaderCore> ShaderCore::create(const String& name, const SHADER_DESC_CORE& desc, const Vector<SPtr<TechniqueCore>>& techniques)
@@ -319,7 +319,7 @@ namespace BansheeEngine
 	Shader::Shader(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques)
 		:TShader(name, desc, techniques)
 	{
-
+		mMetaData = bs_shared_ptr<ShaderMetaData>();
 	}
 
 	SPtr<ShaderCore> Shader::getCore() const
@@ -327,6 +327,12 @@ namespace BansheeEngine
 		return std::static_pointer_cast<ShaderCore>(mCoreSpecific);
 	}
 
+	void Shader::setIncludeFiles(const Vector<String>& includes)
+	{
+		SPtr<ShaderMetaData> meta = std::static_pointer_cast<ShaderMetaData>(getMetaData());
+		meta->includes = includes;
+	}
+
 	SPtr<CoreObjectCore> Shader::createCore() const
 	{
 		Vector<SPtr<TechniqueCore>> techniques;
@@ -486,4 +492,14 @@ namespace BansheeEngine
 	{
 		return Shader::getRTTIStatic();
 	}
+
+	RTTITypeBase* ShaderMetaData::getRTTIStatic()
+	{
+		return ShaderMetaDataRTTI::instance();
+	}
+
+	RTTITypeBase* ShaderMetaData::getRTTI() const
+	{
+		return ShaderMetaData::getRTTIStatic();
+	}
 }

+ 11 - 0
BansheeEditor/Include/BsProjectLibrary.h

@@ -87,6 +87,9 @@ namespace BansheeEngine
 		Path mProjectFolder;
 		Path mResourcesFolder;
 
+		UnorderedMap<Path, Vector<Path>> mDependencies;
+		UnorderedSet<Path> mReimportQueue;
+
 		void save();
 		void load();
 
@@ -104,6 +107,14 @@ namespace BansheeEngine
 		Path getMetaPath(const Path& path) const;
 		bool isMeta(const Path& fullPath) const;
 
+		void doOnEntryRemoved(const LibraryEntry* entry);
+		void doOnEntryAdded(const LibraryEntry* entry);
+
 		void onMonitorFileModified(const Path& path);
+
+		Vector<Path> getImportDependencies(const ResourceEntry* entry);
+		void addDependencies(const ResourceEntry* entry);
+		void removeDependencies(const ResourceEntry* entry);
+		void queueDependantForReimport(const ResourceEntry* entry);
 	};
 }

+ 6 - 0
BansheeEditor/Include/BsShaderIncludeHandler.h

@@ -17,5 +17,11 @@ namespace BansheeEngine
 		 * @copydoc	IShaderIncludeHandler::findInclude
 		 */
 		virtual HShaderInclude findInclude(const String& name) const override;
+
+		/**
+		 * @brief	Converts a shader include name or path to a path
+		 *			of the resource containing include data.
+		 */
+		static Path toResourcePath(const String& name);
 	};
 }

+ 106 - 19
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -14,6 +14,7 @@
 #include "BsProjectLibraryEntries.h"
 #include "BsResource.h"
 #include "BsResourceImporter.h"
+#include "BsShader.h"
 #include <regex>
 
 using namespace std::placeholders;
@@ -87,6 +88,20 @@ namespace BansheeEngine
 	void ProjectLibrary::update()
 	{
 		mMonitor->_update();
+
+		while (!mReimportQueue.empty())
+		{
+			Path toReimport = *mReimportQueue.begin();
+			LibraryEntry* entry = findEntry(toReimport);
+			if (entry != nullptr && entry->type == LibraryEntryType::File)
+			{
+				ResourceEntry* resEntry = static_cast<ResourceEntry*>(entry);
+				reimportResourceInternal(resEntry, resEntry->meta->getImportOptions(), true);
+				queueDependantForReimport(resEntry);
+			}
+
+			mReimportQueue.erase(mReimportQueue.begin());
+		}
 	}
 
 	void ProjectLibrary::checkForModifications(const Path& fullPath)
@@ -133,7 +148,9 @@ namespace BansheeEngine
 		{
 			if(FileSystem::isFile(entry->path))
 			{
-				reimportResourceInternal(static_cast<ResourceEntry*>(entry));
+				ResourceEntry* resEntry = static_cast<ResourceEntry*>(entry);
+				reimportResourceInternal(resEntry);
+				queueDependantForReimport(resEntry);
 			}
 			else
 			{
@@ -204,6 +221,7 @@ namespace BansheeEngine
 							if(existingEntry != nullptr)
 							{
 								reimportResourceInternal(existingEntry);
+								queueDependantForReimport(existingEntry);
 							}
 							else
 							{
@@ -267,9 +285,7 @@ namespace BansheeEngine
 		parent->mChildren.push_back(newResource);
 
 		reimportResourceInternal(newResource, importOptions, forceReimport);
-
-		if(!onEntryAdded.empty())
-			onEntryAdded(filePath);
+		doOnEntryAdded(newResource);
 
 		return newResource;
 	}
@@ -279,9 +295,7 @@ namespace BansheeEngine
 		DirectoryEntry* newEntry = bs_new<DirectoryEntry>(dirPath, dirPath.getWTail(), parent);
 		parent->mChildren.push_back(newEntry);
 
-		if(!onEntryAdded.empty())
-			onEntryAdded(dirPath);
-
+		doOnEntryAdded(newEntry);
 		return newEntry;
 	}
 
@@ -305,9 +319,7 @@ namespace BansheeEngine
 
 		parent->mChildren.erase(findIter);
 
-		if(!onEntryRemoved.empty())
-			onEntryRemoved(resource->path);
-
+		doOnEntryRemoved(resource);
 		bs_delete(resource);
 	}
 
@@ -334,9 +346,7 @@ namespace BansheeEngine
 			parent->mChildren.erase(findIter);
 		}
 
-		if(!onEntryRemoved.empty())
-			onEntryRemoved(directory->path);
-
+		doOnEntryRemoved(directory);
 		bs_delete(directory);
 	}
 
@@ -380,7 +390,6 @@ namespace BansheeEngine
 				curImportOptions = importOptions;
 
 			HResource importedResource;
-
 			if(resource->meta == nullptr)
 			{
 				importedResource = Importer::instance().import(resource->path, curImportOptions);
@@ -394,10 +403,14 @@ namespace BansheeEngine
 			}
 			else
 			{
+				removeDependencies(resource);
+
 				importedResource = HResource(resource->meta->getUUID());
 				Importer::instance().reimport(importedResource, resource->path, curImportOptions);
 			}
 
+			addDependencies(resource);
+
 			Path internalResourcesPath = mProjectFolder;
 			internalResourcesPath.append(INTERNAL_RESOURCES_DIR);
 
@@ -651,6 +664,8 @@ namespace BansheeEngine
 			}
 			else // Just moving internally
 			{
+				doOnEntryRemoved(oldEntry);
+
 				if(FileSystem::isFile(oldMetaPath))
 					FileSystem::move(oldMetaPath, newMetaPath);
 
@@ -700,11 +715,7 @@ namespace BansheeEngine
 					}
 				}
 
-				if(!onEntryRemoved.empty())
-					onEntryRemoved(oldPath);
-
-				if(!onEntryAdded.empty())
-					onEntryAdded(newPath);
+				doOnEntryAdded(oldEntry);
 
 				if(newHierarchyParent != nullptr)
 					checkForModifications(newHierarchyParent->path);
@@ -830,6 +841,7 @@ namespace BansheeEngine
 			{
 				ResourceEntry* resEntry = static_cast<ResourceEntry*>(entry);
 				reimportResourceInternal(resEntry, importOptions, forceReimport);
+				queueDependantForReimport(resEntry);
 			}
 		}
 	}
@@ -980,6 +992,8 @@ namespace BansheeEngine
 							}
 						}
 					}
+
+					addDependencies(resEntry);
 				}
 				else if(child->type == LibraryEntryType::Directory)
 				{
@@ -998,4 +1012,77 @@ namespace BansheeEngine
 			mResourceManifest = ResourceManifest::load(resourceManifestPath, mProjectFolder);
 		}
 	}
+
+	void ProjectLibrary::doOnEntryRemoved(const LibraryEntry* entry)
+	{
+		if (!onEntryRemoved.empty())
+			onEntryRemoved(entry->path);
+
+		if (entry->type == LibraryEntryType::File)
+		{
+			const ResourceEntry* resEntry = static_cast<const ResourceEntry*>(entry);
+			queueDependantForReimport(resEntry);
+			removeDependencies(resEntry);
+		}
+	}
+
+	void ProjectLibrary::doOnEntryAdded(const LibraryEntry* entry)
+	{
+		if (!onEntryAdded.empty())
+			onEntryAdded(entry->path);
+
+		if (entry->type == LibraryEntryType::File)
+		{
+			const ResourceEntry* resEntry = static_cast<const ResourceEntry*>(entry);
+			queueDependantForReimport(resEntry);
+		}
+	}
+
+	Vector<Path> ProjectLibrary::getImportDependencies(const ResourceEntry* entry)
+	{
+		Vector<Path> output;
+
+		if (entry->meta->getTypeID() == TID_Shader)
+		{
+			SPtr<ShaderMetaData> metaData = std::static_pointer_cast<ShaderMetaData>(entry->meta->getResourceMetaData());
+
+			for (auto& include : metaData->includes)
+				output.push_back(include);
+		}
+
+		return output;
+	}
+
+	void ProjectLibrary::addDependencies(const ResourceEntry* entry)
+	{
+		Vector<Path> dependencies = getImportDependencies(entry);
+		for (auto& dependency : dependencies)
+			mDependencies[dependency].push_back(entry->path);
+	}
+
+	void ProjectLibrary::removeDependencies(const ResourceEntry* entry)
+	{
+		Vector<Path> dependencies = getImportDependencies(entry);
+		for (auto& dependency : dependencies)
+		{
+			Vector<Path>& curDependencies = mDependencies[dependency];
+			auto iterRemove = std::remove_if(curDependencies.begin(), curDependencies.end(),
+				[&](const Path& x)
+			{
+				return x == entry->path;
+			});
+
+			curDependencies.erase(iterRemove, curDependencies.end());
+		}
+	}
+	
+	void ProjectLibrary::queueDependantForReimport(const ResourceEntry* entry)
+	{
+		auto iterFind = mDependencies.find(entry->path);
+		if (iterFind == mDependencies.end())
+			return;
+
+		for (auto& dependency : iterFind->second)
+			mReimportQueue.insert(dependency);
+	}
 }

+ 27 - 11
BansheeEditor/Source/BsShaderIncludeHandler.cpp

@@ -8,6 +8,29 @@
 namespace BansheeEngine
 {
 	HShaderInclude EditorShaderIncludeHandler::findInclude(const String& name) const
+	{
+		Path path = toResourcePath(name);
+
+		if (path.isEmpty())
+			return HShaderInclude();
+
+		if (name.size() >= 8)
+		{
+			if (name.substr(0, 8) == "$ENGINE$" || name.substr(0, 8) == "$EDITOR$")
+				return static_resource_cast<ShaderInclude>(Resources::instance().load(path));
+		}
+
+		ProjectLibrary::LibraryEntry* entry = ProjectLibrary::instance().findEntry(path);
+		if (entry != nullptr && entry->type == ProjectLibrary::LibraryEntryType::File)
+		{
+			ProjectLibrary::ResourceEntry* resEntry = static_cast<ProjectLibrary::ResourceEntry*>(entry);
+			return static_resource_cast<ShaderInclude>(Resources::instance().loadFromUUID(resEntry->meta->getUUID()));
+		}
+
+		return HShaderInclude();
+	}
+
+	Path EditorShaderIncludeHandler::toResourcePath(const String& name)
 	{
 		if (name.substr(0, 8) == "$ENGINE$")
 		{
@@ -19,7 +42,7 @@ namespace BansheeEngine
 				fullPath.append(includePath);
 				fullPath.setFilename(includePath.getFilename() + ".asset");
 
-				return static_resource_cast<ShaderInclude>(Resources::instance().load(fullPath));
+				return fullPath;
 			}
 		}
 		else if (name.substr(0, 8) == "$EDITOR$")
@@ -32,21 +55,14 @@ namespace BansheeEngine
 				fullPath.append(includePath);
 				fullPath.setFilename(includePath.getFilename() + ".asset");
 
-				return static_resource_cast<ShaderInclude>(Resources::instance().load(fullPath));
+				return fullPath;
 			}
 		}
 		else
 		{
-			Path path = name;
-
-			ProjectLibrary::LibraryEntry* entry = ProjectLibrary::instance().findEntry(path);
-			if (entry != nullptr && entry->type == ProjectLibrary::LibraryEntryType::File)
-			{
-				ProjectLibrary::ResourceEntry* resEntry = static_cast<ProjectLibrary::ResourceEntry*>(entry);
-				return static_resource_cast<ShaderInclude>(Resources::instance().loadFromUUID(resEntry->meta->getUUID()));
-			}
+			return name;
 		}
 
-		return HShaderInclude();
+		return Path::BLANK;
 	}
 }

+ 12 - 5
BansheeSL/Source/BsSLFXCompiler.cpp

@@ -1485,8 +1485,6 @@ namespace BansheeEngine
 		if (parseState->rootNode == nullptr || parseState->rootNode->type != NT_Shader)
 			return nullptr;
 
-		Vector<String> includeDependencies;
-
 		// Merge all include ASTs
 		std::function<ParseState*(ParseState*, Vector<CodeBlock>&)> parseIncludes = [&](ParseState* parentParseState, Vector<CodeBlock>& parentCodeBlocks)
 		{
@@ -1500,8 +1498,6 @@ namespace BansheeEngine
 				if (option->type == OT_Include)
 				{
 					String includePath = removeQuotes(option->value.strValue);
-					includeDependencies.push_back(includePath);
-
 					HShaderInclude include = ShaderManager::instance().findInclude(includePath);
 
 					if (include != nullptr)
@@ -1566,6 +1562,8 @@ namespace BansheeEngine
 
 		parseState = parseIncludes(parseState, codeBlocks);
 		
+		Vector<String> topLevelIncludes;
+
 		SHADER_DESC shaderDesc;
 		Vector<TechniquePtr> techniques;
 
@@ -1575,6 +1573,12 @@ namespace BansheeEngine
 
 			switch (option->type)
 			{
+			case OT_Include:
+			{
+				String includePath = removeQuotes(option->value.strValue);
+				topLevelIncludes.push_back(includePath);
+			}
+				break;
 			case OT_Separable:
 				shaderDesc.separablePasses = option->value.intValue > 1;
 				break;
@@ -1603,7 +1607,10 @@ namespace BansheeEngine
 
 		parseStateDelete(parseState);
 
-		return Shader::_createPtr(name, shaderDesc, techniques);
+		ShaderPtr output = Shader::_createPtr(name, shaderDesc, techniques);
+		output->setIncludeFiles(topLevelIncludes);
+
+		return output;
 	}
 
 	String BSLFXCompiler::removeQuotes(const char* input)