Browse Source

Adding the skeleton for the software rasterizer.
Support for generating mipmaps for individual surfaces.

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
883b7f072a

+ 2 - 0
include/anki/gr/CommandBuffer.h

@@ -138,6 +138,8 @@ public:
 
 
 	void generateMipmaps(TexturePtr tex);
 	void generateMipmaps(TexturePtr tex);
 
 
+	void generateMipmaps(TexturePtr tex, U surface);
+
 	void copyTextureToTexture(TexturePtr src, U srcSlice, U srcLevel,
 	void copyTextureToTexture(TexturePtr src, U srcSlice, U srcLevel,
 		TexturePtr dest, U destSlice, U destLevel);
 		TexturePtr dest, U destSlice, U destLevel);
 	/// @}
 	/// @}

+ 3 - 3
include/anki/gr/Enums.h

@@ -223,9 +223,9 @@ public:
 	PixelFormat(const PixelFormat&) = default;
 	PixelFormat(const PixelFormat&) = default;
 
 
 	PixelFormat(ComponentFormat cf, TransformFormat tf, Bool srgb = false)
 	PixelFormat(ComponentFormat cf, TransformFormat tf, Bool srgb = false)
-	:	m_components(cf),
-		m_transform(tf),
-		m_srgb(srgb)
+		: m_components(cf)
+		, m_transform(tf)
+		, m_srgb(srgb)
 	{}
 	{}
 
 
 	PixelFormat& operator=(const PixelFormat&) = default;
 	PixelFormat& operator=(const PixelFormat&) = default;

+ 6 - 5
include/anki/gr/gl/TextureImpl.h

@@ -6,6 +6,7 @@
 #pragma once
 #pragma once
 
 
 #include <anki/gr/gl/GlObject.h>
 #include <anki/gr/gl/GlObject.h>
+#include <anki/util/DArray.h>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -23,17 +24,16 @@ public:
 	U32 m_width = 0;
 	U32 m_width = 0;
 	U32 m_height = 0;
 	U32 m_height = 0;
 	U32 m_depth = 0;
 	U32 m_depth = 0;
+	U32 m_surfaceCount = 0;
 	U8 m_mipsCount = 0;
 	U8 m_mipsCount = 0;
 	Bool8 m_compressed = false;
 	Bool8 m_compressed = false;
+	DArray<GLuint> m_texViews; ///< Temp views for gen mips.
 
 
 	TextureImpl(GrManager* manager)
 	TextureImpl(GrManager* manager)
 		: GlObject(manager)
 		: GlObject(manager)
 	{}
 	{}
 
 
-	~TextureImpl()
-	{
-		destroyDeferred(glDeleteTextures);
-	}
+	~TextureImpl();
 
 
 	/// Create the texture storage.
 	/// Create the texture storage.
 	void create(const TextureInitializer& init);
 	void create(const TextureInitializer& init);
@@ -42,7 +42,7 @@ public:
 	void write(U32 mipmap, U32 slice, void* data, PtrSize dataSize);
 	void write(U32 mipmap, U32 slice, void* data, PtrSize dataSize);
 
 
 	/// Generate mipmaps.
 	/// Generate mipmaps.
-	void generateMipmaps();
+	void generateMipmaps(U surface);
 
 
 	/// Copy a single slice from one texture to another.
 	/// Copy a single slice from one texture to another.
 	static void copy(const TextureImpl& src, U srcSlice, U srcLevel,
 	static void copy(const TextureImpl& src, U srcSlice, U srcLevel,
@@ -56,3 +56,4 @@ private:
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki
+

+ 3 - 3
include/anki/math/Functions.h

@@ -124,7 +124,7 @@ template<typename T>
 inline T mod(const T x, const T y)
 inline T mod(const T x, const T y)
 {
 {
 	return x - y * std::floor(x / y);
 	return x - y * std::floor(x / y);
-}       
+}
 
 
 //==============================================================================
 //==============================================================================
 // Other math functions                                                        =
 // Other math functions                                                        =
@@ -132,7 +132,7 @@ inline T mod(const T x, const T y)
 
 
 template<typename T>
 template<typename T>
 inline T abs(const T f)
 inline T abs(const T f)
-{ 
+{
 	return std::fabs(f);
 	return std::fabs(f);
 }
 }
 
 
@@ -222,7 +222,7 @@ static Type cosInterpolate(const Type& from, const Type& to, F32 u)
 ///              from [0.0, 1.0]
 ///              from [0.0, 1.0]
 template<typename Type>
 template<typename Type>
 static Type cubicInterpolate(
 static Type cubicInterpolate(
-	const Type& a, const Type& b, const Type& c, 
+	const Type& a, const Type& b, const Type& c,
 	const Type& d, F32 u)
 	const Type& d, F32 u)
 {
 {
 	F32 u2 = u * u;
 	F32 u2 = u * u;

+ 14 - 4
include/anki/math/Vec4.h

@@ -63,7 +63,7 @@ public:
 
 
 	/// @name Constructors
 	/// @name Constructors
 	/// @{
 	/// @{
-	explicit TVec4()
+	TVec4()
 		: Base()
 		: Base()
 	{}
 	{}
 
 
@@ -71,7 +71,7 @@ public:
 		: Base(b)
 		: Base(b)
 	{}
 	{}
 
 
-	explicit TVec4(const T x_, const T y_, const T z_, const T w_)
+	TVec4(const T x_, const T y_, const T z_, const T w_)
 		: Base(x_, y_, z_, w_)
 		: Base(x_, y_, z_, w_)
 	{}
 	{}
 
 
@@ -87,11 +87,11 @@ public:
 		: Base(simd)
 		: Base(simd)
 	{}
 	{}
 
 
-	explicit TVec4(const TVec2<T>& v, const T z_, const T w_)
+	TVec4(const TVec2<T>& v, const T z_, const T w_)
 		: Base(v.x(), v.y(), z_, w_)
 		: Base(v.x(), v.y(), z_, w_)
 	{}
 	{}
 
 
-	explicit TVec4(const TVec3<T>& v, const T w_)
+	TVec4(const TVec3<T>& v, const T w_)
 		: Base(v.x(), v.y(), v.z(), w_)
 		: Base(v.x(), v.y(), v.z(), w_)
 	{}
 	{}
 	/// @}
 	/// @}
@@ -132,6 +132,16 @@ public:
 			x() * m4(0, 2) + y() * m4(1, 2) + z() * m4(2, 2) + w() * m4(3, 2),
 			x() * m4(0, 2) + y() * m4(1, 2) + z() * m4(2, 2) + w() * m4(3, 2),
 			x() * m4(0, 3) + y() * m4(1, 3) + z() * m4(2, 3) + w() * m4(3, 3));
 			x() * m4(0, 3) + y() * m4(1, 3) + z() * m4(2, 3) + w() * m4(3, 3));
 	}
 	}
+
+	/// Perspective divide. Divide the xyzw of this to the w of this. This
+	/// method will handle some edge cases.
+	TVec4 perspectiveDivide() const
+	{
+		auto invw = T(1) / w(); // This may become (+-)inf
+		invw = (invw > 1e+11) ? 1e+11 : invw; // Clamp
+		invw = (invw < -1e+11) ? -1e+11 : invw; // Clamp
+		return (*this) * invw;
+	}
 	/// @}
 	/// @}
 };
 };
 
 

+ 43 - 0
include/anki/scene/Rasterizer.h

@@ -0,0 +1,43 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/scene/Common.h>
+#include <anki/Math.h>
+#include <anki/collision/Aabb.h>
+
+namespace anki {
+
+/// @addtogroup scene
+/// @{
+
+/// Software rasterizer for visibility tests.
+class Rasterizer
+{
+public:
+	~Rasterizer();
+
+	void init(U width, U height, SceneAllocator<U8> alloc);
+
+	/// Prepare for rastarization.
+	void prepare(const Mat4& mvp);
+
+	/// Rasterize a triangle. It's thread safe. The triangle should be CCW.
+	void rasterizeTriangle(const Vec4& a, const Vec4& b, const Vec4& c);
+
+	/// Do a z-test on a specific collision shape.
+	Bool test(const Aabb& box) const;
+
+private:
+	U32 m_width = 0;
+	U32 m_height = 0;
+	DArray<Atomic<U32>> m_depthBuff;
+	Mat4 m_mvp = Mat4::getIdentity();
+	SceneAllocator<U8> m_alloc;
+};
+/// @}
+
+} // end namespace anki

+ 2 - 2
shaders/ImageReflections.glsl

@@ -147,7 +147,7 @@ void readFromProbes(in vec3 intersection, out vec3 color)
 			// Read!
 			// Read!
 			vec3 c = texture(u_reflectionsTex, vec4(uv, cubemapIndex)).rgb;
 			vec3 c = texture(u_reflectionsTex, vec4(uv, cubemapIndex)).rgb;
 
 
-			// Combine
+			// Combine with previous color
 			float factor = d / R2;
 			float factor = d / R2;
 			color = color * factor + c * (1.0 - factor);
 			color = color * factor + c * (1.0 - factor);
 		}
 		}
@@ -157,7 +157,7 @@ void readFromProbes(in vec3 intersection, out vec3 color)
 //==============================================================================
 //==============================================================================
 vec3 readReflection(in vec3 posVSpace, in vec3 normalVSpace)
 vec3 readReflection(in vec3 posVSpace, in vec3 normalVSpace)
 {
 {
-	vec3 color = vec3(0.0);
+	vec3 color = IMAGE_REFLECTIONS_DEFAULT_COLOR;
 
 
 	// Reflection direction
 	// Reflection direction
 	vec3 eye = normalize(posVSpace);
 	vec3 eye = normalize(posVSpace);

+ 2 - 0
shaders/IsLp.frag.glsl

@@ -32,10 +32,12 @@ layout(location = 0) out vec3 out_color;
 #define IMAGE_REFLECTIONS_PROXY_SS_BINDING 5
 #define IMAGE_REFLECTIONS_PROXY_SS_BINDING 5
 #define IMAGE_REFLECTIONS_PROBE_SS_BINDING 6
 #define IMAGE_REFLECTIONS_PROBE_SS_BINDING 6
 #define IMAGE_REFLECTIONS_TEX_BINDING 6
 #define IMAGE_REFLECTIONS_TEX_BINDING 6
+#define IMAGE_REFLECTIONS_DEFAULT_COLOR vec3(1.0)
 #pragma anki include "shaders/ImageReflections.glsl"
 #pragma anki include "shaders/ImageReflections.glsl"
 #undef IMAGE_REFLECTIONS_SET
 #undef IMAGE_REFLECTIONS_SET
 #undef IMAGE_REFLECTIONS_PROXY_SS_BINDING
 #undef IMAGE_REFLECTIONS_PROXY_SS_BINDING
 #undef IMAGE_REFLECTIONS_PROBE_SS_BINDING
 #undef IMAGE_REFLECTIONS_PROBE_SS_BINDING
+#undef IMAGE_REFLECTIONS_DEFAULT_COLOR
 #endif
 #endif
 
 
 const uint TILE_COUNT = TILES_COUNT_X * TILES_COUNT_Y;
 const uint TILE_COUNT = TILES_COUNT_X * TILES_COUNT_Y;

+ 1 - 1
src/collision/Frustum.cpp

@@ -133,7 +133,7 @@ void Frustum::updateInternal()
 
 
 //==============================================================================
 //==============================================================================
 PerspectiveFrustum::PerspectiveFrustum()
 PerspectiveFrustum::PerspectiveFrustum()
-:	Frustum(Type::PERSPECTIVE)
+	: Frustum(Type::PERSPECTIVE)
 {
 {
 	addShape(&m_hull);
 	addShape(&m_hull);
 	m_hull.initStorage(&m_pointsW[0], m_pointsW.getSize());
 	m_hull.initStorage(&m_pointsW[0], m_pointsW.getSize());

+ 1 - 1
src/core/Config.cpp

@@ -98,7 +98,7 @@ Config::Config()
 	//
 	//
 	// Window
 	// Window
 	//
 	//
-	newOption("glminor", 4);
+	newOption("glminor", 5);
 	newOption("glmajor", 4);
 	newOption("glmajor", 4);
 	newOption("fullscreenDesktopResolution", false);
 	newOption("fullscreenDesktopResolution", false);
 	newOption("debugContext",
 	newOption("debugContext",

+ 25 - 1
src/gr/gl/CommandBuffer.cpp

@@ -440,7 +440,7 @@ public:
 
 
 	Error operator()(GlState&)
 	Error operator()(GlState&)
 	{
 	{
-		m_tex->getImplementation().generateMipmaps();
+		m_tex->getImplementation().generateMipmaps(0);
 		return ErrorCode::NONE;
 		return ErrorCode::NONE;
 	}
 	}
 };
 };
@@ -450,6 +450,30 @@ void CommandBuffer::generateMipmaps(TexturePtr tex)
 	m_impl->pushBackNewCommand<GenMipsCommand>(tex);
 	m_impl->pushBackNewCommand<GenMipsCommand>(tex);
 }
 }
 
 
+//==============================================================================
+class GenMipsCommand1 final: public GlCommand
+{
+public:
+	TexturePtr m_tex;
+	U32 m_surface;
+
+	GenMipsCommand1(const TexturePtr& tex, U surface)
+		: m_tex(tex)
+		, m_surface(surface)
+	{}
+
+	Error operator()(GlState&)
+	{
+		m_tex->getImplementation().generateMipmaps(m_surface);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::generateMipmaps(TexturePtr tex, U surface)
+{
+	m_impl->pushBackNewCommand<GenMipsCommand1>(tex, surface);
+}
+
 //==============================================================================
 //==============================================================================
 CommandBufferInitHints CommandBuffer::computeInitHints() const
 CommandBufferInitHints CommandBuffer::computeInitHints() const
 {
 {

+ 130 - 3
src/gr/gl/TextureImpl.cpp

@@ -7,6 +7,11 @@
 #include <anki/gr/Texture.h>
 #include <anki/gr/Texture.h>
 #include <anki/gr/gl/Error.h>
 #include <anki/gr/gl/Error.h>
 #include <anki/util/Functions.h>
 #include <anki/util/Functions.h>
+#include <anki/gr/GrManager.h>
+#include <anki/gr/gl/GrManagerImpl.h>
+#include <anki/gr/gl/RenderingThread.h>
+#include <anki/gr/CommandBuffer.h>
+#include <anki/gr/gl/CommandBufferImpl.h>
 
 
 namespace anki {
 namespace anki {
 
 
@@ -193,6 +198,69 @@ static void convertTextureInformation(
 // TextureImpl                                                                 =
 // TextureImpl                                                                 =
 //==============================================================================
 //==============================================================================
 
 
+//==============================================================================
+class DeleteTextureCommand final: public GlCommand
+{
+public:
+	GLuint m_tex;
+	DArray<GLuint> m_views;
+	GrAllocator<U8> m_alloc;
+
+	DeleteTextureCommand(GLuint tex, DArray<GLuint>& views,
+		GrAllocator<U8> alloc)
+		: m_tex(tex)
+		, m_views(std::move(views))
+		, m_alloc(alloc)
+	{}
+
+	Error operator()(GlState& state)
+	{
+		// Delete views
+		if(m_views.getSize() > 0)
+		{
+			for(GLuint name : m_views)
+			{
+				if(name != 0)
+				{
+					glDeleteTextures(1, &name);
+				}
+			}
+		}
+		m_views.destroy(m_alloc);
+
+		// Delete texture
+		if(m_tex != 0)
+		{
+			glDeleteTextures(1, &m_tex);
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+TextureImpl::~TextureImpl()
+{
+	GrManager& manager = getManager();
+	RenderingThread& thread = manager.getImplementation().getRenderingThread();
+
+	if(!thread.isServerThread())
+	{
+		CommandBufferPtr commands;
+
+		commands = manager.newInstance<CommandBuffer>();
+		commands->getImplementation().pushBackNewCommand<DeleteTextureCommand>(
+			m_glName, m_texViews, getAllocator());
+		commands->flush();
+	}
+	else
+	{
+		DeleteTextureCommand cmd(m_glName, m_texViews, getAllocator());
+		cmd(thread.getState());
+	}
+
+	m_glName = 0;
+}
+
 //==============================================================================
 //==============================================================================
 void TextureImpl::bind()
 void TextureImpl::bind()
 {
 {
@@ -276,6 +344,28 @@ void TextureImpl::create(const TextureInitializer& init)
 		ANKI_ASSERT(0);
 		ANKI_ASSERT(0);
 	}
 	}
 
 
+	// Surface count
+	switch(m_target)
+	{
+	case GL_TEXTURE_1D:
+	case GL_TEXTURE_2D:
+	case GL_TEXTURE_2D_MULTISAMPLE:
+		m_surfaceCount = 1;
+		break;
+	case GL_TEXTURE_CUBE_MAP:
+		m_surfaceCount = 6;
+		break;
+	case GL_TEXTURE_CUBE_MAP_ARRAY:
+		m_surfaceCount = init.m_depth * 6;
+		break;
+	case GL_TEXTURE_2D_ARRAY:
+	case GL_TEXTURE_3D:
+		m_surfaceCount = init.m_depth;
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+
 	// Set parameters
 	// Set parameters
 	if(init.m_samples == 1)
 	if(init.m_samples == 1)
 	{
 	{
@@ -439,11 +529,48 @@ void TextureImpl::write(U32 mipmap, U32 slice, void* data, PtrSize dataSize)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void TextureImpl::generateMipmaps()
+void TextureImpl::generateMipmaps(U surface)
 {
 {
+	ANKI_ASSERT(surface < m_surfaceCount);
 	ANKI_ASSERT(!m_compressed);
 	ANKI_ASSERT(!m_compressed);
-	bind();
-	glGenerateMipmap(m_target);
+
+	if(m_surfaceCount > 1)
+	{
+		// Create the view array
+		if(m_texViews.getSize() == 0)
+		{
+			m_texViews.create(getAllocator(), m_surfaceCount);
+			memset(&m_texViews[0], 0, m_texViews.getSize() * sizeof(GLuint));
+		}
+
+		// Create the view
+		if(m_texViews[surface] == 0)
+		{
+			glGenTextures(1, &m_texViews[surface]);
+
+			// Get the target
+			GLenum target = GL_NONE;
+			switch(m_target)
+			{
+			case GL_TEXTURE_CUBE_MAP:
+			case GL_TEXTURE_2D_ARRAY:
+			case GL_TEXTURE_CUBE_MAP_ARRAY:
+				target = GL_TEXTURE_2D;
+				break;
+			default:
+				ANKI_ASSERT(0);
+			}
+
+			glTextureView(m_texViews[surface], target, m_glName,
+				m_internalFormat, 0, m_mipsCount, surface, 1);
+		}
+
+		glGenerateTextureMipmap(m_texViews[surface]);
+	}
+	else
+	{
+		glGenerateTextureMipmap(m_glName);
+	}
 }
 }
 
 
 //==============================================================================
 //==============================================================================

+ 6 - 1
src/renderer/Ir.cpp

@@ -97,9 +97,10 @@ Error Ir::init(const ConfigSet& initializer)
 	texinit.m_depth = m_cubemapArrSize;
 	texinit.m_depth = m_cubemapArrSize;
 	texinit.m_type = TextureType::CUBE_ARRAY;
 	texinit.m_type = TextureType::CUBE_ARRAY;
 	texinit.m_format = Is::RT_PIXEL_FORMAT;
 	texinit.m_format = Is::RT_PIXEL_FORMAT;
-	texinit.m_mipmapsCount = 1;
+	texinit.m_mipmapsCount = MAX_U8;
 	texinit.m_samples = 1;
 	texinit.m_samples = 1;
 	texinit.m_sampling.m_minMagFilter = SamplingFilter::LINEAR;
 	texinit.m_sampling.m_minMagFilter = SamplingFilter::LINEAR;
+	texinit.m_sampling.m_mipmapFilter = SamplingFilter::NEAREST;
 
 
 	m_cubemapArr = getGrManager().newInstance<Texture>(texinit);
 	m_cubemapArr = getGrManager().newInstance<Texture>(texinit);
 
 
@@ -244,6 +245,10 @@ Error Ir::renderReflection(SceneNode& node, ShaderReflectionProbe& shaderProb)
 				m_nestedR.getIs().getRt(), 0, 0, m_cubemapArr, 6 * entry + i,
 				m_nestedR.getIs().getRt(), 0, 0, m_cubemapArr, 6 * entry + i,
 				0);
 				0);
 
 
+			// Gen mips
+			cmdb[cmdb.getSize() - 1]->generateMipmaps(m_cubemapArr,
+				6 * entry + i);
+
 			// Flush
 			// Flush
 			for(U j = 0; j < cmdb.getSize(); ++j)
 			for(U j = 0; j < cmdb.getSize(); ++j)
 			{
 			{

+ 73 - 0
src/scene/Rasterizer.cpp

@@ -0,0 +1,73 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/scene/Rasterizer.h>
+
+namespace anki {
+
+//==============================================================================
+Rasterizer::~Rasterizer()
+{
+	m_depthBuff.destroy(m_alloc);
+}
+
+//==============================================================================
+void Rasterizer::init(U width, U height, SceneAllocator<U8> alloc)
+{
+	ANKI_ASSERT(width > 1 && height > 1);
+	m_width = width;
+	m_height = height;
+	m_alloc = alloc;
+	m_depthBuff.create(m_alloc, width * height);
+}
+
+//==============================================================================
+void Rasterizer::prepare(const Mat4& mvp)
+{
+	m_mvp = mvp;
+	memset(&m_depthBuff[0], 0, m_depthBuff.getSize() * sizeof(U32));
+}
+
+//==============================================================================
+void Rasterizer::rasterizeTriangle(const Vec4& a, const Vec4& b, const Vec4& c)
+{
+	ANKI_ASSERT(a.w() == 1.0 && b.w() == 1.0 && c.w() == 1.0);
+
+	// Project
+	Array<Vec4, 3> positions;
+	positions[0] = m_mvp * a;
+	positions[1] = m_mvp * b;
+	positions[2] = m_mvp * c;
+
+	// - Viewport transform
+	// - Perspective divide
+	// - Box calculation
+	Vec4 vpScale = Vec4(m_width, m_height, 1.0, 0.0) * 0.5;
+	Vec4 vpTransl = vpScale; // In this case
+	Vec2 boxMin(MAX_F32);
+	Vec2 boxMax(MIN_F32);
+	for(Vec4& v : positions)
+	{
+		v = (v * vpScale).perspectiveDivide() + vpTransl;
+
+		boxMin.x() = min(boxMin.x(), v.x());
+		boxMin.y() = min(boxMin.y(), v.y());
+		boxMax.x() = max(boxMax.x(), v.x());
+		boxMax.y() = max(boxMax.y(), v.y());
+	}
+
+	// Cull
+	if(boxMin.x() > m_width || boxMin.y() > m_height
+		|| boxMax.x() < 0 || boxMax.y() < 0)
+	{
+		return;
+	}
+
+	// Backface culling
+	//Vec4 n = (positions[1].xyz0() - positions[0].xyz0()).cross(
+	//	positions[2].xyz0() - positions[1].xyz0());
+}
+
+} // end namespace anki