Browse Source

Making IS more flexible. Adding android support to logger

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
7ed1fc805b

+ 0 - 4
include/anki/Config.h.cmake

@@ -96,10 +96,6 @@
 #define ANKI_MAX_INSTANCES 64
 #define ANKI_MAX_INSTANCES 64
 
 
 // Renderer and rendering related config options
 // Renderer and rendering related config options
-#define ANKI_RENDERER_MAX_POINT_LIGHTS_PER_TILE 48
-#define ANKI_RENDERER_MAX_SPOT_LIGHTS_PER_TILE 4
-#define ANKI_RENDERER_MAX_SPOT_TEX_LIGHTS_PER_TILE 4
-
 #define ANKI_RENDERER_TILES_X_COUNT 16
 #define ANKI_RENDERER_TILES_X_COUNT 16
 #define ANKI_RENDERER_TILES_Y_COUNT 16
 #define ANKI_RENDERER_TILES_Y_COUNT 16
 
 

+ 22 - 9
include/anki/core/Logger.h

@@ -1,9 +1,9 @@
 #ifndef ANKI_CORE_LOGGER_H
 #ifndef ANKI_CORE_LOGGER_H
 #define ANKI_CORE_LOGGER_H
 #define ANKI_CORE_LOGGER_H
 
 
+#include "anki/Config.h"
 #include "anki/util/Observer.h"
 #include "anki/util/Observer.h"
 #include "anki/util/Singleton.h"
 #include "anki/util/Singleton.h"
-#include "anki/Config.h"
 #include <array>
 #include <array>
 #include <mutex>
 #include <mutex>
 #include <sstream> // For the macros
 #include <sstream> // For the macros
@@ -15,9 +15,13 @@ namespace anki {
 
 
 /// The logger singleton class. The logger cannot print errors or throw
 /// The logger singleton class. The logger cannot print errors or throw
 /// exceptions, it has to recover somehow. Its thread safe
 /// exceptions, it has to recover somehow. Its thread safe
+/// To add a new signal: 
+/// @code ANKI_CONNECT(&logger, messageRecieved, &instance, handle) @endcode
 class Logger
 class Logger
 {
 {
 public:
 public:
+	ANKI_HAS_SLOTS(Logger)
+
 	/// Logger message type
 	/// Logger message type
 	enum LoggerMessageType
 	enum LoggerMessageType
 	{
 	{
@@ -36,14 +40,25 @@ public:
 		const char* msg;
 		const char* msg;
 	};
 	};
 
 
+	Logger();
+
 	/// Send a message
 	/// Send a message
 	void write(const char* file, int line, const char* func,
 	void write(const char* file, int line, const char* func,
 		LoggerMessageType type, const char* msg);
 		LoggerMessageType type, const char* msg);
 
 
+	/// Send a formated message
+	void writeFormated(const char* file, int line, const char* func,
+		LoggerMessageType type, const char* fmt, ...);
+
 	ANKI_SIGNAL(const Info&, messageRecieved)
 	ANKI_SIGNAL(const Info&, messageRecieved)
 
 
 private:
 private:
 	std::mutex mutex; ///< For thread safety
 	std::mutex mutex; ///< For thread safety
+
+	/// Depending on the OS implement a different handler. This one is the 
+	/// default one
+	void defaultSystemMessageHandler(const Info& info);
+	ANKI_SLOT(defaultSystemMessageHandler, const Logger::Info&)
 };
 };
 
 
 typedef Singleton<Logger> LoggerSingleton;
 typedef Singleton<Logger> LoggerSingleton;
@@ -55,19 +70,17 @@ typedef Singleton<Logger> LoggerSingleton;
 // Macros                                                                      =
 // Macros                                                                      =
 //==============================================================================
 //==============================================================================
 
 
-#define ANKI_LOGGER_MESSAGE(t, msg) \
+#define ANKI_LOGGER_MESSAGE(t, ...) \
 	do \
 	do \
 	{ \
 	{ \
-		std::stringstream ss; \
-		ss << msg; \
-		LoggerSingleton::get().write(ANKI_FILE, __LINE__, ANKI_FUNC, \
-			t, ss.str().c_str()); \
+		LoggerSingleton::get().writeFormated(ANKI_FILE, __LINE__, ANKI_FUNC, \
+			t, __VA_ARGS__); \
 	} while(false);
 	} while(false);
 
 
-#define ANKI_LOGI(x) ANKI_LOGGER_MESSAGE(Logger::LMT_NORMAL, x)
+#define ANKI_LOGI(...) ANKI_LOGGER_MESSAGE(Logger::LMT_NORMAL, __VA_ARGS__)
 
 
-#define ANKI_LOGW(x) ANKI_LOGGER_MESSAGE(Logger::LMT_WARNING, x)
+#define ANKI_LOGW(...) ANKI_LOGGER_MESSAGE(Logger::LMT_WARNING, __VA_ARGS__)
 
 
-#define ANKI_LOGE(x) ANKI_LOGGER_MESSAGE(Logger::LMT_ERROR, x)
+#define ANKI_LOGE(...) ANKI_LOGGER_MESSAGE(Logger::LMT_ERROR, __VA_ARGS__)
 
 
 #endif
 #endif

+ 13 - 0
include/anki/renderer/Is.h

@@ -91,10 +91,17 @@ private:
 	Vao quadVao; ///< This VAO is used everywhere except material stage
 	Vao quadVao; ///< This VAO is used everywhere except material stage
 	/// @}
 	/// @}
 
 
+	/// @name Limits
+	/// @{
 	U16 maxPointLights;
 	U16 maxPointLights;
 	U8 maxSpotLights;
 	U8 maxSpotLights;
 	U8 maxSpotTexLights;
 	U8 maxSpotTexLights;
 
 
+	U8 maxPointLightsPerTile;
+	U8 maxSpotLightsPerTile;
+	U8 maxSpotTexLightsPerTile;
+	/// @}
+
 	/// Called by init
 	/// Called by init
 	void initInternal(const RendererInitializer& initializer);
 	void initInternal(const RendererInitializer& initializer);
 
 
@@ -106,6 +113,12 @@ private:
 
 
 	/// Calculate the size of the lights UBO
 	/// Calculate the size of the lights UBO
 	PtrSize calcLightsUboSize() const;
 	PtrSize calcLightsUboSize() const;
+
+	/// Calculate the size of the tiles UBO
+	PtrSize calcTileSize() const;
+
+	/// Calculate the size of the tiles UBO
+	PtrSize calcTilesUboSize() const;
 };
 };
 
 
 } // end namespace anki
 } // end namespace anki

+ 3 - 0
include/anki/renderer/Renderer.h

@@ -49,6 +49,9 @@ struct RendererInitializer
 		U32 maxPointLights = 512 - 16;
 		U32 maxPointLights = 512 - 16;
 		U32 maxSpotLights = 8;
 		U32 maxSpotLights = 8;
 		U32 maxSpotTexLights = 4;
 		U32 maxSpotTexLights = 4;
+		U32 maxPointLightsPerTile = 48;
+		U32 maxSpotLightsPerTile = 4;
+		U32 maxSpotTexLightsPerTile = 4;
 	} is;
 	} is;
 
 
 	// Pps
 	// Pps

+ 4 - 8
src/core/App.cpp

@@ -92,10 +92,6 @@ void App::init(int argc, char* argv[])
 	signal(SIGBUS, handler);
 	signal(SIGBUS, handler);
 	signal(SIGFPE, handler);
 	signal(SIGFPE, handler);
 
 
-	// send output to handleMessageHanlderMsgs
-	ANKI_CONNECT(&LoggerSingleton::get(), messageRecieved, 
-		this, handleLoggerMessages);
-
 	parseCommandLineArgs(argc, argv);
 	parseCommandLineArgs(argc, argv);
 	printAppInfo();
 	printAppInfo();
 	initDirs();
 	initDirs();
@@ -110,7 +106,7 @@ void App::initDirs()
 	settingsPath = std::string(getenv("HOME")) + "/.anki";
 	settingsPath = std::string(getenv("HOME")) + "/.anki";
 	if(!directoryExists(settingsPath.c_str()))
 	if(!directoryExists(settingsPath.c_str()))
 	{
 	{
-		ANKI_LOGI("Creating settings dir: " << settingsPath);
+		ANKI_LOGI("Creating settings dir: %s", settingsPath.c_str());
 		createDirectory(settingsPath.c_str());
 		createDirectory(settingsPath.c_str());
 	}
 	}
 
 
@@ -118,11 +114,11 @@ void App::initDirs()
 	cachePath = settingsPath + "/cache";
 	cachePath = settingsPath + "/cache";
 	if(directoryExists(cachePath.c_str()))
 	if(directoryExists(cachePath.c_str()))
 	{
 	{
-		ANKI_LOGI("Deleting dir: " << cachePath);
+		ANKI_LOGI("Deleting dir: %s", cachePath.c_str());
 		removeDirectory(cachePath.c_str());
 		removeDirectory(cachePath.c_str());
 	}
 	}
 
 
-	ANKI_LOGI("Creating cache dir: " << cachePath);
+	ANKI_LOGI("Creating cache dir: %s", cachePath.c_str());
 	createDirectory(cachePath.c_str());
 	createDirectory(cachePath.c_str());
 
 
 	// Data
 	// Data
@@ -160,7 +156,7 @@ void App::printAppInfo()
 
 
 	msg << " build date " __DATE__ ", " << "rev " << ANKI_REVISION;
 	msg << " build date " __DATE__ ", " << "rev " << ANKI_REVISION;
 
 
-	ANKI_LOGI(msg.str());
+	ANKI_LOGI(msg.str().c_str());
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 4 - 4
src/core/Async.cpp

@@ -42,7 +42,7 @@ void Async::assignNewJobInternal(AsyncJob* job)
 	ANKI_ASSERT(started == true);
 	ANKI_ASSERT(started == true);
 
 
 #if DEBUG_ASYNC
 #if DEBUG_ASYNC
-	ANKI_LOGI("Assigning new job: " << job);
+	ANKI_LOGI("Assigning new job: %p", (void*)job);
 #endif
 #endif
 	pendingJobsMtx.lock();
 	pendingJobsMtx.lock();
 	pendingJobs.push_back(job);
 	pendingJobs.push_back(job);
@@ -88,10 +88,10 @@ void Async::workingFunc()
 		}
 		}
 		catch(const std::exception& e)
 		catch(const std::exception& e)
 		{
 		{
-			ANKI_LOGE("Job failed: " << e.what());
+			ANKI_LOGE("Job failed: %s", e.what());
 		}
 		}
 #if DEBUG_ASYNC
 #if DEBUG_ASYNC
-		ANKI_LOGI("Job finished: " << job);
+		ANKI_LOGI("Job finished: %p", (void*)job);
 #endif
 #endif
 
 
 		// Put back the response
 		// Put back the response
@@ -124,7 +124,7 @@ void Async::cleanupFinishedJobs(F32 maxTime)
 
 
 		AsyncJob* job = finishedJobs.front();
 		AsyncJob* job = finishedJobs.front();
 #if DEBUG_ASYNC
 #if DEBUG_ASYNC
-		ANKI_LOGI("Executing post for job: " << job);
+		ANKI_LOGI("Executing post for job: %p", (void*)job);
 #endif
 #endif
 		job->post();
 		job->post();
 
 

+ 79 - 1
src/core/Logger.cpp

@@ -1,8 +1,18 @@
 #include "anki/core/Logger.h"
 #include "anki/core/Logger.h"
 #include <cstring>
 #include <cstring>
+#include <cstdarg>
+#if ANKI_OS == ANKI_OS_ANDROID
+#	include <android/log.h>
+#endif
 
 
 namespace anki {
 namespace anki {
 
 
+//==============================================================================
+Logger::Logger()
+{
+	ANKI_CONNECT(this, messageRecieved, this, defaultSystemMessageHandler);
+}
+
 //==============================================================================
 //==============================================================================
 void Logger::write(const char* file, int line, const char* func,
 void Logger::write(const char* file, int line, const char* func,
 	LoggerMessageType type, const char* msg)
 	LoggerMessageType type, const char* msg)
@@ -15,4 +25,72 @@ void Logger::write(const char* file, int line, const char* func,
 	mutex.unlock();
 	mutex.unlock();
 }
 }
 
 
-} // end namespace
+//==============================================================================
+void Logger::writeFormated(const char* file, int line, const char* func,
+	LoggerMessageType type, const char* fmt, ...)
+{
+	char buffer[1024];
+	va_list args;
+
+	va_start(args, fmt);
+	vsnprintf(buffer, sizeof(buffer), fmt, args);
+	write(file, line, func, type, buffer);
+	va_end(args);
+}
+
+//==============================================================================
+void Logger::defaultSystemMessageHandler(const Info& info)
+{
+#if ANKI_OS == ANKI_OS_LINUX
+	std::ostream* out = NULL;
+	const char* x = NULL;
+	const char* terminalColor = nullptr;
+
+	switch(info.type)
+	{
+	case Logger::LMT_NORMAL:
+		out = &std::cout;
+		x = "Info";
+		terminalColor = "\033[0;32m";
+		break;
+	case Logger::LMT_ERROR:
+		out = &std::cerr;
+		x = "Error";
+		terminalColor = "\033[0;31m";
+		break;
+	case Logger::LMT_WARNING:
+		out = &std::cerr;
+		x = "Warn";
+		terminalColor = "\033[0;33m";
+		break;
+	}
+
+	(*out) << terminalColor << "(" << info.file << ":" << info.line << " "
+		<< info.func << ") " << x << ": " << info.msg << "\033[0m" << std::endl;
+#elif ANKI_OS == ANKI_OS_ANDROID
+	U32 andMsgType = ANDROID_LOG_INFO;
+
+	switch(info.type)
+	{
+	case Logger::LMT_NORMAL:
+		andMsgType = ANDROID_LOG_INFO;
+		break;
+	case Logger::LMT_ERROR:
+		andMsgType = ANDROID_LOG_ERROR;
+		break;
+	case Logger::LMT_WARNING:
+		andMsgType = ANDROID_LOG_WARN;
+		break;
+	}
+
+	std::stringstream ss;
+
+	__android_log_print(andMsgType, "AnKi", "(%s:%d %s) %s", info.file,
+		info.line, info.func, info.msg);
+#else
+	std::cout << "(" << info.file << ":" << info.line << " "
+		<< info.func << ") " << x << ": " << info.msg << std::endl;
+#endif
+}
+
+} // end namespace anki

+ 3 - 6
src/gl/GlState.cpp

@@ -61,16 +61,13 @@ static void oglMessagesCallback(GLenum source,
 	switch(severity)
 	switch(severity)
 	{
 	{
 	case GL_DEBUG_SEVERITY_LOW:
 	case GL_DEBUG_SEVERITY_LOW:
-		ANKI_LOGI("GL: " << sourced->str 
-			<< ", " << typed->str << ": " << message);
+		ANKI_LOGI("GL: %s, %s: %s", sourced->str, typed->str, message);
 		break;
 		break;
 	case GL_DEBUG_SEVERITY_MEDIUM:
 	case GL_DEBUG_SEVERITY_MEDIUM:
-		ANKI_LOGW("GL: " << sourced->str 
-			<< ", " << typed->str << ": " << message);
+		ANKI_LOGW("GL: %s, %s: %s", sourced->str, typed->str, message);
 		break;
 		break;
 	case GL_DEBUG_SEVERITY_HIGH:
 	case GL_DEBUG_SEVERITY_HIGH:
-		ANKI_LOGE("GL: " << sourced->str 
-			<< ", " << typed->str << ": " << message);
+		ANKI_LOGE("GL: %s, %s: %s", sourced->str, typed->str, message);
 		break;
 		break;
 	}
 	}
 }
 }

+ 1 - 1
src/gl/ShaderProgram.cpp

@@ -843,7 +843,7 @@ void ShaderProgram::initUniformBlocks()
 		if(isRowMajor)
 		if(isRowMajor)
 		{
 		{
 			ANKI_LOGW("The engine is designed to work with column major "
 			ANKI_LOGW("The engine is designed to work with column major "
-				"matrices: " << uni.name);
+				"matrices: %s", uni.name.c_str());
 		}
 		}
 	}
 	}
 }
 }

+ 102 - 52
src/renderer/Is.cpp

@@ -10,13 +10,6 @@ namespace anki {
 //==============================================================================
 //==============================================================================
 // Consts
 // Consts
 
 
-static const U MAX_POINT_LIGHTS_PER_TILE = 
-	ANKI_RENDERER_MAX_POINT_LIGHTS_PER_TILE;
-static const U MAX_SPOT_LIGHTS_PER_TILE = 
-	ANKI_RENDERER_MAX_SPOT_LIGHTS_PER_TILE;
-static const U MAX_SPOT_TEX_LIGHTS_PER_TILE = 
-	ANKI_RENDERER_MAX_SPOT_TEX_LIGHTS_PER_TILE;
-
 static const U TILES_X_COUNT = ANKI_RENDERER_TILES_X_COUNT;
 static const U TILES_X_COUNT = ANKI_RENDERER_TILES_X_COUNT;
 static const U TILES_Y_COUNT = ANKI_RENDERER_TILES_Y_COUNT;
 static const U TILES_Y_COUNT = ANKI_RENDERER_TILES_Y_COUNT;
 static const U TILES_COUNT = TILES_X_COUNT * TILES_Y_COUNT;
 static const U TILES_COUNT = TILES_X_COUNT * TILES_Y_COUNT;
@@ -50,19 +43,6 @@ void clamp(T& in, Y limit)
 
 
 namespace shader {
 namespace shader {
 
 
-struct Tile
-{
-	Array<U32, 4> lightsCount; 
-	Array<U32, MAX_POINT_LIGHTS_PER_TILE> pointLightIndices;
-	Array<U32, MAX_SPOT_LIGHTS_PER_TILE> spotLightIndices;
-	Array<U32, MAX_SPOT_TEX_LIGHTS_PER_TILE> spotTexLightIndices;
-};
-
-struct Tiles
-{
-	Array<Array<Tile, TILES_X_COUNT>, TILES_Y_COUNT> tiles;
-};
-
 struct Light
 struct Light
 {
 {
 	Vec4 posRadius;
 	Vec4 posRadius;
@@ -111,7 +91,7 @@ struct WriteLightsJob: ThreadJob
 	shader::SpotLight* spotLights = nullptr;
 	shader::SpotLight* spotLights = nullptr;
 	shader::SpotTexLight* spotTexLights = nullptr;
 	shader::SpotTexLight* spotTexLights = nullptr;
 
 
-	shader::Tiles* tiles = nullptr;
+	U8* tileBuffer = nullptr;
 
 
 	VisibilityTestResults::Container::const_iterator lightsBegin;
 	VisibilityTestResults::Container::const_iterator lightsBegin;
 	VisibilityTestResults::Container::const_iterator lightsEnd;
 	VisibilityTestResults::Container::const_iterator lightsEnd;
@@ -130,7 +110,7 @@ struct WriteLightsJob: ThreadJob
 	Tiler* tiler = nullptr;
 	Tiler* tiler = nullptr;
 	Is* is = nullptr;
 	Is* is = nullptr;
 
 
-	/// Bin ligths on CPU path
+	/// Bin lights on CPU path
 	Bool binLights = true;
 	Bool binLights = true;
 
 
 	void operator()(U threadId, U threadsCount)
 	void operator()(U threadId, U threadsCount)
@@ -316,9 +296,9 @@ struct WriteLightsJob: ThreadJob
 
 
 			U tilePos = (*tilePointLightsCount)[y][x].fetch_add(1);
 			U tilePos = (*tilePointLightsCount)[y][x].fetch_add(1);
 
 
-			if(tilePos < MAX_POINT_LIGHTS_PER_TILE)
+			if(tilePos < is->maxPointLightsPerTile)
 			{
 			{
-				tiles->tiles[y][x].pointLightIndices[tilePos] = pos;
+				writeIndexToTileBuffer(0, pos, tilePos, x, y);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -346,22 +326,58 @@ struct WriteLightsJob: ThreadJob
 			{
 			{
 				U tilePos = (*tileSpotTexLightsCount)[y][x].fetch_add(1);
 				U tilePos = (*tileSpotTexLightsCount)[y][x].fetch_add(1);
 
 
-				if(tilePos < MAX_SPOT_TEX_LIGHTS_PER_TILE)
+				if(tilePos < is->maxSpotTexLightsPerTile)
 				{
 				{
-					tiles->tiles[y][x].spotTexLightIndices[tilePos] = pos;
+					writeIndexToTileBuffer(2, pos, tilePos, x, y);
 				}
 				}
 			}
 			}
 			else
 			else
 			{
 			{
 				U tilePos = (*tileSpotLightsCount)[y][x].fetch_add(1);
 				U tilePos = (*tileSpotLightsCount)[y][x].fetch_add(1);
 
 
-				if(tilePos < MAX_SPOT_LIGHTS_PER_TILE)
+				if(tilePos < is->maxSpotLightsPerTile)
 				{
 				{
-					tiles->tiles[y][x].spotLightIndices[tilePos] = pos;
+					writeIndexToTileBuffer(1, pos, tilePos, x, y);
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
+
+	/// XXX
+	void writeIndexToTileBuffer(
+		U lightType, U lightIndex, U i, U tileX, U tileY)
+	{
+		const PtrSize tileSize = is->calcTileSize();
+		PtrSize offset;
+
+		// Calc the start of the tile
+		offset = (tileY * TILES_X_COUNT + tileX) * tileSize;
+
+		// Skip the lightsCount header
+		offset += sizeof(Vec4);
+
+		// Move to the correct light section
+		switch(lightType)
+		{
+		case 0:
+			break;
+		case 1:
+			offset += sizeof(U32) * is->maxPointLightsPerTile;
+			break;
+		case 2:
+			offset += sizeof(U32) * is->maxPointLightsPerTile
+				+ sizeof(U32) * is->maxSpotLightsPerTile;
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
+
+		// Move to the array offset
+		offset += sizeof(U32) * i;
+
+		// Write the lightIndex
+		*((U32*)(tileBuffer + offset)) = lightIndex;
+	}
 };
 };
 
 
 //==============================================================================
 //==============================================================================
@@ -399,6 +415,18 @@ void Is::initInternal(const RendererInitializer& initializer)
 		throw ANKI_EXCEPTION("Incorrect number of max lights");
 		throw ANKI_EXCEPTION("Incorrect number of max lights");
 	}
 	}
 
 
+	maxPointLightsPerTile = initializer.is.maxPointLightsPerTile;
+	maxSpotLightsPerTile = initializer.is.maxSpotLightsPerTile;
+	maxSpotTexLightsPerTile = initializer.is.maxSpotTexLightsPerTile;
+
+	if(maxPointLightsPerTile < 1 || maxSpotLightsPerTile < 1 
+		|| maxSpotTexLightsPerTile < 1
+		|| maxPointLightsPerTile % 4 != 0 || maxSpotLightsPerTile % 4 != 0
+		|| maxSpotTexLightsPerTile % 4 != 0)
+	{
+		throw ANKI_EXCEPTION("Incorrect number of max lights");
+	}
+
 	//
 	//
 	// Init the passes
 	// Init the passes
 	//
 	//
@@ -414,12 +442,12 @@ void Is::initInternal(const RendererInitializer& initializer)
 		<< "#define TILES_COUNT " << TILES_COUNT << "\n"
 		<< "#define TILES_COUNT " << TILES_COUNT << "\n"
 		<< "#define RENDERER_WIDTH " << r->getWidth() << "\n"
 		<< "#define RENDERER_WIDTH " << r->getWidth() << "\n"
 		<< "#define RENDERER_HEIGHT " << r->getHeight() << "\n"
 		<< "#define RENDERER_HEIGHT " << r->getHeight() << "\n"
-		<< "#define MAX_POINT_LIGHTS_PER_TILE " << MAX_POINT_LIGHTS_PER_TILE
+		<< "#define MAX_POINT_LIGHTS_PER_TILE " << (U32)maxPointLightsPerTile
 		<< "\n"
 		<< "\n"
-		<< "#define MAX_SPOT_LIGHTS_PER_TILE " << MAX_SPOT_LIGHTS_PER_TILE
+		<< "#define MAX_SPOT_LIGHTS_PER_TILE " << (U32)maxSpotLightsPerTile
 		<< "\n"
 		<< "\n"
 		<< "#define MAX_SPOT_TEX_LIGHTS_PER_TILE " 
 		<< "#define MAX_SPOT_TEX_LIGHTS_PER_TILE " 
-		<< MAX_SPOT_TEX_LIGHTS_PER_TILE << "\n"
+		<< (U32)maxSpotTexLightsPerTile << "\n"
 		<< "#define MAX_POINT_LIGHTS " << (U32)maxPointLights << "\n"
 		<< "#define MAX_POINT_LIGHTS " << (U32)maxPointLights << "\n"
 		<< "#define MAX_SPOT_LIGHTS " << (U32)maxSpotLights << "\n"
 		<< "#define MAX_SPOT_LIGHTS " << (U32)maxSpotLights << "\n"
 		<< "#define MAX_SPOT_TEX_LIGHTS " << (U32)maxSpotTexLights << "\n"
 		<< "#define MAX_SPOT_TEX_LIGHTS " << (U32)maxSpotTexLights << "\n"
@@ -495,12 +523,12 @@ void Is::initInternal(const RendererInitializer& initializer)
 	// tiles BO
 	// tiles BO
 	tilesBuffer.create(
 	tilesBuffer.create(
 		GL_UNIFORM_BUFFER, 
 		GL_UNIFORM_BUFFER, 
-		sizeof(shader::Tiles), 
+		calcTilesUboSize(), 
 		nullptr, 
 		nullptr, 
 		GL_DYNAMIC_DRAW);
 		GL_DYNAMIC_DRAW);
 
 
-	ANKI_LOGI("Creating BOs: lights: " << calcLightsUboSize() << "B tiles: "
-		<< sizeof(shader::Tiles) << "B");
+	ANKI_LOGI("Creating BOs: lights: %uB, tiles: %uB", calcLightsUboSize(), 
+		calcTilesUboSize());
 
 
 	// Sanity checks
 	// Sanity checks
 	const ShaderProgramUniformBlock* ublock;
 	const ShaderProgramUniformBlock* ublock;
@@ -565,7 +593,7 @@ void Is::initInternal(const RendererInitializer& initializer)
 
 
 	ublock = &lightPassProg->findUniformBlock("tilesBlock");
 	ublock = &lightPassProg->findUniformBlock("tilesBlock");
 	ublock->setBinding(TILES_BLOCK_BINDING);
 	ublock->setBinding(TILES_BLOCK_BINDING);
-	if(ublock->getSize() != sizeof(shader::Tiles)
+	if(ublock->getSize() != calcTilesUboSize()
 		|| ublock->getBinding() != TILES_BLOCK_BINDING)
 		|| ublock->getBinding() != TILES_BLOCK_BINDING)
 	{
 	{
 		throw ANKI_EXCEPTION("Problem with the tilesBlock");
 		throw ANKI_EXCEPTION("Problem with the tilesBlock");
@@ -667,7 +695,9 @@ void Is::lightPass()
 
 
 	U8 clientBuffer[32 * 1024]; // Aproximate size
 	U8 clientBuffer[32 * 1024]; // Aproximate size
 	ANKI_ASSERT(sizeof(clientBuffer) >= calcLightsUboSize());
 	ANKI_ASSERT(sizeof(clientBuffer) >= calcLightsUboSize());
-	shader::Tiles clientTiles;
+
+	U8 tilesClientBuffer[64 * 1024]; // Aproximate size
+	ANKI_ASSERT(sizeof(tilesClientBuffer) >= calcTilesUboSize());
 
 
 	std::atomic<U32> pointLightsAtomicCount(0);
 	std::atomic<U32> pointLightsAtomicCount(0);
 	std::atomic<U32> spotLightsAtomicCount(0);
 	std::atomic<U32> spotLightsAtomicCount(0);
@@ -701,7 +731,7 @@ void Is::lightPass()
 		job.spotTexLights = 
 		job.spotTexLights = 
 			(shader::SpotTexLight*)(&clientBuffer[0] + spotTexLightsOffset);
 			(shader::SpotTexLight*)(&clientBuffer[0] + spotTexLightsOffset);
 
 
-		job.tiles = &clientTiles;
+		job.tileBuffer = &tilesClientBuffer[0];
 
 
 		job.lightsBegin = vi.getLightsBegin();
 		job.lightsBegin = vi.getLightsBegin();
 		job.lightsEnd = vi.getLightsEnd();
 		job.lightsEnd = vi.getLightsEnd();
@@ -731,27 +761,29 @@ void Is::lightPass()
 	{
 	{
 		for(U x = 0; x < TILES_X_COUNT; x++)
 		for(U x = 0; x < TILES_X_COUNT; x++)
 		{
 		{
-			clientTiles.tiles[y][x].lightsCount[0] = 
-				tilePointLightsCount[y][x].load();
-			clamp(clientTiles.tiles[y][x].lightsCount[0], 
-				MAX_POINT_LIGHTS_PER_TILE);
-
-			clientTiles.tiles[y][x].lightsCount[2] = 
-				tileSpotLightsCount[y][x].load();
-			clamp(clientTiles.tiles[y][x].lightsCount[2], 
-				MAX_SPOT_LIGHTS_PER_TILE);
-
-			clientTiles.tiles[y][x].lightsCount[3] = 
-				tileSpotTexLightsCount[y][x].load();
-			clamp(clientTiles.tiles[y][x].lightsCount[3], 
-				MAX_SPOT_TEX_LIGHTS_PER_TILE);
+			const PtrSize tileSize = calcTileSize();
+			UVec4* vec;
+
+			vec = (UVec4*)(
+				&tilesClientBuffer[0] + (y * TILES_X_COUNT + x) * tileSize);
+
+			vec->x() = tilePointLightsCount[y][x].load();
+			clamp(vec->x(), maxPointLightsPerTile);
+
+			vec->y() = 0;
+
+			vec->z() = tileSpotLightsCount[y][x].load();
+			clamp(vec->z(), maxSpotLightsPerTile);
+
+			vec->w() = tileSpotTexLightsCount[y][x].load();
+			clamp(vec->w(), maxSpotTexLightsPerTile);
 		}
 		}
 	}
 	}
 
 
 	// Write BOs
 	// Write BOs
 	lightsUbo.write(
 	lightsUbo.write(
 		&clientBuffer[0], 0, spotTexLightsOffset + spotTexLightsSize);
 		&clientBuffer[0], 0, spotTexLightsOffset + spotTexLightsSize);
-	tilesBuffer.write(&clientTiles);
+	tilesBuffer.write(&tilesClientBuffer[0]);
 
 
 	//
 	//
 	// Reject occluded lights. This operation issues a compute job to reject 
 	// Reject occluded lights. This operation issues a compute job to reject 
@@ -906,4 +938,22 @@ PtrSize Is::calcLightsUboSize() const
 	return size;
 	return size;
 }
 }
 
 
+//==============================================================================
+PtrSize Is::calcTileSize() const
+{
+	PtrSize size =
+		sizeof(Vec4) // lightsCount
+		+ maxPointLightsPerTile * sizeof(U32) // pointLightIndices
+		+ maxSpotLightsPerTile * sizeof(U32) // spotLightIndices
+		+ maxSpotTexLightsPerTile * sizeof(U32); // spotTexLightIndices
+
+	return size;
+}
+
+//==============================================================================
+PtrSize Is::calcTilesUboSize() const
+{
+	return calcTileSize() * TILES_COUNT;
+}
+
 } // end namespace anki
 } // end namespace anki

+ 3 - 3
src/renderer/MainRenderer.cpp

@@ -47,9 +47,9 @@ void MainRenderer::initGl()
 	glGetError();
 	glGetError();
 
 
 	// print GL info
 	// print GL info
-	ANKI_LOGI("OpenGL info: OGL "
-		<< reinterpret_cast<const char*>(glGetString(GL_VERSION))
-		<< ", GLSL " << reinterpret_cast<const char*>(
+	ANKI_LOGI("OpenGL info: OGL %s, GLSL %s",
+		reinterpret_cast<const char*>(glGetString(GL_VERSION)),
+		reinterpret_cast<const char*>(
 		glGetString(GL_SHADING_LANGUAGE_VERSION)));
 		glGetString(GL_SHADING_LANGUAGE_VERSION)));
 
 
 	// get max texture units
 	// get max texture units

+ 2 - 2
src/scene/Renderable.cpp

@@ -64,8 +64,8 @@ RenderableVariable::RenderableVariable(
 	// Sanity checks
 	// Sanity checks
 	if(!mvar->hasValues() && buildinId == BMV_NO_BUILDIN)
 	if(!mvar->hasValues() && buildinId == BMV_NO_BUILDIN)
 	{
 	{
-		ANKI_LOGW("Material variable no buildin and not initialized: "
-			<< name);
+		ANKI_LOGW("Material variable no buildin and not initialized: %s",
+			name.c_str());
 	}
 	}
 }
 }
 
 

+ 1 - 1
src/script/LuaBinder.cpp

@@ -53,7 +53,7 @@ void pushCFunctionStatic(lua_State* l, const char* className,
 static int luaPanic(lua_State* l)
 static int luaPanic(lua_State* l)
 {
 {
 	std::string err(lua_tostring(l, -1));
 	std::string err(lua_tostring(l, -1));
-	ANKI_LOGE("Lua panic attack: " << err);
+	ANKI_LOGE("Lua panic attack: %s", err.c_str());
 	abort();
 	abort();
 }
 }
 
 

+ 2 - 1
testapp/Main.cpp

@@ -572,6 +572,7 @@ void initSubsystems(int argc, char* argv[])
 #if ANKI_GL == ANKI_GL_ES
 #if ANKI_GL == ANKI_GL_ES
 	initializer.samples = 1;
 	initializer.samples = 1;
 	initializer.pps.enabled = false;
 	initializer.pps.enabled = false;
+	initializer.is.maxPointLights = 64;
 #endif
 #endif
 
 
 	MainRendererSingleton::get().init(initializer);
 	MainRendererSingleton::get().init(initializer);
@@ -601,7 +602,7 @@ int main(int argc, char* argv[])
 	}
 	}
 	catch(std::exception& e)
 	catch(std::exception& e)
 	{
 	{
-		ANKI_LOGE("Aborting: " << e.what());
+		ANKI_LOGE("Aborting: %s", e.what());
 		exitCode = 1;
 		exitCode = 1;
 	}
 	}
 	ANKI_LOGI("Bye!!");
 	ANKI_LOGI("Bye!!");