Просмотр исходного кода

Better error reporting when shaders fail to compile

BearishSun 8 лет назад
Родитель
Сommit
47fcc0fec4

BIN
Data/Examples/Example.bsl.asset


+ 1 - 1
Data/Raw/Engine/Shaders/ReflectionCubeImportanceSample.bsl

@@ -26,7 +26,7 @@ Technique
 			#define PI 3.1415926
 		
 			// From Hacker's Delight
-			float reverseBits(uint bits) 
+			float reverseBits(uint bits)  
 			{
 				bits = (bits << 16u) | (bits >> 16u);
 				bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);

+ 7 - 1
Source/BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -2061,7 +2061,13 @@ namespace bs
 		Path programPath = EditorShaderFolder;
 		programPath.append(name + L".asset");
 
-		return gResources().load<Shader>(programPath);
+		HShader shader = gResources().load<Shader>(programPath);
+
+#if BS_DEBUG_MODE
+		BuiltinResourcesHelper::verifyAndReportShader(shader);
+#endif
+
+		return shader;
 	}
 
 	HMaterial BuiltinEditorResources::createDockDropOverlayMaterial() const

+ 5 - 1
Source/BansheeEngine/Include/BsBuiltinResourcesHelper.h

@@ -37,8 +37,9 @@ namespace bs
 		 * @param[in]	outputFolder	Folder in which to store the imported resources.
 		 * @param[in]	manifest		Manifest in which to register the imported resources in.
 		 * @param[in]	mode			Mode that controls how are files imported.
+		 * @return						True if the process was sucessful.
 		 */
-		static void importAssets(const nlohmann::json& entries, const Path& inputFolder, const Path& outputFolder, 
+		static bool importAssets(const nlohmann::json& entries, const Path& inputFolder, const Path& outputFolder, 
 			const SPtr<ResourceManifest>& manifest, AssetType mode = AssetType::Normal);
 
 		/**
@@ -66,6 +67,9 @@ namespace bs
 		 * Timestamp file must have been saved using writeTimestamp().
 		 */
 		static bool checkForModifications(const Path& folder, const Path& timeStampFile);
+
+		/** Checks if the shader compiled properly and reports the problem if it hasn't. Returns true if shader is valid. */
+		static bool verifyAndReportShader(const HShader& shader);
 	};
 
 	/** @} */

+ 7 - 1
Source/BansheeEngine/Source/BsBuiltinResources.cpp

@@ -1191,7 +1191,13 @@ namespace bs
 		programPath.append(path);
 		programPath.setExtension(programPath.getExtension() + ".asset");
 
-		return gResources().load<Shader>(programPath);
+		HShader shader = gResources().load<Shader>(programPath);
+
+#if BS_DEBUG_MODE
+		BuiltinResourcesHelper::verifyAndReportShader(shader);
+#endif
+
+		return shader;
 	}
 
 	HTexture BuiltinResources::getCursorTexture(const WString& name)

+ 66 - 2
Source/BansheeEngine/Source/BsBuiltinResourcesHelper.cpp

@@ -16,16 +16,19 @@
 #include "BsFileSystem.h"
 #include "BsCoreThread.h"
 #include "BsUUID.h"
+#include "BsShader.h"
+#include "BsPass.h"
+#include "BsGpuProgram.h"
 
 using json = nlohmann::json;
 
 namespace bs
 {
-	void BuiltinResourcesHelper::importAssets(const nlohmann::json& entries, const Path& inputFolder, 
+	bool BuiltinResourcesHelper::importAssets(const nlohmann::json& entries, const Path& inputFolder, 
 		const Path& outputFolder, const SPtr<ResourceManifest>& manifest, AssetType mode)
 	{
 		if (!FileSystem::exists(inputFolder))
-			return;
+			return true;
 
 		if (FileSystem::exists(outputFolder))
 			FileSystem::remove(outputFolder);
@@ -174,6 +177,13 @@ namespace bs
 			if (outputRes == nullptr)
 				continue;
 
+			if (rtti_is_of_type<Shader>(outputRes.get()))
+			{
+				HShader shader = static_resource_cast<Shader>(outputRes);
+				if (!verifyAndReportShader(shader))
+					return false;
+			}
+
 			if (mode == AssetType::Sprite)
 			{
 				std::string spriteUUID = entry["SpriteUUID"];
@@ -258,6 +268,8 @@ namespace bs
 				generateSprite(tex16, iconsToGenerate[i].name + "16", iconsToGenerate[i].SpriteUUIDs[2].c_str());
 			}
 		}
+
+		return true;
 	}
 
 	void BuiltinResourcesHelper::importFont(const Path& inputFile, const WString& outputName, const Path& outputFolder,
@@ -411,4 +423,56 @@ namespace bs
 
 		return !upToDate;
 	}
+
+	bool BuiltinResourcesHelper::verifyAndReportShader(const HShader& shader)
+	{
+		if(!shader.isLoaded(false) || shader->getNumTechniques() == 0)
+		{
+#if BS_DEBUG_MODE
+			BS_EXCEPT(InvalidStateException, "Error occured while compiling a shader. Check earlier log messages for exact error.");
+#else
+			LOGERR("Error occured while compiling a shader. Check earlier log messages for exact error.")
+#endif
+			return false;
+		}
+
+		Vector<SPtr<Technique>> techniques = shader->getCompatibleTechniques();
+		for(auto& technique : techniques)
+		{
+			UINT32 numPasses = technique->getNumPasses();
+			for(UINT32 i = 0; i < numPasses; i++)
+			{
+				SPtr<Pass> pass = technique->getPass(i);
+
+				std::array<SPtr<GpuProgram>, 6> gpuPrograms;
+				gpuPrograms[0] = pass->getVertexProgram();
+				gpuPrograms[1] = pass->getFragmentProgram();
+				gpuPrograms[2] = pass->getGeometryProgram();
+				gpuPrograms[3] = pass->getHullProgram();
+				gpuPrograms[4] = pass->getDomainProgram();
+				gpuPrograms[5] = pass->getComputeProgram();
+
+				for(auto& program : gpuPrograms)
+				{
+					if (program == nullptr)
+						continue;
+
+					program->blockUntilCoreInitialized();
+					if(!program->isCompiled())
+					{
+#if BS_DEBUG_MODE
+						BS_EXCEPT(InvalidStateException, "Error occured while compiling a shader. Error message: " + 
+							program->getCompileErrorMessage());
+#else
+						LOGERR("Error occured while compiling a shader. Error message: " +
+							program->getCompileErrorMessage())
+#endif
+						return false;
+					}
+				}
+			}
+		}
+
+		return true;
+	}
 }

+ 1 - 2
Source/BansheeSL/Source/BsSLFXCompiler.cpp

@@ -226,7 +226,6 @@ namespace bs
 
 			if (hasError)
 			{
-				output.shader = nullptr;
 				output.errorMessage = "Failed compiling GPU program(s): " + gpuProgError.str();
 				output.errorLine = 0;
 				output.errorColumn = 0;
@@ -1430,7 +1429,7 @@ namespace bs
 		bs_stack_free(techniqueWasParsed);
 
 		// If no GLSL technique, auto-generate them for each non-base technique
-		if(!hasGLSLTechnique)
+		if(false /*!hasGLSLTechnique*/) // TODO : Disabled for now
 		{
 			UINT32 end = (UINT32)techniqueData.size();
 			for(UINT32 i = 0; i < end; i++)

+ 3 - 2
Source/BansheeSL/Source/BsSLImporter.cpp

@@ -43,7 +43,8 @@ namespace bs
 
 		if (result.shader != nullptr)
 			result.shader->setName(shaderName);
-		else
+		
+		if(!result.errorMessage.empty())
 		{
 			String file;
 			if (result.errorFile.empty())
@@ -51,7 +52,7 @@ namespace bs
 			else
 				file = result.errorFile;
 
-			LOGERR("Error while parsing shader FX code \"" + file + "\":\n" + result.errorMessage + ". Location: " +
+			LOGERR("Compilation error when importing shader \"" + file + "\":\n" + result.errorMessage + ". Location: " +
 				toString(result.errorLine) + " (" + toString(result.errorColumn) + ")");
 		}
 

+ 4 - 0
Source/Examples/ExampleGettingStarted/Source/Main.cpp

@@ -81,6 +81,9 @@ int CALLBACK WinMain(
 	_In_  int nCmdShow
 	)
 {
+	// Ensure all errors are reported properly
+	CrashHandler::startUp();
+
 	// Descriptor used for initializing the engine
 	START_UP_DESC startUpDesc;
 
@@ -114,6 +117,7 @@ int CALLBACK WinMain(
 	Application::instance().runMainLoop();
 
 	Application::shutDown();
+	CrashHandler::shutDown();
 
 	return 0;
 }

+ 4 - 0
Source/Examples/ExampleLowLevelRendering/Source/Main.cpp

@@ -107,6 +107,9 @@ int CALLBACK WinMain(
 	_In_  int nCmdShow
 )
 {
+	// Ensure all errors are reported properly
+	CrashHandler::startUp();
+
 	// Define a video mode for the resolution of the primary rendering window.
 	VideoMode videoMode(windowResWidth, windowResHeight);
 
@@ -119,6 +122,7 @@ int CALLBACK WinMain(
 	Application::instance().runMainLoop();
 
 	Application::shutDown();
+	CrashHandler::shutDown();
 
 	return 0;
 }

+ 4 - 0
Source/Examples/ExamplePhysicallyBasedShading/Source/Main.cpp

@@ -81,6 +81,9 @@ int CALLBACK WinMain(
 	_In_  int nCmdShow
 	)
 {
+	// Ensure all errors are reported properly
+	CrashHandler::startUp();
+
 	// Descriptor used for initializing the engine
 	START_UP_DESC startUpDesc;
 
@@ -114,6 +117,7 @@ int CALLBACK WinMain(
 	Application::instance().runMainLoop();
 
 	Application::shutDown();
+	CrashHandler::shutDown();
 
 	return 0;
 }