Browse Source

Some Vulkan fixes and some work on the Octree

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
db74484c00

+ 4 - 2
programs/Ui.ankiprog

@@ -15,8 +15,10 @@ http://www.anki3d.org/LICENSE
 #include "shaders/Common.glsl"
 
 layout(location = 0) in vec2 in_pos;
-layout(location = 1) in vec2 in_uv;
-layout(location = 2) in vec4 in_col;
+layout(location = 1) in vec4 in_col;
+#if TEXTURE_TYPE > 0
+layout(location = 2) in vec2 in_uv;
+#endif
 
 #if TEXTURE_TYPE > 0
 layout(location = 0) out vec2 out_uv;

+ 32 - 10
src/anki/gr/RenderGraph.cpp

@@ -104,6 +104,8 @@ public:
 	};
 	DynamicArray<ConsumedTextureInfo> m_consumedTextures;
 
+	Bool8 m_drawsToDefaultFb = false;
+
 	FramebufferPtr& fb()
 	{
 		return m_secondLevelCmdbInitInfo.m_framebuffer;
@@ -116,11 +118,13 @@ public:
 };
 
 /// A batch of render passes. These passes can run in parallel.
+/// @warning It's POD. Destructor won't be called.
 class RenderGraph::Batch
 {
 public:
 	DynamicArray<U32> m_passIndices;
 	DynamicArray<Barrier> m_barriersBefore;
+	CommandBuffer* m_cmdb; ///< Someone else holds the ref already so have a ptr here.
 };
 
 /// The RenderGraph build context.
@@ -134,7 +138,7 @@ public:
 	DynamicArray<RT> m_rts;
 	DynamicArray<Buffer> m_buffers;
 
-	CommandBufferPtr m_cmdb;
+	DynamicArray<CommandBufferPtr> m_graphicsCmdbs;
 
 	BakeContext(const StackAllocator<U8>& alloc)
 		: m_alloc(alloc)
@@ -271,7 +275,7 @@ void RenderGraph::reset()
 		p.m_secondLevelCmdbs.destroy(m_ctx->m_alloc);
 	}
 
-	m_ctx->m_cmdb.reset(nullptr);
+	m_ctx->m_graphicsCmdbs.destroy(m_ctx->m_alloc);
 
 	m_ctx->m_alloc = StackAllocator<U8>();
 	m_ctx = nullptr;
@@ -617,6 +621,7 @@ void RenderGraph::initRenderPassesAndSetDeps(const RenderGraphDescription& descr
 			if(graphicsPass.hasFramebuffer())
 			{
 				outPass.fb() = getOrCreateFramebuffer(graphicsPass.m_fbDescr, &graphicsPass.m_rtHandles[0]);
+				outPass.m_drawsToDefaultFb = graphicsPass.m_fbDescr.m_defaultFb;
 
 				outPass.m_fbRenderArea = graphicsPass.m_fbRenderArea;
 
@@ -691,6 +696,7 @@ void RenderGraph::initBatches()
 	while(passesInBatchCount < passCount)
 	{
 		Batch batch;
+		Bool drawsToDefaultFb = false;
 
 		for(U i = 0; i < passCount; ++i)
 		{
@@ -699,9 +705,26 @@ void RenderGraph::initBatches()
 				// Add to the batch
 				++passesInBatchCount;
 				batch.m_passIndices.emplaceBack(m_ctx->m_alloc, i);
+
+				// Will batch draw to default FB?
+				drawsToDefaultFb = drawsToDefaultFb || m_ctx->m_passes[i].m_drawsToDefaultFb;
 			}
 		}
 
+		// Get or create cmdb for the batch.
+		// Create a new cmdb if the batch is writing to default FB. This will help Vulkan to have a dependency of the
+		// swap chain image acquire to the 2nd command buffer instead of adding it to a single big cmdb.
+		if(m_ctx->m_graphicsCmdbs.isEmpty() || drawsToDefaultFb)
+		{
+			CommandBufferInitInfo cmdbInit;
+			cmdbInit.m_flags = CommandBufferFlag::COMPUTE_WORK | CommandBufferFlag::GRAPHICS_WORK;
+			CommandBufferPtr cmdb = getManager().newCommandBuffer(cmdbInit);
+
+			m_ctx->m_graphicsCmdbs.emplaceBack(m_ctx->m_alloc, cmdb);
+
+			batch.m_cmdb = cmdb.get();
+		}
+
 		// Push back batch
 		m_ctx->m_batches.emplaceBack(m_ctx->m_alloc, std::move(batch));
 
@@ -905,11 +928,6 @@ void RenderGraph::compileNewGraph(const RenderGraphDescription& descr, StackAllo
 	// Create barriers between batches
 	setBatchBarriers(descr);
 
-	// Create main command buffer
-	CommandBufferInitInfo cmdbInit;
-	cmdbInit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::COMPUTE_WORK;
-	m_ctx->m_cmdb = getManager().newCommandBuffer(cmdbInit);
-
 #if ANKI_DBG_RENDER_GRAPH
 	if(dumpDependencyDotFile(descr, ctx, "./"))
 	{
@@ -964,16 +982,17 @@ void RenderGraph::run() const
 {
 	ANKI_TRACE_SCOPED_EVENT(GR_RENDER_GRAPH);
 	ANKI_ASSERT(m_ctx);
-	CommandBufferPtr& cmdb = m_ctx->m_cmdb;
 
 	RenderPassWorkContext ctx;
 	ctx.m_rgraph = this;
 	ctx.m_currentSecondLevelCommandBufferIndex = 0;
 	ctx.m_secondLevelCommandBufferCount = 0;
-	ctx.m_commandBuffer = cmdb;
 
 	for(const Batch& batch : m_ctx->m_batches)
 	{
+		ctx.m_commandBuffer.reset(batch.m_cmdb);
+		CommandBufferPtr& cmdb = ctx.m_commandBuffer;
+
 		// Set the barriers
 		for(const Barrier& barrier : batch.m_barriersBefore)
 		{
@@ -1036,7 +1055,10 @@ void RenderGraph::run() const
 
 void RenderGraph::flush()
 {
-	m_ctx->m_cmdb->flush();
+	for(CommandBufferPtr& cmdb : m_ctx->m_graphicsCmdbs)
+	{
+		cmdb->flush();
+	}
 }
 
 void RenderGraph::getCrntUsage(

+ 1 - 0
src/anki/renderer/DownscaleBlur.cpp

@@ -39,6 +39,7 @@ Error DownscaleBlur::initInternal(const ConfigSet&)
 			| TextureUsageBit::SAMPLED_COMPUTE,
 		"DownscaleBlur");
 	texinit.m_mipmapCount = m_passCount;
+	texinit.m_initialUsage = TextureUsageBit::SAMPLED_COMPUTE;
 	m_rtTex = m_r->createAndClearRenderTarget(texinit);
 
 	// FB descr

+ 9 - 6
src/anki/renderer/Indirect.cpp

@@ -366,12 +366,15 @@ void Indirect::runGBuffer(CommandBufferPtr& cmdb)
 		ANKI_ASSERT(probe.m_renderQueues[faceIdx]);
 		const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
 
-		m_r->getSceneDrawer().drawRange(Pass::GB_FS,
-			rqueue.m_viewMatrix,
-			rqueue.m_viewProjectionMatrix,
-			cmdb,
-			rqueue.m_renderables.getBegin(),
-			rqueue.m_renderables.getEnd());
+		if(!rqueue.m_renderables.isEmpty())
+		{
+			m_r->getSceneDrawer().drawRange(Pass::GB_FS,
+				rqueue.m_viewMatrix,
+				rqueue.m_viewProjectionMatrix,
+				cmdb,
+				rqueue.m_renderables.getBegin(),
+				rqueue.m_renderables.getEnd());
+		}
 	}
 
 	// Restore state

+ 60 - 15
src/anki/scene/Octree.cpp

@@ -19,22 +19,45 @@ void Octree::init(const Vec3& sceneAabbMin, const Vec3& sceneAabbMax, U32 maxDep
 	m_sceneAabbMin = sceneAabbMin;
 	m_sceneAabbMax = sceneAabbMax;
 
-	OctreeLeaf& root = newLeaf();
-	m_rootLeaf = &root;
+	m_rootLeaf = newLeaf();
 }
 
-void Octree::placeElement(const Aabb& volume, OctreeElement* element)
+void Octree::place(const Aabb& volume, OctreeHandle* handle)
 {
 	ANKI_ASSERT(m_rootLeaf);
-	ANKI_ASSERT(element);
-	placeElementRecursive(volume, element, *m_rootLeaf, m_sceneAabbMin, m_sceneAabbMax);
+	ANKI_ASSERT(handle);
+
+	// Remove the handle from the Octree...
+	// TOOD
+
+	// .. and re-place it
+	placeRecursive(volume, handle, m_rootLeaf, m_sceneAabbMin, m_sceneAabbMax, 0);
 }
 
-void Octree::placeElementRecursive(
-	const Aabb& volume, OctreeElement* element, OctreeLeaf& parent, const Vec3& aabbMin, const Vec3& aabbMax)
+void Octree::placeRecursive(
+	const Aabb& volume, OctreeHandle* handle, Leaf* parent, const Vec3& aabbMin, const Vec3& aabbMax, U32 depth)
 {
+	ANKI_ASSERT(handle);
+	ANKI_ASSERT(parent);
 	ANKI_ASSERT(testCollisionShapes(volume, Aabb(Vec4(aabbMin, 0.0f), Vec4(aabbMax, 0.0f))) && "Should be inside");
 
+	if(depth == m_maxDepth)
+	{
+		// Need to stop and bin the handle to the leaf
+
+		// Checks
+		for(const LeafNode& node : handle->m_leafs)
+		{
+			ANKI_ASSERT(node.m_leaf != parent && "Already binned. That's wrong");
+		}
+
+		// Connect handle and leaf
+		handle->m_leafs.pushBack(newLeafNode(parent));
+		parent->m_handles.pushBack(newHandle(handle));
+
+		return;
+	}
+
 	const Vec4& vMin = volume.getMin();
 	const Vec4& vMax = volume.getMax();
 	const Vec3 center = (aabbMax + aabbMin) / 2.0f;
@@ -43,12 +66,12 @@ void Octree::placeElementRecursive(
 	if(vMin.x() > center.x())
 	{
 		// Only right
-		maskX = LeafMask::PX_PY_PZ | LeafMask::PX_PY_NZ | LeafMask::PX_NY_PZ | LeafMask::PX_NY_NZ;
+		maskX = LeafMask::RIGHT;
 	}
 	else if(vMax.x() < center.x())
 	{
 		// Only left
-		maskX = LeafMask::NX_PY_PZ | LeafMask::NX_PY_NZ | LeafMask::NX_NY_PZ | LeafMask::NX_NY_NZ;
+		maskX = LeafMask::LEFT;
 	}
 	else
 	{
@@ -59,12 +82,12 @@ void Octree::placeElementRecursive(
 	if(vMin.y() > center.y())
 	{
 		// Only top
-		maskY = LeafMask::PX_PY_PZ | LeafMask::PX_PY_NZ | LeafMask::NX_PY_PZ | LeafMask::NX_PY_NZ;
+		maskY = LeafMask::TOP;
 	}
 	else if(vMax.y() < center.y())
 	{
 		// Only bottom
-		maskY = LeafMask::PX_NY_PZ | LeafMask::PX_NY_NZ | LeafMask::NX_NY_PZ | LeafMask::NX_NY_NZ;
+		maskY = LeafMask::BOTTOM;
 	}
 	else
 	{
@@ -75,12 +98,12 @@ void Octree::placeElementRecursive(
 	if(vMin.z() > center.z())
 	{
 		// Only front
-		maskZ = LeafMask::PX_PY_PZ | LeafMask::PX_NY_PZ | LeafMask::NX_PY_PZ | LeafMask::NX_NY_PZ;
+		maskZ = LeafMask::FRONT;
 	}
 	else if(vMax.z() < center.z())
 	{
 		// Only back
-		maskZ = LeafMask::PX_PY_NZ | LeafMask::PX_NY_NZ | LeafMask::NX_PY_NZ | LeafMask::NX_NY_NZ;
+		maskZ = LeafMask::BACK;
 	}
 	else
 	{
@@ -88,9 +111,31 @@ void Octree::placeElementRecursive(
 	}
 
 	LeafMask maskUnion = maskX & maskY & maskZ;
-	ANKI_ASSERT(!!maskUnion);
+	ANKI_ASSERT(!!maskUnion && "Should be inside at least one leaf");
+
+	for(U i = 0; i < 8; ++i)
+	{
+		const LeafMask crntBit = LeafMask(1 << i);
+
+		if(!!(maskUnion & crntBit))
+		{
+			// Inside the leaf, move deeper
 
-	// TODO
+			// Compute AABB
+			Vec3 aabbMin, aabbMax;
+			if(!!(crntBit & LeafMask::RIGHT))
+			{
+				// TODO
+			}
+
+			if(parent->m_leafs[i] == nullptr)
+			{
+				parent->m_leafs[i] = newLeaf();
+			}
+
+			// TODO
+		}
+	}
 }
 
 } // end namespace anki

+ 94 - 34
src/anki/scene/Octree.h

@@ -11,37 +11,22 @@
 #include <anki/util/WeakArray.h>
 #include <anki/util/Enum.h>
 #include <anki/util/ObjectAllocator.h>
+#include <anki/util/List.h>
 
 namespace anki
 {
 
 // Forward
-class OctreeLeaf;
+class OctreeHandle;
 
 /// @addtogroup scene
 /// @{
 
-/// XXX
-class OctreeElement
-{
-public:
-	Bool8 m_visited = false;
-};
-
-/// XXX
-/// @warning Keept its size as small as possible.
-/// @warning Watch the members. Should be be able to zero its memory to initialize it.
-class OctreeLeaf
-{
-public:
-	OctreeElement* m_first;
-	OctreeElement* m_last;
-	Array<OctreeLeaf*, 8> m_leafs;
-};
-
 /// Octree for visibility tests.
 class Octree
 {
+	friend class OctreeHandle;
+
 public:
 	Octree(SceneAllocator<U8> alloc)
 		: m_alloc(alloc)
@@ -54,21 +39,39 @@ public:
 
 	/// Place or re-place an element in the tree.
 	/// @note It's thread-safe.
-	void placeElement(const Aabb& volume, OctreeElement* element);
+	void place(const Aabb& volume, OctreeHandle* handle);
 
 	/// Remove an element from the tree.
 	/// @note It's thread-safe.
-	void removeElement(OctreeElement& element);
+	void remove(OctreeHandle& handle);
+
+	/// Gather visible handles.
+	/// @note It's thread-safe.
+	DynamicArray<OctreeHandle*> gatherVisible(GenericMemoryPoolAllocator<U8> alloc, U32 testId);
 
 private:
-	SceneAllocator<U8> m_alloc;
-	U32 m_maxDepth = 0;
-	Vec3 m_sceneAabbMin = Vec3(0.0f);
-	Vec3 m_sceneAabbMax = Vec3(0.0f);
+	/// XXX
+	class Handle : public IntrusiveListEnabled<Handle>
+	{
+	public:
+		OctreeHandle* m_handle = nullptr;
+	};
 
-	ObjectAllocatorSameType<OctreeLeaf, 256> m_leafAlloc;
+	/// XXX
+	/// @warning Keept its size as small as possible.
+	class Leaf
+	{
+	public:
+		IntrusiveList<Handle> m_handles;
+		Array<Leaf*, 8> m_leafs = {};
+	};
 
-	OctreeLeaf* m_rootLeaf = nullptr;
+	/// XXX
+	class LeafNode : public IntrusiveListEnabled<LeafNode>
+	{
+	public:
+		Leaf* m_leaf = nullptr;
+	};
 
 	/// P: Stands for positive and N: Negative
 	enum class LeafMask : U8
@@ -84,23 +87,80 @@ private:
 
 		NONE = 0,
 		ALL = PX_PY_PZ | PX_PY_NZ | PX_NY_PZ | PX_NY_NZ | NX_PY_PZ | NX_PY_NZ | NX_NY_PZ | NX_NY_NZ,
+		RIGHT = PX_PY_PZ | PX_PY_NZ | PX_NY_PZ | PX_NY_NZ,
+		LEFT = NX_PY_PZ | NX_PY_NZ | NX_NY_PZ | NX_NY_NZ,
+		TOP = PX_PY_PZ | PX_PY_NZ | NX_PY_PZ | NX_PY_NZ,
+		BOTTOM = PX_NY_PZ | PX_NY_NZ | NX_NY_PZ | NX_NY_NZ,
+		FRONT = PX_PY_PZ | PX_NY_PZ | NX_PY_PZ | NX_NY_PZ,
+		BACK = PX_PY_NZ | PX_NY_NZ | NX_PY_NZ | NX_NY_NZ,
 	};
 	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(LeafMask, friend)
 
-	OctreeLeaf& newLeaf()
+	SceneAllocator<U8> m_alloc;
+	U32 m_maxDepth = 0;
+	Vec3 m_sceneAabbMin = Vec3(0.0f);
+	Vec3 m_sceneAabbMax = Vec3(0.0f);
+
+	ObjectAllocatorSameType<Leaf, 256> m_leafAlloc;
+	ObjectAllocatorSameType<LeafNode, 128> m_leafNodeAlloc;
+	ObjectAllocatorSameType<Handle, 256> m_handleAlloc;
+
+	Leaf* m_rootLeaf = nullptr;
+
+	Leaf* newLeaf()
 	{
-		OctreeLeaf* out = m_leafAlloc.newInstance(m_alloc);
-		zeroMemory(*out);
-		return *out;
+		return m_leafAlloc.newInstance(m_alloc);
 	}
 
-	void releaseLeaf(OctreeLeaf* leaf)
+	void releaseLeaf(Leaf* leaf)
 	{
 		m_leafAlloc.deleteInstance(m_alloc, leaf);
 	}
 
-	void placeElementRecursive(
-		const Aabb& volume, OctreeElement* element, OctreeLeaf& parent, const Vec3& aabbMin, const Vec3& aabbMax);
+	Handle* newHandle(OctreeHandle* handle)
+	{
+		ANKI_ASSERT(handle);
+		Handle* out = m_handleAlloc.newInstance(m_alloc);
+		out->m_handle = handle;
+		return out;
+	}
+
+	void releaseHandle(Handle* handle)
+	{
+		m_handleAlloc.deleteInstance(m_alloc, handle);
+	}
+
+	LeafNode* newLeafNode(Leaf* leaf)
+	{
+		ANKI_ASSERT(leaf);
+		LeafNode* out = m_leafNodeAlloc.newInstance(m_alloc);
+		out->m_leaf = leaf;
+		return out;
+	}
+
+	void releaseLeafNode(LeafNode* node)
+	{
+		m_leafNodeAlloc.deleteInstance(m_alloc, node);
+	}
+
+	void placeRecursive(
+		const Aabb& volume, OctreeHandle* handle, Leaf* parent, const Vec3& aabbMin, const Vec3& aabbMax, U32 depth);
+};
+
+/// XXX
+class OctreeHandle
+{
+	friend class Octree;
+
+public:
+	void reset()
+	{
+		m_visitedMask.set(0);
+	}
+
+private:
+	Atomic<U64> m_visitedMask = {0u};
+	IntrusiveList<Octree::LeafNode> m_leafs; ///< A list of leafs this handle belongs.
 };
 /// @}
 

+ 2 - 2
src/anki/ui/Canvas.cpp

@@ -205,8 +205,8 @@ void Canvas::appendToCommandBuffer(CommandBufferPtr cmdb)
 	// Vert & idx buffers
 	cmdb->bindVertexBuffer(0, vertCtx.m_token.m_buffer, vertCtx.m_token.m_offset, sizeof(Vert));
 	cmdb->setVertexAttribute(0, 0, Format::R32G32_SFLOAT, 0);
-	cmdb->setVertexAttribute(1, 0, Format::R32G32_SFLOAT, sizeof(Vec2));
-	cmdb->setVertexAttribute(2, 0, Format::R8G8B8A8_UNORM, sizeof(Vec2) * 2);
+	cmdb->setVertexAttribute(1, 0, Format::R8G8B8A8_UNORM, sizeof(Vec2) * 2);
+	cmdb->setVertexAttribute(2, 0, Format::R32G32_SFLOAT, sizeof(Vec2));
 
 	cmdb->bindIndexBuffer(idxCtx.m_token.m_buffer, idxCtx.m_token.m_offset, IndexType::U16);
 

+ 14 - 0
src/anki/util/Atomic.h

@@ -81,6 +81,20 @@ public:
 		return m_att.fetch_sub(a, static_cast<std::memory_order>(memOrd));
 	}
 
+	/// Fetch and do bitwise or.
+	template<typename Y>
+	Value fetchOr(const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	{
+		return m_att.fetch_or(a, static_cast<std::memory_order>(memOrd));
+	}
+
+	/// Fetch and do bitwise and.
+	template<typename Y>
+	Value fetchAnd(const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	{
+		return m_att.fetch_and(a, static_cast<std::memory_order>(memOrd));
+	}
+
 	/// @code
 	/// if(m_val == expected) {
 	/// 	m_val = desired;