Browse Source

Add GL fence. Some work in the transfer allocator

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
1c031e0e90

+ 2 - 1
src/anki/gr/CommandBuffer.h

@@ -133,7 +133,8 @@ public:
 	CommandBufferInitHints computeInitHints() const;
 	CommandBufferInitHints computeInitHints() const;
 
 
 	/// Finalize and submit if it's primary command buffer and just finalize if it's second level.
 	/// Finalize and submit if it's primary command buffer and just finalize if it's second level.
-	void flush();
+	/// @param[out] fence Optionaly create fence.
+	void flush(FencePtr* fence = nullptr);
 
 
 	/// Flush and wait to finish.
 	/// Flush and wait to finish.
 	void finish();
 	void finish();

+ 1 - 0
src/anki/gr/Common.h

@@ -67,6 +67,7 @@ ANKI_GR_CLASS(Shader)
 ANKI_GR_CLASS(Framebuffer)
 ANKI_GR_CLASS(Framebuffer)
 ANKI_GR_CLASS(OcclusionQuery)
 ANKI_GR_CLASS(OcclusionQuery)
 ANKI_GR_CLASS(ShaderProgram)
 ANKI_GR_CLASS(ShaderProgram)
+ANKI_GR_CLASS(Fence)
 
 
 #undef ANKI_GR_CLASS
 #undef ANKI_GR_CLASS
 
 

+ 38 - 0
src/anki/gr/Fence.h

@@ -0,0 +1,38 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/gr/GrObject.h>
+
+namespace anki
+{
+
+/// @addtogroup graphics
+/// @{
+
+/// GPU fence.
+class Fence final : public GrObject
+{
+	ANKI_GR_OBJECT
+
+public:
+	/// Wait for the fence.
+	Bool clientWait(F64 seconds);
+
+anki_internal:
+	static const GrObjectType CLASS_TYPE = GrObjectType::FENCE;
+
+	UniquePtr<FenceImpl> m_impl;
+
+	/// Construct.
+	Fence(GrManager* manager, U64 hash, GrObjectCache* cache);
+
+	/// Destroy.
+	~Fence();
+};
+/// @}
+
+} // end namespace anki

+ 1 - 0
src/anki/gr/GrObject.h

@@ -26,6 +26,7 @@ enum GrObjectType : U16
 	SHADER,
 	SHADER,
 	TEXTURE,
 	TEXTURE,
 	SHADER_PROGRAM,
 	SHADER_PROGRAM,
+	FENCE,
 	COUNT
 	COUNT
 };
 };
 
 

+ 3 - 2
src/anki/gr/gl/CommandBuffer.cpp

@@ -52,16 +52,17 @@ void CommandBuffer::init(CommandBufferInitInfo& inf)
 	}
 	}
 }
 }
 
 
-void CommandBuffer::flush()
+void CommandBuffer::flush(FencePtr* fence)
 {
 {
 	if(!m_impl->isSecondLevel())
 	if(!m_impl->isSecondLevel())
 	{
 	{
 		ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 		ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
+		ANKI_ASSERT(fence == nullptr);
 	}
 	}
 
 
 	if(!m_impl->isSecondLevel())
 	if(!m_impl->isSecondLevel())
 	{
 	{
-		getManager().getImplementation().getRenderingThread().flushCommandBuffer(CommandBufferPtr(this));
+		getManager().getImplementation().getRenderingThread().flushCommandBuffer(CommandBufferPtr(this), fence);
 	}
 	}
 }
 }
 
 

+ 85 - 0
src/anki/gr/gl/Fence.cpp

@@ -0,0 +1,85 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/Fence.h>
+#include <anki/gr/gl/FenceImpl.h>
+#include <anki/gr/CommandBuffer.h>
+#include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
+
+namespace anki
+{
+
+Fence::Fence(GrManager* manager, U64 hash, GrObjectCache* cache)
+	: GrObject(manager, CLASS_TYPE, hash, cache)
+{
+}
+
+Fence::~Fence()
+{
+}
+
+Bool Fence::clientWait(F64 seconds)
+{
+	if(m_impl->m_signaled.load())
+	{
+		return true;
+	}
+
+	if(seconds == 0.0)
+	{
+		return false;
+	}
+
+	class CheckFenceCommand final : public GlCommand
+	{
+	public:
+		FenceImpl* m_fence; // Use the ptr to impl because there is a barrier that covers racing condition.
+		F64 m_timeout;
+		Barrier* m_barrier;
+
+		CheckFenceCommand(FenceImpl* fence, F64 timeout, Barrier* barrier)
+			: m_fence(fence)
+			, m_timeout(timeout)
+			, m_barrier(barrier)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			GLenum out = glClientWaitSync(m_fence->m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, m_timeout * 1e+9);
+
+			if(out == GL_ALREADY_SIGNALED || out == GL_CONDITION_SATISFIED)
+			{
+				m_fence->m_signaled.store(true);
+			}
+			else if(out == GL_TIMEOUT_EXPIRED)
+			{
+				// Do nothing
+			}
+			else
+			{
+				ANKI_ASSERT(out == GL_WAIT_FAILED);
+				return ErrorCode::FUNCTION_FAILED;
+			}
+
+			m_barrier->wait();
+
+			return ErrorCode::NONE;
+		}
+	};
+
+	Barrier barrier(2);
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	cmdb->m_impl->pushBackNewCommand<CheckFenceCommand>(m_impl.get(), seconds, &barrier);
+	cmdb->flush();
+
+	barrier.wait();
+
+	return m_impl->m_signaled.load();
+}
+
+} // end namespace anki

+ 55 - 0
src/anki/gr/gl/FenceImpl.cpp

@@ -0,0 +1,55 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/gl/FenceImpl.h>
+#include <anki/gr/CommandBuffer.h>
+#include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
+#include <anki/gr/gl/GrManagerImpl.h>
+#include <anki/gr/gl/RenderingThread.h>
+
+namespace anki
+{
+
+FenceImpl::~FenceImpl()
+{
+	class DeleteFenceCommand final : public GlCommand
+	{
+	public:
+		GLsync m_fence;
+
+		DeleteFenceCommand(GLsync fence)
+			: m_fence(fence)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			glDeleteSync(m_fence);
+			return ErrorCode::NONE;
+		}
+	};
+
+	if(m_fence)
+	{
+		GrManager& manager = getManager();
+		RenderingThread& thread = manager.getImplementation().getRenderingThread();
+
+		if(!thread.isServerThread())
+		{
+			CommandBufferPtr commands;
+
+			commands = manager.newInstance<CommandBuffer>(CommandBufferInitInfo());
+			commands->m_impl->pushBackNewCommand<DeleteFenceCommand>(m_fence);
+			commands->flush();
+		}
+		else
+		{
+			glDeleteSync(m_fence);
+		}
+	}
+}
+
+} // end namespace anki

+ 14 - 5
src/anki/resource/TransferGpuMemoryAllocator.h → src/anki/gr/gl/FenceImpl.h

@@ -5,18 +5,27 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <anki/resource/Common.h>
-#include <anki/gr/common/ClassGpuAllocator.h>
+#include <anki/gr/gl/GlObject.h>
 
 
 namespace anki
 namespace anki
 {
 {
 
 
-/// @addtogroup resource
+/// @addtogroup opengl
 /// @{
 /// @{
 
 
-/// GPU memory allocator for GPU buffers used in transfer operations.
-class TransferGpuMemoryAllocator
+/// Fence implementation.
+class FenceImpl : public GlObject
 {
 {
+public:
+	GLsync m_fence = nullptr;
+	Atomic<Bool> m_signaled = {false};
+
+	FenceImpl(GrManager* gr)
+		: GlObject(gr)
+	{
+	}
+
+	~FenceImpl();
 };
 };
 /// @}
 /// @}
 
 

+ 35 - 5
src/anki/gr/gl/RenderingThread.cpp

@@ -8,6 +8,8 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/GlState.h>
 #include <anki/gr/gl/GlState.h>
+#include <anki/gr/Fence.h>
+#include <anki/gr/gl/FenceImpl.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Logger.h>
 #include <anki/core/Trace.h>
 #include <anki/core/Trace.h>
 #include <cstdlib>
 #include <cstdlib>
@@ -76,8 +78,36 @@ RenderingThread::~RenderingThread()
 	m_queue.destroy(m_manager->getAllocator());
 	m_queue.destroy(m_manager->getAllocator());
 }
 }
 
 
-void RenderingThread::flushCommandBuffer(CommandBufferPtr cmdb)
+void RenderingThread::flushCommandBuffer(CommandBufferPtr cmdb, FencePtr* fence)
 {
 {
+	// Create a fence
+	if(fence)
+	{
+		FencePtr& f = *fence;
+
+		f.reset(m_manager->getImplementation().getAllocator().newInstance<Fence>(m_manager.get(), 0, nullptr));
+		f->m_impl.reset(m_manager->getAllocator().newInstance<FenceImpl>(m_manager.get()));
+
+		class CreateFenceCmd final : public GlCommand
+		{
+		public:
+			FencePtr m_fence;
+
+			CreateFenceCmd(FencePtr fence)
+				: m_fence(fence)
+			{
+			}
+
+			Error operator()(GlState&)
+			{
+				m_fence->m_impl->m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+				return ErrorCode::NONE;
+			}
+		};
+
+		cmdb->m_impl->pushBackNewCommand<CreateFenceCmd>(f);
+	}
+
 	cmdb->m_impl->makeImmutable();
 	cmdb->m_impl->makeImmutable();
 
 
 	{
 	{
@@ -104,7 +134,7 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr cmdb)
 
 
 void RenderingThread::finishCommandBuffer(CommandBufferPtr commands)
 void RenderingThread::finishCommandBuffer(CommandBufferPtr commands)
 {
 {
-	flushCommandBuffer(commands);
+	flushCommandBuffer(commands, nullptr);
 
 
 	syncClientServer();
 	syncClientServer();
 }
 }
@@ -137,7 +167,7 @@ void RenderingThread::stop()
 {
 {
 	syncClientServer();
 	syncClientServer();
 	m_renderingThreadSignal = 1;
 	m_renderingThreadSignal = 1;
-	flushCommandBuffer(m_emptyCmdb);
+	flushCommandBuffer(m_emptyCmdb, nullptr);
 
 
 	Error err = m_thread.join();
 	Error err = m_thread.join();
 	(void)err;
 	(void)err;
@@ -242,7 +272,7 @@ void RenderingThread::syncClientServer()
 	// syncClientServer all of them will hit the same barrier.
 	// syncClientServer all of them will hit the same barrier.
 	LockGuard<SpinLock> lock(m_syncLock);
 	LockGuard<SpinLock> lock(m_syncLock);
 
 
-	flushCommandBuffer(m_syncCommands);
+	flushCommandBuffer(m_syncCommands, nullptr);
 	m_syncBarrier.wait();
 	m_syncBarrier.wait();
 }
 }
 
 
@@ -279,7 +309,7 @@ void RenderingThread::swapBuffers()
 	}
 	}
 
 
 	// ...and then flush a new swap buffers
 	// ...and then flush a new swap buffers
-	flushCommandBuffer(m_swapBuffersCommands);
+	flushCommandBuffer(m_swapBuffersCommands, nullptr);
 	ANKI_TRACE_STOP_EVENT(SWAP_BUFFERS);
 	ANKI_TRACE_STOP_EVENT(SWAP_BUFFERS);
 }
 }
 
 

+ 1 - 1
src/anki/gr/gl/RenderingThread.h

@@ -33,7 +33,7 @@ public:
 	void stop();
 	void stop();
 
 
 	/// Push a command buffer to the queue for deferred execution
 	/// Push a command buffer to the queue for deferred execution
-	void flushCommandBuffer(CommandBufferPtr commands);
+	void flushCommandBuffer(CommandBufferPtr commands, FencePtr* fence);
 
 
 	/// Push a command buffer to the queue and wait for it
 	/// Push a command buffer to the queue and wait for it
 	void finishCommandBuffer(CommandBufferPtr commands);
 	void finishCommandBuffer(CommandBufferPtr commands);

+ 0 - 15
src/anki/gr/vulkan/GpuMemoryManager.cpp

@@ -18,21 +18,6 @@ public:
 	PtrSize m_chunkSize;
 	PtrSize m_chunkSize;
 };
 };
 
 
-static constexpr unsigned long long int operator""_B(unsigned long long int x)
-{
-	return x;
-}
-
-static constexpr unsigned long long int operator""_KB(unsigned long long int x)
-{
-	return x * 1024;
-}
-
-static constexpr unsigned long long int operator""_MB(unsigned long long int x)
-{
-	return x * 1024 * 1024;
-}
-
 static const Array<ClassInf, CLASS_COUNT> CLASSES = {{{256_B, 16_KB},
 static const Array<ClassInf, CLASS_COUNT> CLASSES = {{{256_B, 16_KB},
 	{4_KB, 256_KB},
 	{4_KB, 256_KB},
 	{128_KB, 8_MB},
 	{128_KB, 8_MB},

+ 75 - 0
src/anki/resource/TransferGpuAllocator.cpp

@@ -0,0 +1,75 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/resource/TransferGpuAllocator.h>
+#include <anki/gr/Fence.h>
+#include <anki/gr/Buffer.h>
+#include <anki/gr/GrManager.h>
+
+namespace anki
+{
+
+class TransferGpuAllocator::Memory : public ClassGpuAllocatorMemory
+{
+public:
+	BufferPtr m_buffer;
+	void* m_mappedMemory;
+
+	DynamicArray<FencePtr> m_fences;
+	U32 m_fencesCount = 0;
+};
+
+class TransferGpuAllocator::ClassInf
+{
+public:
+	PtrSize m_slotSize;
+	PtrSize m_chunkSize;
+};
+
+static const Array<TransferGpuAllocator::ClassInf, 3> CLASSES = {{{8_MB, 128_MB}, {64_MB, 256_MB}, {128_MB, 256_MB}}};
+
+class TransferGpuAllocator::Interface : public ClassGpuAllocatorInterface
+{
+public:
+	GrManager* m_gr;
+	ResourceAllocator<U8> m_alloc;
+
+	Error allocate(U classIdx, ClassGpuAllocatorMemory*& mem) override
+	{
+		TransferGpuAllocator::Memory* mm = m_alloc.newInstance<TransferGpuAllocator::Memory>();
+
+		const PtrSize size = CLASSES[classIdx].m_chunkSize;
+		mm->m_buffer = m_gr->newInstance<Buffer>(size, BufferUsageBit::BUFFER_UPLOAD_SOURCE, BufferMapAccessBit::WRITE);
+
+		// TODO
+
+		mem = mm;
+
+		return ErrorCode::NONE;
+	}
+
+	void free(ClassGpuAllocatorMemory* mem) override
+	{
+		ANKI_ASSERT(mem);
+
+		TransferGpuAllocator::Memory* mm = static_cast<TransferGpuAllocator::Memory*>(mem);
+		mm->m_fences.destroy(m_alloc);
+		mm->m_buffer.reset(nullptr);
+		mm->m_fencesCount = 0;
+	}
+
+	U getClassCount() const override
+	{
+		return CLASSES.getSize();
+	}
+
+	void getClassInfo(U classIdx, PtrSize& slotSize, PtrSize& chunkSize) const override
+	{
+		slotSize = CLASSES[classIdx].m_slotSize;
+		chunkSize = CLASSES[classIdx].m_chunkSize;
+	}
+};
+
+} // end namespace anki

+ 81 - 0
src/anki/resource/TransferGpuAllocator.h

@@ -0,0 +1,81 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/resource/Common.h>
+#include <anki/gr/common/ClassGpuAllocator.h>
+
+namespace anki
+{
+
+/// @addtogroup resource
+/// @{
+
+/// Memory handle.
+class TransferGpuAllocatorHandle
+{
+public:
+	TransferGpuAllocatorHandle() = default;
+
+	TransferGpuAllocatorHandle(const TransferGpuAllocatorHandle&) = delete;
+
+	TransferGpuAllocatorHandle(TransferGpuAllocatorHandle&& b)
+	{
+		*this = std::move(b);
+	}
+
+	~TransferGpuAllocatorHandle();
+
+	TransferGpuAllocatorHandle& operator=(TransferGpuAllocatorHandle&& b)
+	{
+		m_handle = b.m_handle;
+		b.m_handle = {};
+		return *this;
+	}
+
+	BufferPtr getBuffer() const;
+
+	PtrSize getOffset() const
+	{
+		ANKI_ASSERT(m_handle);
+		return m_handle.m_offset;
+	}
+
+	PtrSize getRange() const
+	{
+		ANKI_ASSERT(m_handle);
+		ANKI_ASSERT(m_range != 0);
+		return m_range;
+	}
+
+private:
+	ClassGpuAllocatorHandle m_handle;
+	PtrSize m_range = 0;
+};
+
+/// GPU memory allocator for GPU buffers used in transfer operations.
+class TransferGpuAllocator
+{
+public:
+	class ClassInf;
+
+	ANKI_USE_RESULT Bool allocate(PtrSize size, TransferGpuAllocatorHandle& handle);
+
+	void release(TransferGpuAllocatorHandle& handle, FencePtr fence);
+
+private:
+	class Memory;
+	class Interface;
+
+	ResourceAllocator<U8> m_alloc;
+	GrManager* m_gr = nullptr;
+
+	ClassGpuAllocatorInterface* m_interface = nullptr;
+	ClassGpuAllocator m_classAlloc;
+};
+/// @}
+
+} // end namespace anki

+ 0 - 13
src/anki/resource/TransferGpuMemoryAllocator.cpp

@@ -1,13 +0,0 @@
-// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <anki/resource/TransferGpuMemoryAllocator.h>
-
-namespace anki
-{
-
-// TODO
-
-} // end namespace anki

+ 15 - 0
src/anki/util/StdTypes.h

@@ -184,6 +184,21 @@ private:
 #else
 #else
 #define ANKI_DBG_NULLIFY
 #define ANKI_DBG_NULLIFY
 #endif
 #endif
+
+static constexpr unsigned long long int operator""_B(unsigned long long int x)
+{
+	return x;
+}
+
+static constexpr unsigned long long int operator""_KB(unsigned long long int x)
+{
+	return x * 1024;
+}
+
+static constexpr unsigned long long int operator""_MB(unsigned long long int x)
+{
+	return x * 1024 * 1024;
+}
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki