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

WIP Linux port:
- Variety of runtime fixes:
- System info parser now reports valid CPU and memory info
- Retrieving working directory no longer logs an error, even though it was successful
- Recursive directory creation now works even for paths whose last entry was parsed as a file (but is a directory)
- GLX procedures for FBConfig selection are now properly loaded before use
- FBConfig selection now properly selects the best config instead of failing or selecting a non-optimal configuration
- Dynamically loaded shader libraries are now looked for in the correct path
- Dynamic library loaded now automatically appends "lib" to the name, in order to support unix naming convention

Marko Pintera 8 лет назад
Родитель
Сommit
928d32dcc2

+ 1 - 1
Source/BansheeGLRenderAPI/BsGLSupport.cpp

@@ -4,7 +4,7 @@
 #include "BsGLTexture.h"
 #include "GL/glew.h"
 
-GLenum GLEWAPIENTRY glewContextInit(bs::ct::GLSupport* glSupport);
+GLenum glewContextInit(bs::ct::GLSupport* glSupport);
 
 namespace bs { namespace ct
 {

+ 54 - 24
Source/BansheeGLRenderAPI/Linux/BsLinuxGLSupport.cpp

@@ -29,14 +29,14 @@ namespace bs { namespace ct
 		return glXCreateContextAttribsARB != nullptr;
 	}
 
-	typedef void (*glXSwapIntervalEXTProc)(::Display*, GLXDrawable, int);
-	typedef int (*glXSwapIntervalMESAProc)(int);
-	typedef int (*glXSwapIntervalSGIProc)(int);
-
 	glXSwapIntervalEXTProc glXSwapIntervalEXT = nullptr;
 	glXSwapIntervalMESAProc glXSwapIntervalMESA = nullptr;
 	glXSwapIntervalSGIProc glXSwapIntervalSGI = nullptr;
 
+	glXChooseFBConfigProc glXChooseFBConfig = nullptr;
+	glXGetFBConfigAttribProc glXGetFBConfigAttrib = nullptr;
+	glXGetVisualFromFBConfigProc glXGetVisualFromFBConfig = nullptr;
+
 	bool Load_EXT_swap_control()
 	{
 		glXSwapIntervalEXT = (glXSwapIntervalEXTProc)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
@@ -118,23 +118,35 @@ namespace bs { namespace ct
 				iter++;
 
 			const char* end = iter;
-			const char* name = std::string(start, end).c_str();
+			std::string name(start, end);
 
 			UINT32 numExtensions = sizeof(gExtensionMap) / sizeof(gExtensionMap[0]);
 			for (UINT32 i = 0; i < numExtensions; ++i)
 			{
-				if(strcmp(name, gExtensionMap[i].name) == 0)
+				if(strcmp(name.c_str(), gExtensionMap[i].name) == 0)
 				{
-					if(gExtensionMap[i].func != nullptr)
-						*gExtensionMap[i].status = gExtensionMap[i].func();
+					if(gExtensionMap[i].status != nullptr)
+					{
+						if (gExtensionMap[i].func != nullptr)
+							*gExtensionMap[i].status = gExtensionMap[i].func();
+						else
+							*gExtensionMap[i].status = true;
+					}
 					else
-						*gExtensionMap[i].status = true;
+					{
+						if (gExtensionMap[i].func != nullptr)
+							gExtensionMap[i].func();
+					}
 				}
 
 			}
 
 		} while(*iter++);
 
+		glXChooseFBConfig = (glXChooseFBConfigProc)glXGetProcAddressARB((const GLubyte*)"glXChooseFBConfig");
+		glXGetFBConfigAttrib = (glXGetFBConfigAttribProc)glXGetProcAddressARB((const GLubyte*)"glXGetFBConfigAttrib");
+		glXGetVisualFromFBConfig = (glXGetVisualFromFBConfigProc)glXGetProcAddressARB((const GLubyte*)"glXGetVisualFromFBConfig");
+
 		LinuxPlatform::unlockX();
 	}
 
@@ -166,7 +178,7 @@ namespace bs { namespace ct
 
 	GLVisualConfig LinuxGLSupport::findBestVisual(::Display* display, bool depthStencil, UINT32 multisample, bool srgb) const
 	{
-		static constexpr INT32 VISUAL_ATTRIBS[] =
+		INT32 VISUAL_ATTRIBS[] =
 		{
 			GLX_X_RENDERABLE, 		True,
 			GLX_DRAWABLE_TYPE, 		GLX_WINDOW_BIT,
@@ -175,7 +187,12 @@ namespace bs { namespace ct
 			GLX_RED_SIZE,			8,
 			GLX_GREEN_SIZE,			8,
 			GLX_BLUE_SIZE,			8,
-			GLX_ALPHA_SIZE,			8
+			GLX_ALPHA_SIZE,			8,
+			GLX_DOUBLEBUFFER,		True,
+			GLX_DEPTH_SIZE,			depthStencil ? 24 : 0,
+			GLX_STENCIL_SIZE,		depthStencil ? 8 : 0,
+			GLX_SAMPLE_BUFFERS,		multisample > 1 ? 1 : 0,
+			0
 		};
 
 		INT32 numConfigs;
@@ -190,28 +207,36 @@ namespace bs { namespace ct
 			INT32 configScore = 0;
 
 			// Depth buffer contributes the most to score
+			INT32 depth, stencil;
+			glXGetFBConfigAttrib(display, configs[i], GLX_DEPTH_SIZE, &depth);
+			glXGetFBConfigAttrib(display, configs[i], GLX_STENCIL_SIZE, &stencil);
+
+			// Depth buffer was requested
 			if(depthStencil)
 			{
-				INT32 depth, stencil;
-				glXGetFBConfigAttrib(display, configs[i], GLX_DEPTH_SIZE, &depth);
-				glXGetFBConfigAttrib(display, configs[i], GLX_STENCIL_SIZE, &stencil);
-
 				INT32 score = 0;
-				if(depth == 24 && stencil == 8)
+				if (depth == 24 && stencil == 8)
 					score = 10000;
-				else if(depth == 32 && stencil == 8)
+				else if (depth == 32 && stencil == 8)
 					score = 9000;
-				else if(depth == 32)
+				else if (depth == 32)
 					score = 8000;
-				else if(depth == 16)
+				else if (depth == 24)
 					score = 7000;
+				else if (depth == 16)
+					score = 6000;
 
-				if(score > 0)
+				if (score > 0)
 				{
 					configScore += score;
 					caps[i].depthStencil = true;
 				}
 			}
+			else // Depth buffer not requested, prefer configs without it
+			{
+				if(depth == 0 && stencil == 0)
+					configScore += 10000;
+			}
 
 			// sRGB contributes second most
 			if(srgb)
@@ -255,11 +280,16 @@ namespace bs { namespace ct
 
 		if(bestConfig == -1)
 		{
-			// Something went wrong
-			XFree(configs);
-			bs_stack_delete(caps, (UINT32)numConfigs);
+			if(numConfigs > 0)
+				bestConfig = 0;
+			else
+			{
+				// Something went wrong
+				XFree(configs);
+				bs_stack_delete(caps, (UINT32) numConfigs);
 
-			return output;
+				return output;
+			}
 		}
 
 		XVisualInfo* visualInfo = glXGetVisualFromFBConfig(display, configs[bestConfig]);

+ 13 - 1
Source/BansheeGLRenderAPI/Linux/BsLinuxGLSupport.h

@@ -3,7 +3,6 @@
 #pragma once
 
 #include <X11/Xutil.h>
-#include <GL/glxew.h>
 #include "BsGLSupport.h"
 #include "BsGLRenderAPI.h"
 
@@ -15,6 +14,11 @@ namespace bs { namespace ct
 	 *  @{
 	 */
 
+	typedef XID GLXDrawable;
+	typedef struct __GLXcontextRec *GLXContext;
+	typedef XID GLXWindow;
+	typedef struct __GLXFBConfigRec *GLXFBConfig;
+
 	// Extensions
 	extern bool extGLX_ARB_multisample;
 	extern bool extGLX_ARB_framebuffer_sRGB;
@@ -36,6 +40,14 @@ namespace bs { namespace ct
 	extern glXSwapIntervalMESAProc glXSwapIntervalMESA;
 	extern glXSwapIntervalSGIProc glXSwapIntervalSGI;
 
+	typedef GLXFBConfig* (*glXChooseFBConfigProc) (Display *dpy, int screen, const int *attrib_list, int *nelements);
+	typedef int (*glXGetFBConfigAttribProc) (Display *dpy, GLXFBConfig config, int attribute, int *value);
+	typedef XVisualInfo* (*glXGetVisualFromFBConfigProc) (Display *dpy, GLXFBConfig config);
+
+	extern glXChooseFBConfigProc glXChooseFBConfig;
+	extern glXGetFBConfigAttribProc glXGetFBConfigAttrib;
+	extern glXGetVisualFromFBConfigProc glXGetVisualFromFBConfig;
+
 	/** Determines which features are supported by a particular framebuffer configuration. */
 	struct GLVisualCapabilities
 	{

+ 4 - 0
Source/BansheeUtility/Linux/BsUnixCrashHandler.cpp

@@ -10,6 +10,7 @@
 
 #include <ctime>
 #include <sstream>
+#include <csignal>
 
 namespace bs
 {
@@ -103,5 +104,8 @@ namespace bs
 	{
 		logErrorAndStackTrace(type, description, function, file, line);
 		saveCrashLog();
+
+		// Allow the debugger a chance to attach
+		std::raise(SIGINT);
 	}
 }

+ 7 - 6
Source/BansheeUtility/Linux/BsUnixFileSystem.cpp

@@ -177,6 +177,10 @@ namespace bs
 			parentPath.append(path[i]);
 			unix_createDirectory(parentPath.toString());
 		}
+
+		// Last "file" entry is also considered a directory
+		if(!parentPath.equals(path))
+			unix_createDirectory(path.toString());
 	}
 
 	void FileSystem::getChildren(const Path& dirPath, Vector<Path>& files, Vector<Path>& directories)
@@ -222,15 +226,12 @@ namespace bs
 		char *buffer = bs_newN<char>(PATH_MAX);
 
 		String wd;
-		if (getcwd(buffer, PATH_MAX) != NULL)
+		if (getcwd(buffer, PATH_MAX) != nullptr)
 			wd = buffer;
+		else
+			LOGERR(String("Error when calling getcwd(): ") + strerror(errno));
 
 		bs_free(buffer);
-
-		const int error = errno;
-		if (error)
-			LOGERR(String("Error when calling getcwd(): ") + strerror(error));
-
 		return Path(wd);
 	}
 

+ 19 - 18
Source/BansheeUtility/Linux/BsUnixPlatformUtility.cpp

@@ -21,56 +21,57 @@ namespace bs
 
 		// Get CPU vendor, model and number of cores
 		{
-			std::ifstream file("/proc/meminfo");
-			std::string token;
-			while(file >> token)
+			std::ifstream file("/proc/cpuinfo");
+			std::string line;
+			while(std::getline(file, line))
 			{
+				std::stringstream lineStream(line);
+				std::string token;
+				lineStream >> token;
+
 				if(token == "vendor_id")
 				{
-					if(file >> token && token == ":")
+					if(lineStream >> token && token == ":")
 					{
 						std::string vendorId;
-						if(file >> vendorId)
+						if(lineStream >> vendorId)
 							output.cpuManufacturer = vendorId.c_str();
 					}
 				}
 				else if(token == "model")
 				{
-					if(file >> token && token == "name")
+					if(lineStream >> token && token == "name")
 					{
-						if (file >> token && token == ":")
+						if (lineStream >> token && token == ":")
 						{
 							std::stringstream modelName;
-							if (file >> token)
+							if (lineStream >> token)
 							{
 								modelName << token;
 
-								while (file >> token)
+								while (lineStream >> token)
 									modelName << " " << token;
 							}
 
-							output.cpuManufacturer = modelName.str().c_str();
+							output.cpuModel = modelName.str().c_str();
 						}
 					}
 				}
 				else if(token == "cpu")
 				{
-					if(file >> token)
+					if(lineStream >> token)
 					{
 						if (token == "cores")
 						{
-							if (file >> token && token == ":")
+							if (lineStream >> token && token == ":")
 							{
 								UINT32 numCores;
-								if (file >> numCores)
+								if (lineStream >> numCores)
 									output.cpuNumCores = numCores;
 							}
 						}
 					}
 				}
-
-				// Ignore the rest of the line
-				file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 			}
 		}
 
@@ -79,7 +80,7 @@ namespace bs
 			std::ifstream file("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
 			UINT32 frequency;
 			if(file >> frequency)
-				output.cpuClockSpeedMhz = frequency / (1000 * 1000);
+				output.cpuClockSpeedMhz = frequency / 1000;
 		}
 
 		// Get amount of system memory
@@ -92,7 +93,7 @@ namespace bs
 				{
 					UINT32 memTotal;
 					if(file >> memTotal)
-						output.memoryAmountMb = memTotal / (1024 * 1024);
+						output.memoryAmountMb = memTotal / 1024;
 					else
 						output.memoryAmountMb = 0;
 

+ 11 - 8
Source/BansheeUtility/Utility/BsDynLib.cpp

@@ -20,10 +20,13 @@ namespace bs
 
 #if BS_PLATFORM == BS_PLATFORM_LINUX
 	const char* DynLib::EXTENSION = "so";
+	const char* DynLib::PREFIX = "lib";
 #elif BS_PLATFORM == BS_PLATFORM_OSX
 	const char* DynLib::EXTENSION = "dylib";
+	const char* DynLib::PREFIX = "lib";
 #elif BS_PLATFORM == BS_PLATFORM_WIN32
 	const char* DynLib::EXTENSION = "dll";
+	const char* DynLib::PREFIX = nullptr;
 #else
 	#error Unhandled platform
 #endif
@@ -31,7 +34,7 @@ namespace bs
 	DynLib::DynLib(const String& name)
 	{
 		mName = name;
-		m_hInst = nullptr;
+		mHandle = nullptr;
 
 		load();
 	}
@@ -42,12 +45,12 @@ namespace bs
 
 	void DynLib::load()
 	{
-		if (m_hInst)
+		if (mHandle)
 			return;
 
-		m_hInst = (DYNLIB_HANDLE)DYNLIB_LOAD(mName.c_str());
+		mHandle = (DYNLIB_HANDLE)DYNLIB_LOAD(mName.c_str());
 
-		if (!m_hInst)
+		if (!mHandle)
 		{
 			BS_EXCEPT(InternalErrorException,
 				"Could not load dynamic library " + mName +
@@ -57,10 +60,10 @@ namespace bs
 
 	void DynLib::unload()
 	{
-		if (!m_hInst)
+		if (!mHandle)
 			return;
 
-		if (DYNLIB_UNLOAD(m_hInst))
+		if (DYNLIB_UNLOAD(mHandle))
 		{
 			BS_EXCEPT(InternalErrorException,
 				"Could not unload dynamic library " + mName +
@@ -70,10 +73,10 @@ namespace bs
 
 	void* DynLib::getSymbol(const String& strName) const
 	{
-		if (!m_hInst)
+		if (!mHandle)
 			return nullptr;
 
-		return (void*)DYNLIB_GETSYM(m_hInst, strName.c_str());
+		return (void*)DYNLIB_GETSYM(mHandle, strName.c_str());
 	}
 
 	String DynLib::dynlibError()

+ 5 - 2
Source/BansheeUtility/Utility/BsDynLib.h

@@ -33,9 +33,12 @@ namespace bs
 	class BS_UTILITY_EXPORT DynLib
     {
     public:
-		/** System-specific file extension for a dynamic library (e.g. "dll"). */
+		/** Platform-specific file extension for a dynamic library (e.g. "dll"). */
 		static const char* EXTENSION;
 
+		/** Platform-specific name suffix for a dynamic library (e.g. "lib" on Unix) */
+		static const char* PREFIX;
+
 		/** Constructs the dynamic library object and loads the library with the specified name. */
 		DynLib(const String& name);
         ~DynLib();
@@ -65,7 +68,7 @@ namespace bs
 
     protected:
 		String mName;
-        DYNLIB_HANDLE m_hInst; // Handle to the loaded library.
+        DYNLIB_HANDLE mHandle;
     };
 
 	/** @} */

+ 3 - 0
Source/BansheeUtility/Utility/BsDynLibManager.cpp

@@ -19,6 +19,9 @@ namespace bs
 		if (length <= extLength || filename.substr(length - extLength) != extension)
 			filename += extension;
 
+		if(DynLib::PREFIX != nullptr)
+			filename = DynLib::PREFIX + filename;
+
 		auto iterFind = mLoadedLibraries.find(filename);
 		if (iterFind != mLoadedLibraries.end())
 		{

+ 2 - 2
Source/CMakeLists.txt

@@ -170,7 +170,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
 	# Note: Optionally add -ffunction-sections, -fdata-sections, but with linker option --gc-sections
 	# TODO: Use link-time optimization -flto. Might require non-default linker.
 	set(BS_COMPILER_FLAGS_COMMON "-Wall -fPIC -fno-exceptions -fno-strict-aliasing -fno-rtti -fno-ms-compatibility
-	-fms-extensions")
+	-fms-extensions -Wl,-rpath=$ORIGIN")
 	
 	set(CMAKE_CXX_FLAGS_DEBUG "${BS_COMPILER_FLAGS_COMMON} -g -O0")
 	set(CMAKE_CXX_FLAGS_OPTIMIZEDDEBUG "${BS_COMPILER_FLAGS_COMMON} -gline-tables-only -O2")
@@ -181,7 +181,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
 	set(CMAKE_EXE_LINKER_FLAGS_RELEASE -s)
 elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 	# TODO: Use link-time optimization -flto. Might require non-default linker.
-	set(BS_COMPILER_FLAGS_COMMON "-Wall -fPIC -fno-exceptions -fno-strict-aliasing -fno-rtti")
+	set(BS_COMPILER_FLAGS_COMMON "-Wall -fPIC -fno-exceptions -fno-strict-aliasing -fno-rtti -Wl,-rpath=$ORIGIN")
 	
 	set(CMAKE_CXX_FLAGS_DEBUG "${BS_COMPILER_FLAGS_COMMON} -g -O0")
 	set(CMAKE_CXX_FLAGS_OPTIMIZEDDEBUG "${BS_COMPILER_FLAGS_COMMON} -gline-tables-only -O2")