Panagiotis Christopoulos Charitos 13 years ago
parent
commit
60b88f0db2

+ 51 - 44
include/anki/gl/Texture.h

@@ -4,8 +4,9 @@
 #include "anki/util/Assert.h"
 #include "anki/util/Singleton.h"
 #include "anki/gl/Ogl.h"
-#include <cstdlib>
 #include "anki/util/Vector.h"
+#include "anki/util/StdTypes.h"
+#include <cstdlib>
 #include <limits>
 #include <thread>
 
@@ -24,34 +25,34 @@ public:
 
 	/// @name Accessors
 	/// @{
-	uint32_t getAnisotropyLevel() const
+	U getAnisotropyLevel() const
 	{
 		return anisotropyLevel;
 	}
-	void setAnisotropyLevel(uint32_t x) 
+	void setAnisotropyLevel(U x)
 	{
 		anisotropyLevel = x;
 	}
 
-	bool getMipmappingEnabled() const
+	Bool getMipmappingEnabled() const
 	{
 		return mipmapping;
 	}
-	void setMipmappingEnabled(bool x) 
+	void setMipmappingEnabled(Bool x)
 	{
 		mipmapping = x;
 	}
 
-	bool getCompressionEnabled() const
+	Bool getCompressionEnabled() const
 	{
 		return compression;
 	}
-	void setCompressionEnabled(bool x) 
+	void setCompressionEnabled(Bool x)
 	{
 		compression = x;
 	}
 
-	uint32_t getMaxUnitsCount() const
+	U getMaxUnitsCount() const
 	{
 		return unitsCount;
 	}
@@ -62,13 +63,13 @@ private:
 	/// Hints when creating new textures. The implementation may try to ignore 
 	/// them
 	/// @{
-	uint32_t anisotropyLevel;
-	bool mipmapping;
+	U anisotropyLevel;
+	Bool mipmapping;
 	/// If true the new textures will be compressed if not already
-	bool compression;
+	Bool compression;
 	/// @}
 
-	uint32_t unitsCount;
+	U unitsCount;
 };
 
 /// The global texture manager
@@ -81,11 +82,11 @@ public:
 	TextureUnits();
 
 	/// Alias for glActiveTexture
-	void activateUnit(uint32_t unit);
+	void activateUnit(U unit);
 
 	/// Bind the texture to a unit. It's not sure that it will activate the unit
 	/// @return The texture unit index
-	uint32_t bindTexture(const Texture& tex);
+	U bindTexture(const Texture& tex);
 
 	/// Like bindTexture but ensure that the unit is active
 	void bindTextureAndActivateUnit(const Texture& tex);
@@ -95,7 +96,7 @@ public:
 
 	/// Get the number of the texture unit the @a tex is binded. Returns -1 if
 	/// not binded to any unit
-	int whichUnit(const Texture& tex);
+	I whichUnit(const Texture& tex);
 
 private:
 	/// Texture unit representation
@@ -104,26 +105,25 @@ private:
 		/// Have the GL ID to save memory. -1 if no tex is binded to that unit
 		GLuint tex;
 		
-		/// Born time
-		///
-		/// The bigger the value the latter the unit has been accessed. This 
-		/// practicaly means that if the @a born is low the unit is a canditate
-		/// for replacement 
-		uint64_t born; 
+		/// Born time. The bigger the value the latter the unit has been
+		/// accessed. This practicaly means that if the @a born is low the
+		/// unit is a canditate for replacement
+		U64 born;
 	};
 
 	/// Texture units
 	Vector<Unit> units;
+
 	/// The active texture unit
-	int activeUnit;
+	I activeUnit;
+
 	/// How many times the @a choseUnit has been called. Used to set the 
 	/// Unit::born
-	uint64_t choseUnitTimes; 
+	U64 choseUnitTimes;
 
-	/// Helper method 
-	///
-	/// It returns the texture unit where the @a tex can be binded
-	uint32_t choseUnit(const Texture& tex, bool& allreadyBinded);
+	/// Helper method. It returns the texture unit where the @a tex can be
+	/// binded
+	U choseUnit(const Texture& tex, Bool& allreadyBinded);
 };
 
 /// The global texture units manager. Its per thread
@@ -148,17 +148,17 @@ public:
 	/// Texture initializer struct
 	struct Initializer
 	{
-		uint32_t width = 0;
-		uint32_t height = 0;
-		GLint internalFormat = 0;
-		GLenum format = 0;
-		GLenum type = 0;
+		U width = 0;
+		U height = 0;
+		GLint internalFormat = GL_NONE;
+		GLenum format = GL_NONE;
+		GLenum type = GL_NONE;
 		const void* data = nullptr;
-		bool mipmapping = false;
+		Bool mipmapping = false;
 		TextureFilteringType filteringType = TFT_NEAREST;
-		bool repeat = true;
-		int anisotropyLevel = 0;
-		size_t dataSize = 0; ///< For compressed textures
+		Bool repeat = true;
+		I anisotropyLevel = 0;
+		PtrSize dataSize = 0; ///< For compressed textures
 	};
 
 	/// @name Constructors/Destructor
@@ -200,6 +200,7 @@ public:
 
 	GLenum getTarget() const
 	{
+		ANKI_ASSERT(isCreated());
 		return target;
 	}
 
@@ -209,18 +210,21 @@ public:
 		return type;
 	}
 
-	int getUnit() const
+	I getUnit() const
 	{
+		ANKI_ASSERT(isCreated());
 		return TextureUnitsSingleton::get().whichUnit(*this);
 	}
 
 	GLuint getWidth() const
 	{
+		ANKI_ASSERT(isCreated());
 		return width;
 	}
 
 	GLuint getHeight() const
 	{
+		ANKI_ASSERT(isCreated());
 		return height;
 	}
 	/// @}
@@ -230,7 +234,7 @@ public:
 
 	/// Bind the texture to a unit that the texture unit system will decide
 	/// @return The texture init
-	uint32_t bind() const;
+	U bind() const;
 
 	/// Change the filtering type
 	void setFiltering(TextureFilteringType filterType)
@@ -242,15 +246,18 @@ public:
 	/// Generate new mipmaps
 	void genMipmap();
 
+	/// Read the data from the texture
+	void readPixels(void* data, U level = 0);
+
 private:
 	GLuint glId = 0; ///< Identification for OGL
-	GLuint target = 0; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
-	GLuint internalFormat = 0; ///< GL_COMPRESSED_RED, GL_RGB16 etc
-	GLuint format = 0; ///< GL_RED, GL_RG, GL_RGB etc
-	GLuint type = 0; ///< GL_UNSIGNED_BYTE, GL_BYTE etc
+	GLuint target = GL_NONE; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
+	GLuint internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc
+	GLuint format = GL_NONE; ///< GL_RED, GL_RG, GL_RGB etc
+	GLuint type = GL_NONE; ///< GL_UNSIGNED_BYTE, GL_BYTE etc
 	GLuint width = 0, height = 0;
 
-	bool isCreated() const
+	Bool isCreated() const
 	{
 		return glId != 0;
 	}
@@ -259,6 +266,6 @@ private:
 };
 /// @}
 
-} // end namespace
+} // end namespace anki
 
 #endif

+ 9 - 1
include/anki/gl/Ubo.h

@@ -2,6 +2,7 @@
 #define ANKI_GL_UBO_H
 
 #include "anki/gl/BufferObject.h"
+#include "anki/util/StdTypes.h"
 
 namespace anki {
 
@@ -9,7 +10,14 @@ namespace anki {
 /// @{
 	
 /// Uniform buffer object
-typedef BufferObject Ubo;
+class Ubo: public BufferObject
+{
+public:
+	void create(PtrSize size, void* data)
+	{
+		BufferObject::create(GL_UNIFORM_BUFFER, size, data, GL_DYNAMIC_DRAW);
+	}
+};
 
 /// @}
 

+ 37 - 37
include/anki/renderer/Is.h

@@ -20,6 +20,13 @@ class SpotLight;
 class Is: private RenderingPass
 {
 public:
+	static const U TILES_X_COUNT = 16;
+	static const U TILES_Y_COUNT = 16;
+
+	static const U MAX_LIGHTS_PER_TILE = 128;
+
+	static const U MAX_LIGHTS = 1024;
+
 	Is(Renderer* r);
 
 	~Is();
@@ -33,6 +40,11 @@ public:
 	{
 		return fai;
 	}
+
+	const Texture& getMinMaxFai() const
+	{
+		return minMaxFai;
+	}
 	/// @}
 
 private:
@@ -40,7 +52,8 @@ private:
 	{
 		LST_POINT,
 		LST_SPOT,
-		LST_SPOT_SHADOW
+		LST_SPOT_SHADOW,
+		LST_COUNT
 	};
 
 	/// A screen tile
@@ -55,19 +68,10 @@ private:
 		///       top right
 		Vec2 coords[2]; 
 
-		Vector<PointLight*> plights;
-		Vector<SpotLight*> slights;
-		Vector<SpotLight*> slightsShadow;
-		Ubo lightIndicesUbo;
+		std::array<U32, MAX_LIGHTS_PER_TILE> lightIndices;
+		U lightsCount = 0;
 	};
 
-	static const U TILES_X_COUNT = 16;
-	static const U TILES_Y_COUNT = 16;
-
-	static const U MAX_LIGHTS_PER_TILE = 128;
-
-	static const U MAX_LIGHTS = 1024;
-
 	/// @note The [0][0] is the bottom left tile
 	Tile tiles[TILES_X_COUNT][TILES_Y_COUNT];
 
@@ -75,12 +79,32 @@ private:
 	/// to fill the Tile::depth
 	Texture minMaxFai;
 
+	/// The IS FAI
+	Texture fai;
+
 	/// An FBO to write to the minMaxTex
 	Fbo minMaxTilerFbo;
 
+	/// The IS FBO
+	Fbo fbo;
+
+	/// Contains common data for all shader programs
+	Ubo commonUbo;
+
+	/// Contains the indices of lights per tile
+	Ubo lightIndicesUbo;
+
+	/// Contains info of all the lights
+	Ubo lightsUbo;
+
 	/// Min max shader program
 	ShaderProgramResourcePointer minMaxPassSprog;
 
+	/// Light shaders
+	std::array<ShaderProgramResourcePointer, LST_COUNT> lightSProgs;
+
+	Sm sm;
+
 	/// Project a sphere to a circle
 	static void projectShape(const Mat4& projectionMat, 
 		const Sphere& sphere, Vec2& circleCenter, F32& circleRadius);
@@ -104,31 +128,7 @@ private:
 	/// Do the light culling
 	void tileCulling();
 
-	void initTiles();
-
-	Smo smo;
-	Sm sm;
-	Texture fai;
-	Fbo fbo;
-	BufferObject generalUbo;
-
-	/// Illumination stage ambient pass shader program
-	ShaderProgramResourcePointer ambientPassSProg;
-	/// Illumination stage point light shader program
-	ShaderProgramResourcePointer pointLightSProg;
-	/// Illumination stage spot light w/o shadow shader program
-	ShaderProgramResourcePointer spotLightNoShadowSProg;
-	/// Illumination stage spot light w/ shadow shader program
-	ShaderProgramResourcePointer spotLightShadowSProg;
-
-	/// The ambient pass
-	void ambientPass(const Vec3& color);
-
-	/// The point light pass
-	void pointLightPass(PointLight& plight);
-
-	/// The spot light pass
-	void spotLightPass(SpotLight& slight);
+	void initInternal(const RendererInitializer& initializer);
 };
 
 } // end namespace anki

+ 2 - 1
shaders/Final.glsl

@@ -22,7 +22,8 @@ void main()
 	vec4 diffAndSpec = unpackUnorm4x8(a.x);
 	fFragColor = diffAndSpec.rgb;
 #else
-	fFragColor = texture2D(rasterImage, vTexCoords).rgb;
+	vec2 col = texture2D(rasterImage, vTexCoords).rg;
+	fFragColor = vec3(col.rg, 0.0);
 #endif
 	//fFragColor = texture2D(rasterImage, vTexCoords).rgb;
 }

+ 3 - 2
shaders/LinearDepth.glsl

@@ -5,7 +5,8 @@ float linearizeDepth(in float depth, in float zNear, in float zFar)
 	return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
 }
 
-float readFromTexAndLinearizeDepth(in sampler2D depthMap, in vec2 texCoord, in float zNear, in float zFar)
+float readFromTextureAndLinearizeDepth(in sampler2D depthMap, in vec2 texCoord, 
+	in float zNear, in float zFar)
 {
-	return linearizeDepth(texture2D(depthMap, texCoord).r, zNear, zFar);
+	return linearizeDepth(texture(depthMap, texCoord).r, zNear, zFar);
 }

+ 25 - 18
src/gl/Texture.cpp

@@ -36,10 +36,10 @@ TextureUnits::TextureUnits()
 }
 
 //==============================================================================
-int TextureUnits::whichUnit(const Texture& tex)
+I TextureUnits::whichUnit(const Texture& tex)
 {
 	GLuint glid = tex.getGlId();
-	int i = units.size();
+	I i = units.size();
 
 	do
 	{
@@ -50,21 +50,21 @@ int TextureUnits::whichUnit(const Texture& tex)
 }
 
 //==============================================================================
-void TextureUnits::activateUnit(uint32_t unit)
+void TextureUnits::activateUnit(U unit)
 {
 	ANKI_ASSERT(unit < units.size());
-	if(activeUnit != (int)unit)
+	if(activeUnit != (I)unit)
 	{
-		activeUnit = (int)unit;
+		activeUnit = (I)unit;
 		glActiveTexture(GL_TEXTURE0 + activeUnit);
 	}
 }
 
 //==============================================================================
-uint32_t TextureUnits::choseUnit(const Texture& tex, bool& allreadyBinded)
+U TextureUnits::choseUnit(const Texture& tex, Bool& allreadyBinded)
 {
 	++choseUnitTimes;
-	int myTexUnit = whichUnit(tex);
+	I myTexUnit = whichUnit(tex);
 
 	// Already binded => renew it
 	//
@@ -80,7 +80,7 @@ uint32_t TextureUnits::choseUnit(const Texture& tex, bool& allreadyBinded)
 
 	// Find an empty slot for it
 	//
-	for(uint32_t i = 0; i < units.size(); i++)
+	for(U i = 0; i < units.size(); i++)
 	{
 		if(units[i].tex == 0)
 		{
@@ -92,8 +92,8 @@ uint32_t TextureUnits::choseUnit(const Texture& tex, bool& allreadyBinded)
 
 	// Find the older unit and replace the texture
 	//
-	uint64_t older = 0;
-	for(uint32_t i = 1; i < units.size(); ++i)
+	U64 older = 0;
+	for(U i = 1; i < units.size(); ++i)
 	{
 		if(units[i].born < units[older].born)
 		{
@@ -107,10 +107,10 @@ uint32_t TextureUnits::choseUnit(const Texture& tex, bool& allreadyBinded)
 }
 
 //==============================================================================
-uint32_t TextureUnits::bindTexture(const Texture& tex)
+U TextureUnits::bindTexture(const Texture& tex)
 {
-	bool allreadyBinded;
-	uint32_t unit = choseUnit(tex, allreadyBinded);
+	Bool allreadyBinded;
+	U unit = choseUnit(tex, allreadyBinded);
 
 	if(!allreadyBinded)
 	{
@@ -124,8 +124,8 @@ uint32_t TextureUnits::bindTexture(const Texture& tex)
 //==============================================================================
 void TextureUnits::bindTextureAndActivateUnit(const Texture& tex)
 {
-	bool allreadyBinded;
-	uint32_t unit = choseUnit(tex, allreadyBinded);
+	Bool allreadyBinded;
+	U unit = choseUnit(tex, allreadyBinded);
 
 	activateUnit(unit);
 
@@ -138,7 +138,7 @@ void TextureUnits::bindTextureAndActivateUnit(const Texture& tex)
 //==============================================================================
 void TextureUnits::unbindTexture(const Texture& tex)
 {
-	int unit = whichUnit(tex);
+	I unit = whichUnit(tex);
 	if(unit == -1)
 	{
 		return;
@@ -237,7 +237,7 @@ void Texture::create(const Initializer& init)
 }
 
 //==============================================================================
-uint32_t Texture::bind() const
+U Texture::bind() const
 {
 	return TextureUnitsSingleton::get().bindTexture(*this);
 }
@@ -268,4 +268,11 @@ void Texture::setFilteringNoBind(TextureFilteringType filterType) const
 	}
 }
 
-} // end namespace
+//==============================================================================
+void Texture::readPixels(void* pixels, U level)
+{
+	TextureUnitsSingleton::get().bindTextureAndActivateUnit(*this);
+	glGetTexImage(target, level, format, type, pixels);
+}
+
+} // end namespace anki

+ 31 - 0
src/renderer/Dbg.cpp

@@ -70,6 +70,37 @@ void Dbg::run()
 	{
 		sceneDrawer->draw(sector->getOctree());
 	}
+
+	// XXX Remove these
+	CollisionDebugDrawer cdd(drawer.get());
+	Sphere s(Vec3(90.0, 4.0, 0.0), 2.0);
+	s.accept(cdd);
+
+	Camera& cam = scene.getActiveCamera();
+
+	Vec4 p0(s.getCenter(), 1.0);
+	Vec4 p1(s.getCenter() + Vec3(0.0, 2.0, 0.0), 1.0);
+	p0 = cam.getViewProjectionMatrix() * p0;
+	F32 w = p0.w();
+	p0 /= p0.w();
+	p1 = cam.getViewProjectionMatrix() * p1;
+	F32 p1w = p1.w();
+	p1 /= p1.w();
+
+	Vec4 l = cam.getViewProjectionMatrix() * Vec4(0.0, 0.0, 0.0, 1.0);
+	l /= l.w();
+
+	std::cout << (p1 - p0).getLength() << ", " << l << std::endl;
+
+	drawer->setViewProjectionMatrix(Mat4::getIdentity());
+	drawer->setModelMatrix(Mat4::getIdentity());
+
+	drawer->drawLine(Vec3(p0.x(), p0.y(), 0.0),
+		Vec3(p0.x(), p0.y(), 0.0) + Vec3(2.0 / w, 0.0, 0.0),
+		Vec4(0.0, 1.0, 0.0, 0.0));
+
+	drawer->drawLine(Vec3(p0.x(), p0.y(), 0.0),
+		Vec3(p1.x(), p1.y(), 0.0), Vec4(0.0, 1.0, 1.0, 0.0));
 }
 
 } // end namespace anki

+ 153 - 245
src/renderer/Is.cpp

@@ -10,67 +10,52 @@ namespace anki {
 
 //==============================================================================
 
-struct PointLightUniformBlock
+// Shader struct and block representations
+
+struct ShaderLight
 {
 	Vec4 posAndRadius; ///< xyz: Light pos in eye space. w: The radius
 	Vec4 diffuseColor;
 	Vec4 specularColor;
 };
 
-struct SpotLightUniformBlock: PointLightUniformBlock
+typedef ShaderLight ShaderPointLight;
+
+struct ShaderSpotLight: ShaderLight
 {
 	Mat4 texProjectionMat;
 };
 
-struct GeneralUniformBlock
+struct ShaderPointLights
 {
-	Vec4 nearPlanes;
-	Vec4 limitsOfNearPlane;
-	PointLightUniformBlock light;
+	ShaderPointLight lights[Is::MAX_LIGHTS];
 };
 
-//==============================================================================
-void Is::initTiles()
+struct ShaderSpotLights
 {
-	// FBO
-	Renderer::createFai(TILES_X_COUNT, TILES_Y_COUNT, GL_RGB32F, GL_RGB, 
-		GL_FLOAT, minMaxFai);
-	minMaxTilerFbo.create();
-	minMaxTilerFbo.setColorAttachments({&minMaxFai});
-	if(!minMaxTilerFbo.isComplete())
-	{
-		throw ANKI_EXCEPTION("minMaxTilerFbo creation failed");
-	}
-
-	// Shader program
-	std::string preproc = 
-		"#define TILES_X_COUNT " + std::to_string(TILES_X_COUNT) + "\n"
-		"#define TILES_Y_COUNT " + std::to_string(TILES_Y_COUNT) + "\n";
-	std::string filename = ShaderProgramResource::createSrcCodeToCache(
-		"shaders/IsMinMax.glsl", 
-		preproc.c_str());
-	minMaxPassSprog.load(filename.c_str());
+	ShaderSpotLight lights[Is::MAX_LIGHTS];
+};
 
-	// Tiles
-	F32 tileWidth = 1.0 / TILES_X_COUNT;
-	F32 tileHeight = 1.0 / TILES_Y_COUNT;
+struct ShaderTile
+{
+	U32 lightsCount;
+	U32 lightIndices[Is::MAX_LIGHTS_PER_TILE];
+};
 
-	for(U i = 0; i < TILES_X_COUNT; i++)
-	{
-		for(U j = 0; j < TILES_Y_COUNT; j++)
-		{
-		}
-	}
-}
+struct ShaderTiles
+{
+	ShaderTile tile[Is::TILES_X_COUNT * Is::TILES_X_COUNT];
+};
 
-//==============================================================================
-void Is::minMaxPass()
+struct ShaderCommonUniforms
 {
-}
+	Vec4 nearPlanes;
+	Vec4 limitsOfNearPlane;
+};
 
 //==============================================================================
 Is::Is(Renderer* r_)
-	: RenderingPass(r_), smo(r_), sm(r_)
+	: RenderingPass(r_), sm(r_)
 {}
 
 //==============================================================================
@@ -82,251 +67,174 @@ void Is::init(const RendererInitializer& initializer)
 {
 	try
 	{
-		// Init the passes
-		//
-		smo.init(initializer);
-		sm.init(initializer);
-
-		// Load the programs
-		//
-
-		// Ambient pass
-		ambientPassSProg.load("shaders/IsAp.glsl");
-
-		// point light
-		pointLightSProg.load(ShaderProgramResource::createSrcCodeToCache(
-			"shaders/IsLpGeneric.glsl", "#define POINT_LIGHT 1\n").c_str());
-
-		// spot light no shadow
-		spotLightNoShadowSProg.load(
-			ShaderProgramResource::createSrcCodeToCache(
-			"shaders/IsLpGeneric.glsl", "#define SPOT_LIGHT 1\n").c_str());
-
-		// spot light w/t shadow
-		std::string pps = std::string("#define SPOT_LIGHT 1\n"
-			"#define SHADOW 1\n");
-		if(/*sm.isPcfEnabled()*/ 1) // XXX
-		{
-			pps += "#define PCF 1\n";
-		}
-		spotLightShadowSProg.load(ShaderProgramResource::createSrcCodeToCache(
-			"shaders/IsLpGeneric.glsl", pps.c_str()).c_str());
-
-		// Create FBO
-		//
-		Renderer::createFai(r->getWidth(), r->getHeight(), GL_RGB8,
-			GL_RGB, GL_UNSIGNED_INT, fai);
-		fbo.create();
-		fbo.setColorAttachments({&fai});
-		fbo.setOtherAttachment(GL_DEPTH_STENCIL_ATTACHMENT,
-			r->getMs().getDepthFai());
-
-		if(!fbo.isComplete())
-		{
-			throw ANKI_EXCEPTION("Fbo not complete");
-		}
-		
-		// Create UBOs
-		//
-
-		// General UBO
-		const ShaderProgramUniformBlock& block = 
-			pointLightSProg->findUniformBlock("generalBlock");
-
-		if(block.getSize() != sizeof(GeneralUniformBlock))
-		{
-			throw ANKI_EXCEPTION("Uniform block size is not the expected");
-		}
-
-		generalUbo.create(GL_UNIFORM_BUFFER, sizeof(GeneralUniformBlock),
-			nullptr, GL_DYNAMIC_DRAW);
-
-		generalUbo.setBinding(0);
+		initInternal(initializer);
 	}
 	catch(const std::exception& e)
 	{
-		throw ANKI_EXCEPTION("Failed to create IS stage") << e;
+		throw ANKI_EXCEPTION("Failed to init IS") << e;
 	}
 }
 
 //==============================================================================
-void Is::ambientPass(const Vec3& color)
+void Is::initInternal(const RendererInitializer& initializer)
 {
-	// set the shader
-	ambientPassSProg->bind();
-
-	// set the uniforms
-	ambientPassSProg->findUniformVariable("ambientCol").set(color);
-	ambientPassSProg->findUniformVariable("msFai0").set(
-		r->getMs().getFai0());
-
-	// Draw quad
-	r->drawQuad();
-}
-
-//==============================================================================
-void Is::pointLightPass(PointLight& light)
-{
-	const Camera& cam = r->getScene().getActiveCamera();
-
-	/// XXX write the UBO async before calling SMO
+	//
+	// Init the passes
+	//
+	sm.init(initializer);
+
+	//
+	// Load the programs
+	//
+	std::string pps;
+
+	// point light
+	lightSProgs[LST_POINT].load(ShaderProgramResource::createSrcCodeToCache(
+		"shaders/IsLpGeneric.glsl", "#define POINT_LIGHT 1\n").c_str());
+
+	// spot light no shadow
+	lightSProgs[LST_SPOT].load(
+		ShaderProgramResource::createSrcCodeToCache(
+		"shaders/IsLpGeneric.glsl", "#define SPOT_LIGHT 1\n").c_str());
+
+	// spot light w/t shadow
+	pps = std::string("#define SPOT_LIGHT 1\n"
+		"#define SHADOW 1\n");
+	if(/*sm.isPcfEnabled()*/ 1) // XXX
+	{
+		pps += "#define PCF 1\n";
+	}
+	lightSProgs[LST_SPOT_SHADOW].load(
+		ShaderProgramResource::createSrcCodeToCache(
+		"shaders/IsLpGeneric.glsl", pps.c_str()).c_str());
 
-	// SMO
-	smo.run(light);
-	GlStateSingleton::get().disable(GL_DEPTH_TEST);
+	// Min max
+	pps =
+		"#define TILES_X_COUNT " + std::to_string(TILES_X_COUNT) + "\n"
+		"#define TILES_Y_COUNT " + std::to_string(TILES_Y_COUNT) + "\n"
+		"#define RENDERER_WIDTH " + std::to_string(r->getWidth()) + "\n"
+		"#define RENDERER_HEIGHT " + std::to_string(r->getWidth()) + "\n";
+	std::string filename = ShaderProgramResource::createSrcCodeToCache(
+		"shaders/IsMinMax.glsl",
+		pps.c_str());
+	minMaxPassSprog.load(filename.c_str());
 
-	// shader prog
-	const ShaderProgram& shader = *pointLightSProg; // ensure the const-ness
-	shader.bind();
+	//
+	// Create FBOs
+	//
 
-	shader.findUniformVariable("msFai0").set(r->getMs().getFai0());
-	shader.findUniformVariable("msDepthFai").set(
+	// IS FBO
+	Renderer::createFai(r->getWidth(), r->getHeight(), GL_RGB8,
+		GL_RGB, GL_UNSIGNED_INT, fai);
+	fbo.create();
+	fbo.setColorAttachments({&fai});
+	fbo.setOtherAttachment(GL_DEPTH_STENCIL_ATTACHMENT,
 		r->getMs().getDepthFai());
 
-	GeneralUniformBlock blk;
-	blk.nearPlanes = Vec4(cam.getNear(), 0.0, r->getPlanes().x(),
-		r->getPlanes().y());
-	blk.limitsOfNearPlane = Vec4(r->getLimitsOfNearPlane(),
-		r->getLimitsOfNearPlane2());
-
-	Vec3 pos = light.getWorldTransform().getOrigin().getTransformed(
-		cam.getViewMatrix());
-	blk.light.posAndRadius = Vec4(pos, light.getRadius());
-	blk.light.diffuseColor = light.getDiffuseColor();
-	blk.light.specularColor = light.getSpecularColor();;
-
-	generalUbo.write(&blk, 0, sizeof(GeneralUniformBlock));
+	if(!fbo.isComplete())
+	{
+		throw ANKI_EXCEPTION("Fbo not complete");
+	}
 
-	// render quad
-	r->drawQuad();
-}
+	// min max FBO
+	Renderer::createFai(TILES_X_COUNT, TILES_Y_COUNT, GL_RG32F, GL_RG,
+		GL_FLOAT, minMaxFai);
+	minMaxFai.setFiltering(Texture::TFT_NEAREST);
+	minMaxTilerFbo.create();
+	minMaxTilerFbo.setColorAttachments({&minMaxFai});
+	if(!minMaxTilerFbo.isComplete())
+	{
+		throw ANKI_EXCEPTION("minMaxTilerFbo not complete");
+	}
 
-//==============================================================================
-void Is::spotLightPass(SpotLight& light)
-{
-#if 0
-	const Camera& cam = r->getScene().getActiveCamera();
-	const ShaderProgram* shdr;
-	//bool withShadow = light.getShadowEnabled() && sm.getEnabled();
-	bool withShadow = false;
+	//
+	// Create UBOs
+	//
 
-	// shadow mapping
-	if(withShadow)
-	{
-		/*Vec3 zAxis = light.getWorldTransform().getRotation().getColumn(2);
-			LineSegment seg(light.getWorldTransform().getOrigin(),
-		-zAxis * light.getCamera().getZFar());
+	// Common UBO
+	/*const ShaderProgramUniformBlock& block =
+		lightSProgs[LST_POINT]->findUniformBlock("commonBlock");*/
 
-		const Plane& plane = cam.getWSpaceFrustumPlane(Camera::FP_NEAR);
+	commonUbo.create(sizeof(ShaderCommonUniforms), nullptr);
+	commonUbo.setBinding(0);
 
-		float dist = seg.testPlane(plane);
+	// lights UBO
+	lightsUbo.create(sizeof(ShaderSpotLights), nullptr);
+	commonUbo.setBinding(1);
 
-		sm.run(light, dist);
+	// lightIndices UBO
+	lightIndicesUbo.create(sizeof(ShaderTiles), nullptr);
+	commonUbo.setBinding(2);
 
-		// restore the IS FBO
-		fbo.bind();
+	//
+	// Init tiles
+	//
+	F32 tileWidth = 1.0 / TILES_X_COUNT;
+	F32 tileHeight = 1.0 / TILES_Y_COUNT;
 
-		// and restore blending and depth test
-		GlStateMachineSingleton::get().enable(GL_BLEND, BLEND_ENABLE);
-		glBlendFunc(GL_ONE, GL_ONE);
-		GlStateMachineSingleton::get().enable(GL_DEPTH_TEST, false);
-		GlStateMachineSingleton::get().setViewport(0, 0,
-		r.getWidth(), r.getHeight());*/
-		shdr = spotLightShadowSProg.get();
-	}
-	else
+	for(U i = 0; i < TILES_X_COUNT; i++)
 	{
-		shdr = spotLightNoShadowSProg.get();
+		for(U j = 0; j < TILES_Y_COUNT; j++)
+		{
+		}
 	}
+}
 
-	// stencil optimization
-	smo.run(light);
-	GlStateSingleton::get().enable(GL_DEPTH_TEST, false);
-
-	shdr->bind();
-
-	// the block
-	UniformBlockData data;
-	data.planes = Vec4(r->getPlanes(), 0.0, 0.0);
-	data.limitsOfNearPlane = Vec4(r->getLimitsOfNearPlane(),
-		r->getLimitsOfNearPlane2());
-	data.zNearLightRadius = Vec4(cam.getNear(), light.getDistance(), 0.0, 0.0);
-	Vec3 lightPosEyeSpace = light.getWorldTransform().getOrigin().
-		getTransformed(cam.getViewMatrix());
-	data.lightPos = Vec4(lightPosEyeSpace, 0.0);
-	data.lightDiffuseCol = light.getDiffuseColor();
-	data.lightSpecularCol = light.getSpecularColor();
-
-	// set texture matrix for texture & shadowmap projection
-	// Bias * P_light * V_light * inv(V_cam)
-	static const Mat4 biasMat4(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0,
-		0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
-	data.texProjectionMat = biasMat4 * light.getProjectionMatrix() *
-		Mat4::combineTransformations(light.getViewMatrix(),
-		Mat4(cam.getWorldTransform()));
-
-	ubo.write(&data, 0, sizeof(UniformBlockData));
-
-	// bind the FAIs
-	shdr->findUniformVariable("msFai0").set(r->getMs().getFai0());
-	shdr->findUniformVariable("msDepthFai").set(r->getMs().getDepthFai());
-	shdr->findUniformVariable("lightTex").set(light.getTexture());
-
-	// the shadowmap
-	/*if(withShadow)
-	{
-		shdr->findUniformVariable("shadowMap").set(sm.getShadowMap());
-	}*/
+//==============================================================================
+void Is::projectShape(const Mat4& projectionMat,
+	const Sphere& sphere, Vec2& circleCenter, F32& circleRadius)
+{
 
-	// render quad
-	r->drawQuad();
-#endif
 }
 
 //==============================================================================
-void Is::run()
+void Is::minMaxPass()
 {
-	fbo.bind();
-	GlStateSingleton::get().setViewport(0, 0, r->getWidth(), r->getHeight());
+	// Do the pass
+	//
 	const Camera& cam = r->getScene().getActiveCamera();
 
-	// Ambient pass
-	GlStateSingleton::get().disable(GL_BLEND);
 	GlStateSingleton::get().disable(GL_DEPTH_TEST);
-	glDepthMask(GL_FALSE);
-	ambientPass(r->getScene().getAmbientColor());
-
-#if BLEND_ENABLE
-	GlStateSingleton::get().enable(GL_BLEND);
-	glBlendFunc(GL_ONE, GL_ONE);
-#else
-	GlStateSingleton::get().disable(GL_BLEND);
+
+	minMaxTilerFbo.bind();
+	minMaxPassSprog->bind();
+	GlStateSingleton::get().setViewport(0, 0, TILES_X_COUNT, TILES_Y_COUNT);
+#if 1
+	minMaxPassSprog->findUniformVariable("nearFar").set(
+		Vec2(cam.getNear(), cam.getFar()));
+	minMaxPassSprog->findUniformVariable("depthMap").set(
+		r->getMs().getDepthFai());
 #endif
 
-	GlStateSingleton::get().enable(GL_STENCIL_TEST);
+	r->drawQuad();
+
+	// Update the tiles
+	//
+	F32 pixels[TILES_X_COUNT][TILES_Y_COUNT][2];
 
-	VisibilityInfo& vi =
-		r->getScene().getActiveCamera().getFrustumable()->getVisibilityInfo();
-	for(auto it = vi.getLightsBegin();
-		it != vi.getLightsEnd(); ++it)
+	minMaxFai.readPixels(pixels);
+
+	for(U i = 0; i < TILES_X_COUNT; i++)
 	{
-		Light& light = *(*it);
-		switch(light.getLightType())
+		for(U j = 0; j < TILES_Y_COUNT; j++)
 		{
-		case Light::LT_SPOT:
-			spotLightPass(static_cast<SpotLight&>(light));
-			break;
-		case Light::LT_POINT:
-			pointLightPass(static_cast<PointLight&>(light));
-			break;
-		default:
-			ANKI_ASSERT(0);
-			break;
+			Tile& tile = tiles[i][j];
+			tile.depth = Vec2(pixels[i][j][0], pixels[i][j][1]);
 		}
 	}
+}
 
-	GlStateSingleton::get().disable(GL_STENCIL_TEST);
-	glDepthMask(GL_TRUE);
+//==============================================================================
+void Is::run()
+{
+	/*fbo.bind();
+	GlStateSingleton::get().setViewport(0, 0, r->getWidth(), r->getHeight());
+	const Camera& cam = r->getScene().getActiveCamera();*/
+
+	//minMaxPass();
+
+	fbo.bind();
+	glClear(GL_COLOR_BUFFER_BIT);
 }
 
 } // end namespace anki

+ 2 - 2
testapp/Main.cpp

@@ -257,7 +257,7 @@ void mainLoop()
 
 		// Sleep
 		//
-#if 0
+#if 1
 		timer.stop();
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		{
@@ -289,7 +289,7 @@ void initSubsystems(int argc, char* argv[])
 	// Main renderer
 	RendererInitializer initializer;
 	initializer.ms.ez.enabled = true;
-	initializer.dbg.enabled = false;
+	initializer.dbg.enabled = true;
 	initializer.is.sm.bilinearEnabled = true;
 	initializer.is.sm.enabled = true;
 	initializer.is.sm.pcfEnabled = true;