Browse Source

Add support for C-buffer

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
ddb821038d

+ 2 - 2
programs/HiZCopyToClient.ankiprog

@@ -28,9 +28,9 @@ void main()
 	uint x = gl_GlobalInvocationID.x;
 	uint y = gl_GlobalInvocationID.y;
 
-	if(x > HIZ_MIP_SIZE.x || y > HIZ_MIP_SIZE.y)
+	if(x >= HIZ_MIP_SIZE.x || y >= HIZ_MIP_SIZE.y)
 	{
-		// Skup if it's out of bounds
+		// Skip if it's out of bounds
 		return;
 	}
 

+ 2 - 0
src/anki/core/App.cpp

@@ -16,6 +16,7 @@
 #include <anki/core/NativeWindow.h>
 #include <anki/input/Input.h>
 #include <anki/scene/SceneGraph.h>
+#include <anki/renderer/RenderQueue.h>
 #include <anki/resource/ResourceManager.h>
 #include <anki/physics/PhysicsWorld.h>
 #include <anki/renderer/MainRenderer.h>
@@ -24,6 +25,7 @@
 #include <anki/resource/AsyncLoader.h>
 #include <anki/core/StagingGpuMemoryManager.h>
 #include <anki/ui/UiManager.h>
+#include <anki/ui/Canvas.h>
 
 #if ANKI_OS == ANKI_OS_ANDROID
 #	include <android_native_app_glue.h>

+ 5 - 1
src/anki/renderer/DepthDownscale.cpp

@@ -100,6 +100,9 @@ Error DepthDownscale::initInternal(const ConfigSet&)
 		m_copyToBuff.m_buff = getGrManager().newBuffer(buffInit);
 
 		m_copyToBuff.m_buffAddr = m_copyToBuff.m_buff->map(0, buffInit.m_size, BufferMapAccessBit::READ);
+
+		// Fill the buffer with 1.0f
+		memorySet(static_cast<F32*>(m_copyToBuff.m_buffAddr), 1.0f, lastMipHeight * lastMipWidth);
 	}
 
 	return Error::NONE;
@@ -218,9 +221,10 @@ void DepthDownscale::runCopyToBuffer(RenderPassWorkContext& rgraphCtx)
 {
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
+	cmdb->bindShaderProgram(m_copyToBuff.m_grProg);
+
 	TextureSubresourceInfo sampleSubresource;
 	sampleSubresource.m_firstMipmap = getMipmapCount() - 1;
-
 	rgraphCtx.bindTextureAndSampler(0, 0, m_runCtx.m_hizRt, sampleSubresource, m_r->getNearestSampler());
 
 	cmdb->bindStorageBuffer(0, 0, m_copyToBuff.m_buff, 0, m_copyToBuff.m_buff->getSize());

+ 8 - 0
src/anki/renderer/DepthDownscale.h

@@ -51,6 +51,14 @@ anki_internal:
 		return m_passes.getSize();
 	}
 
+	void getClientDepthMapInfo(F32*& depthValues, U32& width, U32& height) const
+	{
+		width = m_copyToBuff.m_lastMipWidth;
+		height = m_copyToBuff.m_lastMipHeight;
+		ANKI_ASSERT(m_copyToBuff.m_buffAddr);
+		depthValues = static_cast<F32*>(m_copyToBuff.m_buffAddr);
+	}
+
 private:
 	RenderTargetDescription m_depthRtDescr;
 	RenderTargetDescription m_hizRtDescr;

+ 6 - 0
src/anki/renderer/RenderQueue.h

@@ -178,6 +178,9 @@ public:
 
 static_assert(std::is_trivially_destructible<UiQueueElement>::value == true, "Should be trivially destructible");
 
+/// A callback to fill a coverage buffer.
+using FillCoverageBufferCallback = void (*)(void* userData, F32* depthValues, U32 width, U32 height);
+
 /// The render queue. This is what the renderer is fed to render.
 class RenderQueue : public RenderingMatrices
 {
@@ -199,6 +202,9 @@ public:
 
 	F32 m_cameraNear;
 	F32 m_cameraFar;
+
+	FillCoverageBufferCallback m_fillCoverageBufferCallback = nullptr;
+	void* m_fillCoverageBufferCallbackUserData = nullptr;
 };
 
 static_assert(std::is_trivially_destructible<RenderQueue>::value == true, "Should be trivially destructible");

+ 11 - 0
src/anki/renderer/Renderer.cpp

@@ -300,6 +300,17 @@ void Renderer::finalize(const RenderingContext& ctx)
 	++m_frameCount;
 	m_prevViewProjMat = ctx.m_renderQueue->m_viewProjectionMatrix;
 	m_prevCamTransform = ctx.m_renderQueue->m_cameraTransform;
+
+	// Inform about the HiZ map. Do it as late as possible
+	if(ctx.m_renderQueue->m_fillCoverageBufferCallback)
+	{
+		F32* depthValues;
+		U32 width;
+		U32 height;
+		m_depth->getClientDepthMapInfo(depthValues, width, height);
+		ctx.m_renderQueue->m_fillCoverageBufferCallback(
+			ctx.m_renderQueue->m_fillCoverageBufferCallbackUserData, depthValues, width, height);
+	}
 }
 
 Vec3 Renderer::unproject(

+ 1 - 1
src/anki/scene/SceneGraph.cpp

@@ -254,7 +254,7 @@ Error SceneGraph::update(Second prevUpdateTime, Second crntTime)
 void SceneGraph::doVisibilityTests(RenderQueue& rqueue)
 {
 	m_stats.m_visibilityTestsTime = HighRezTimer::getCurrentTime();
-	anki::doVisibilityTests(*m_mainCam, *this, rqueue);
+	doVisibilityTests(*m_mainCam, *this, rqueue);
 	m_stats.m_visibilityTestsTime = HighRezTimer::getCurrentTime() - m_stats.m_visibilityTestsTime;
 }
 

+ 3 - 1
src/anki/scene/SceneGraph.h

@@ -7,7 +7,6 @@
 
 #include <anki/scene/Common.h>
 #include <anki/scene/SceneNode.h>
-#include <anki/scene/Visibility.h>
 #include <anki/Math.h>
 #include <anki/util/Singleton.h>
 #include <anki/util/HighRezTimer.h>
@@ -284,6 +283,9 @@ private:
 
 	ANKI_USE_RESULT Error updateNodes(UpdateSceneNodesCtx& ctx) const;
 	ANKI_USE_RESULT static Error updateNode(Second prevTime, Second crntTime, SceneNode& node);
+
+	/// Do visibility tests.
+	static void doVisibilityTests(SceneNode& frustumable, SceneGraph& scene, RenderQueue& rqueue);
 };
 
 template<typename Node, typename... Args>

+ 21 - 1
src/anki/scene/SoftwareRasterizer.cpp

@@ -287,9 +287,12 @@ void SoftwareRasterizer::rasterizeTriangle(const Vec4* tri)
 				const F32 z1 = ndc[1].z();
 				const F32 z2 = ndc[2].z();
 
-				const F32 depth = z0 * bc[0] + z1 * bc[1] + z2 * bc[2];
+				F32 depth = z0 * bc[0] + z1 * bc[1] + z2 * bc[2];
 				ANKI_ASSERT(depth >= 0.0 && depth <= 1.0);
 
+				// Clamp it to a bit less that 1.0f because 1.0f will produce a 0 depthi
+				depth = min(depth, 1.0f - EPSILON);
+
 				// Store the min of the current value and new one
 				const U32 depthi = depth * MAX_U32;
 				m_zbuffer[U(y) * m_width + U(x)].min(depthi);
@@ -391,4 +394,21 @@ Bool SoftwareRasterizer::visibilityTestInternal(const CollisionShape& cs, const
 	return false;
 }
 
+void SoftwareRasterizer::fillDepthBuffer(ConstWeakArray<F32> depthValues)
+{
+	ANKI_ASSERT(m_zbuffer.getSize() == depthValues.getSize());
+
+	U count = depthValues.getSize();
+	while(count--)
+	{
+		F32 depth = depthValues[count];
+		ANKI_ASSERT(depth >= 0.0f && depth <= 1.0f);
+
+		depth = min(depth, 1.0f - EPSILON); // See a few lines above why is that
+
+		const U32 depthi = depth * MAX_U32;
+		m_zbuffer[count].set(depthi);
+	}
+}
+
 } // end namespace anki

+ 5 - 0
src/anki/scene/SoftwareRasterizer.h

@@ -8,6 +8,7 @@
 #include <anki/scene/Common.h>
 #include <anki/Math.h>
 #include <anki/collision/Plane.h>
+#include <anki/util/WeakArray.h>
 
 namespace anki
 {
@@ -42,8 +43,12 @@ public:
 	/// @param vertCount The number of verts to draw.
 	/// @param stride The stride (in bytes) of the next vertex.
 	/// @param backfaceCulling If true it will do backface culling.
+	/// @note It's thread-safe against other draw() invocations only.
 	void draw(const F32* verts, U vertCount, U stride, Bool backfaceCulling);
 
+	/// Fill the depth buffer with some values.
+	void fillDepthBuffer(ConstWeakArray<F32> depthValues);
+
 	/// Perform visibility tests.
 	/// @param cs The collision shape in world space.
 	/// @param aabb The Aabb in of the cs in world space.

+ 27 - 59
src/anki/scene/Visibility.cpp

@@ -3,7 +3,6 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <anki/scene/Visibility.h>
 #include <anki/scene/VisibilityInternal.h>
 #include <anki/scene/SceneGraph.h>
 #include <anki/scene/SectorNode.h>
@@ -71,35 +70,25 @@ void VisibilityContext::submitNewWork(const FrustumComponent& frc, RenderQueue&
 	// Submit new work
 	//
 
-	// Software rasterizer tasks
-	ThreadHiveSemaphore* rasterizeSem = nullptr;
-	if(frc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::OCCLUDERS))
+	// Software rasterizer task
+	ThreadHiveSemaphore* prepareRasterizerSem = nullptr;
+	if(frc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::OCCLUDERS) && frc.hasCoverageBuffer())
 	{
 		// Gather triangles task
-		ThreadHiveTask gatherTask;
-		gatherTask.m_callback = GatherVisibleTrianglesTask::callback;
-		gatherTask.m_argument = alloc.newInstance<GatherVisibleTrianglesTask>(frcCtx);
-		gatherTask.m_signalSemaphore = hive.newSemaphore(1);
-
-		hive.submitTasks(&gatherTask, 1);
-
-		// Rasterize triangles tasks
-		const U count = hive.getThreadCount();
-		rasterizeSem = hive.newSemaphore(count);
+		ThreadHiveTask fillDepthTask;
+		fillDepthTask.m_callback = FillRasterizerWithCoverageTask::callback;
+		fillDepthTask.m_argument = alloc.newInstance<FillRasterizerWithCoverageTask>(frcCtx);
+		fillDepthTask.m_signalSemaphore = hive.newSemaphore(1);
 
-		Array<ThreadHiveTask, ThreadHive::MAX_THREADS> rastTasks;
-		ThreadHiveTask& task = rastTasks[0];
-		task.m_callback = RasterizeTrianglesTask::callback;
-		task.m_argument = alloc.newInstance<RasterizeTrianglesTask>(frcCtx);
-		task.m_waitSemaphore = gatherTask.m_signalSemaphore;
-		task.m_signalSemaphore = rasterizeSem;
+		hive.submitTasks(&fillDepthTask, 1);
 
-		for(U i = 1; i < count; ++i)
-		{
-			rastTasks[i] = rastTasks[0];
-		}
+		prepareRasterizerSem = fillDepthTask.m_signalSemaphore;
+	}
 
-		hive.submitTasks(&rastTasks[0], count);
+	if(frc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::OCCLUDERS))
+	{
+		rqueue.m_fillCoverageBufferCallback = FrustumComponent::fillCoverageBufferCallback;
+		rqueue.m_fillCoverageBufferCallbackUserData = static_cast<void*>(const_cast<FrustumComponent*>(&frc));
 	}
 
 	// Gather visibles from the octree
@@ -107,7 +96,7 @@ void VisibilityContext::submitNewWork(const FrustumComponent& frc, RenderQueue&
 	gatherTask.m_callback = GatherVisiblesFromOctreeTask::callback;
 	gatherTask.m_argument = alloc.newInstance<GatherVisiblesFromOctreeTask>(frcCtx);
 	gatherTask.m_signalSemaphore = nullptr; // No need to signal anything because it will spawn new tasks
-	gatherTask.m_waitSemaphore = rasterizeSem;
+	gatherTask.m_waitSemaphore = prepareRasterizerSem;
 
 	hive.submitTasks(&gatherTask, 1);
 
@@ -121,47 +110,26 @@ void VisibilityContext::submitNewWork(const FrustumComponent& frc, RenderQueue&
 	hive.submitTasks(&combineTask, 1);
 }
 
-void GatherVisibleTrianglesTask::gather()
+void FillRasterizerWithCoverageTask::fill()
 {
-	ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_GATHER_TRIANGLES);
+	ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_FILL_DEPTH);
 
 	auto alloc = m_frcCtx->m_visCtx->m_scene->getFrameAllocator();
-	SceneComponentLists& lists = m_frcCtx->m_visCtx->m_scene->getSceneComponentLists();
 
-	lists.iterateComponents<OccluderComponent>([&](OccluderComponent& comp) {
-		if(m_frcCtx->m_frc->insideFrustum(comp.getBoundingVolume()))
-		{
-			U32 count, stride;
-			const Vec3* it;
-			comp.getVertices(it, count, stride);
-			while(count--)
-			{
-				m_frcCtx->m_verts.emplaceBack(alloc, *it);
-				it = reinterpret_cast<const Vec3*>(reinterpret_cast<const U8*>(it) + stride);
-			}
-		}
-	});
+	// Get the C-Buffer
+	ConstWeakArray<F32> depthBuff;
+	U32 width;
+	U32 height;
+	m_frcCtx->m_frc->getCoverageBufferInfo(depthBuff, width, height);
+	ANKI_ASSERT(width > 0 && height > 0 && depthBuff.getSize() > 0);
 
 	// Init the rasterizer
 	m_frcCtx->m_r = alloc.newInstance<SoftwareRasterizer>();
 	m_frcCtx->m_r->init(alloc);
-	m_frcCtx->m_r->prepare(m_frcCtx->m_frc->getViewMatrix(),
-		m_frcCtx->m_frc->getProjectionMatrix(),
-		SW_RASTERIZER_WIDTH,
-		SW_RASTERIZER_HEIGHT);
-}
+	m_frcCtx->m_r->prepare(m_frcCtx->m_frc->getViewMatrix(), m_frcCtx->m_frc->getProjectionMatrix(), width, height);
 
-void RasterizeTrianglesTask::rasterize()
-{
-	ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_RASTERIZE);
-
-	const U totalVertCount = m_frcCtx->m_verts.getSize();
-
-	U32 idx;
-	while((idx = m_frcCtx->m_rasterizedVertCount.fetchAdd(3)) < totalVertCount)
-	{
-		m_frcCtx->m_r->draw(&m_frcCtx->m_verts[idx][0], 3, sizeof(Vec3), false);
-	}
+	// Do the work
+	m_frcCtx->m_r->fillDepthBuffer(depthBuff);
 }
 
 void GatherVisiblesFromOctreeTask::gather(ThreadHive& hive, ThreadHiveSemaphore& sem)
@@ -705,7 +673,7 @@ void CombineResultsTask::combineQueueElements(SceneFrameAllocator<U8>& alloc,
 	}
 }
 
-void doVisibilityTests(SceneNode& fsn, SceneGraph& scene, RenderQueue& rqueue)
+void SceneGraph::doVisibilityTests(SceneNode& fsn, SceneGraph& scene, RenderQueue& rqueue)
 {
 	ANKI_TRACE_SCOPED_EVENT(SCENE_VIS_TESTS);
 

+ 0 - 21
src/anki/scene/Visibility.h

@@ -1,21 +0,0 @@
-// Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <anki/scene/Common.h>
-#include <anki/renderer/RenderQueue.h>
-
-namespace anki
-{
-
-/// @addtogroup scene
-/// @{
-
-/// Do visibility tests.
-void doVisibilityTests(SceneNode& frustumable, SceneGraph& scene, RenderQueue& rqueue);
-/// @}
-
-} // end namespace anki

+ 8 - 33
src/anki/scene/VisibilityInternal.h

@@ -5,7 +5,6 @@
 
 #pragma once
 
-#include <anki/scene/Visibility.h>
 #include <anki/scene/SectorNode.h>
 #include <anki/scene/SceneGraph.h>
 #include <anki/scene/SoftwareRasterizer.h>
@@ -13,6 +12,7 @@
 #include <anki/scene/Octree.h>
 #include <anki/util/Thread.h>
 #include <anki/core/Trace.h>
+#include <anki/renderer/RenderQueue.h>
 
 namespace anki
 {
@@ -156,13 +156,13 @@ public:
 	RenderQueue* m_renderQueue = nullptr;
 };
 
-/// ThreadHive task to gather all visible triangles from the OccluderComponent.
-class GatherVisibleTrianglesTask
+/// ThreadHive task to set the depth map of the S/W rasterizer.
+class FillRasterizerWithCoverageTask
 {
 public:
 	FrustumVisibilityContext* m_frcCtx = nullptr;
 
-	GatherVisibleTrianglesTask(FrustumVisibilityContext* frcCtx)
+	FillRasterizerWithCoverageTask(FrustumVisibilityContext* frcCtx)
 		: m_frcCtx(frcCtx)
 	{
 		ANKI_ASSERT(m_frcCtx);
@@ -171,40 +171,15 @@ public:
 	/// Thread hive task.
 	static void callback(void* ud, U32 threadId, ThreadHive& hive, ThreadHiveSemaphore* sem)
 	{
-		GatherVisibleTrianglesTask& self = *static_cast<GatherVisibleTrianglesTask*>(ud);
-		self.gather();
+		FillRasterizerWithCoverageTask& self = *static_cast<FillRasterizerWithCoverageTask*>(ud);
+		self.fill();
 	}
 
 private:
-	void gather();
+	void fill();
 };
 static_assert(
-	std::is_trivially_destructible<GatherVisibleTrianglesTask>::value == true, "Should be trivially destructible");
-
-/// ThreadHive task to rasterize triangles.
-class RasterizeTrianglesTask
-{
-public:
-	FrustumVisibilityContext* m_frcCtx = nullptr;
-
-	RasterizeTrianglesTask(FrustumVisibilityContext* frcCtx)
-		: m_frcCtx(frcCtx)
-	{
-		ANKI_ASSERT(m_frcCtx);
-	}
-
-	/// Thread hive task.
-	static void callback(void* ud, U32 threadId, ThreadHive& hive, ThreadHiveSemaphore* sem)
-	{
-		RasterizeTrianglesTask& self = *static_cast<RasterizeTrianglesTask*>(ud);
-		self.rasterize();
-	}
-
-private:
-	void rasterize();
-};
-static_assert(
-	std::is_trivially_destructible<RasterizeTrianglesTask>::value == true, "Should be trivially destructible");
+	std::is_trivially_destructible<FillRasterizerWithCoverageTask>::value == true, "Should be trivially destructible");
 
 /// ThreadHive task to get visible nodes from the octree.
 class GatherVisiblesFromOctreeTask

+ 5 - 1
src/anki/scene/components/FrustumComponent.cpp

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/scene/components/FrustumComponent.h>
-#include <anki/scene/Visibility.h>
 
 namespace anki
 {
@@ -22,6 +21,11 @@ FrustumComponent::FrustumComponent(SceneNode* node, Frustum* frustum)
 	setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
 }
 
+FrustumComponent::~FrustumComponent()
+{
+	m_coverageBuff.m_depthMap.destroy(getAllocator());
+}
+
 Error FrustumComponent::update(SceneNode& node, Second, Second, Bool& updated)
 {
 	updated = false;

+ 44 - 0
src/anki/scene/components/FrustumComponent.h

@@ -52,6 +52,8 @@ public:
 	/// Pass the frustum here so we can avoid the virtuals
 	FrustumComponent(SceneNode* node, Frustum* frustum);
 
+	~FrustumComponent();
+
 	Frustum& getFrustum()
 	{
 		return *m_frustum;
@@ -140,6 +142,40 @@ public:
 		return m_flags.getAny(FrustumComponentVisibilityTestFlag::ALL_TESTS);
 	}
 
+	/// The type is FillCoverageBufferCallback.
+	static void fillCoverageBufferCallback(void* userData, F32* depthValues, U32 width, U32 height)
+	{
+		ANKI_ASSERT(userData && depthValues && width > 0 && height > 0);
+		FrustumComponent& self = *static_cast<FrustumComponent*>(userData);
+
+		self.m_coverageBuff.m_depthMap.destroy(self.getAllocator());
+		self.m_coverageBuff.m_depthMap.create(self.getAllocator(), width * height);
+		memcpy(&self.m_coverageBuff.m_depthMap[0], depthValues, self.m_coverageBuff.m_depthMap.getSizeInBytes());
+
+		self.m_coverageBuff.m_depthMapWidth = width;
+		self.m_coverageBuff.m_depthMapHeight = height;
+	}
+
+	Bool hasCoverageBuffer() const
+	{
+		return m_coverageBuff.m_depthMap.getSize() > 0;
+	}
+
+	void getCoverageBufferInfo(ConstWeakArray<F32>& depthBuff, U32& width, U32& height) const
+	{
+		if(m_coverageBuff.m_depthMap.getSize() > 0)
+		{
+			depthBuff = ConstWeakArray<F32>(&m_coverageBuff.m_depthMap[0], m_coverageBuff.m_depthMap.getSize());
+			width = m_coverageBuff.m_depthMapWidth;
+			height = m_coverageBuff.m_depthMapHeight;
+		}
+		else
+		{
+			depthBuff = ConstWeakArray<F32>();
+			width = height = 0;
+		}
+	}
+
 private:
 	enum Flags
 	{
@@ -154,6 +190,14 @@ private:
 	Mat4 m_vpm = Mat4::getIdentity(); ///< View projection matrix
 
 	BitMask<U16> m_flags;
+
+	class
+	{
+	public:
+		DynamicArray<F32> m_depthMap;
+		U32 m_depthMapWidth = 0;
+		U32 m_depthMapHeight = 0;
+	} m_coverageBuff; ///< Coverage buffer for extra visibility tests.
 };
 /// @}
 

+ 7 - 24
src/anki/util/Functions.h

@@ -184,31 +184,14 @@ struct TypesAreTheSame<T, T>
 };
 
 template<typename T>
-void memorySet(T* dest, T value, const PtrSize count);
-
-#define ANKI_SPECIALISE_MEMORY_SET(T) \
-	template<> \
-	inline void memorySet(T* dest, T value, const PtrSize count) \
-	{ \
-		ANKI_ASSERT(dest); \
-		const T* end = dest + count; \
-		while(dest != end) \
-		{ \
-			memcpy(reinterpret_cast<char*>(dest), &value, sizeof(T)); \
-			++dest; \
-		} \
+void memorySet(T* dest, T value, PtrSize count)
+{
+	ANKI_ASSERT(dest);
+	while(count--)
+	{
+		dest[count] = value;
 	}
-
-ANKI_SPECIALISE_MEMORY_SET(U8)
-ANKI_SPECIALISE_MEMORY_SET(I8)
-ANKI_SPECIALISE_MEMORY_SET(U16)
-ANKI_SPECIALISE_MEMORY_SET(I16)
-ANKI_SPECIALISE_MEMORY_SET(U32)
-ANKI_SPECIALISE_MEMORY_SET(I32)
-ANKI_SPECIALISE_MEMORY_SET(U64)
-ANKI_SPECIALISE_MEMORY_SET(I64)
-
-#undef ANKI_SPECIALISE_MEMORY_SET
+}
 
 /// Zero memory of an object
 template<typename T>