Browse Source

Add more D3D12 code

Panagiotis Christopoulos Charitos 1 year ago
parent
commit
b76a5ff27d

+ 74 - 11
AnKi/Gr/D3D/D3DCommandBuffer.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Gr/D3D/D3DCommandBuffer.h>
+#include <AnKi/Gr/D3D/D3DTexture.h>
 #include <AnKi/Util/Tracer.h>
 
 namespace anki {
@@ -23,7 +24,9 @@ CommandBuffer* CommandBuffer::newInstance(const CommandBufferInitInfo& init)
 
 void CommandBuffer::endRecording()
 {
-	ANKI_ASSERT(!"TODO");
+	ANKI_D3D_SELF(CommandBufferImpl);
+
+	self.m_cmdList->Close();
 }
 
 void CommandBuffer::bindVertexBuffer(U32 binding, const BufferView& buff, PtrSize stride, VertexStepRate stepRate)
@@ -176,6 +179,7 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 									const TextureView& vrsRt, U8 vrsRtTexelSizeX, U8 vrsRtTexelSizeY)
 {
 	ANKI_D3D_SELF(CommandBufferImpl);
+	self.commandCommon();
 
 	Array<D3D12_RENDER_PASS_RENDER_TARGET_DESC, kMaxColorRenderTargets> colorRtDescs;
 	for(U32 i = 0; i < colorRts.getSize(); ++i)
@@ -184,18 +188,40 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 		D3D12_RENDER_PASS_RENDER_TARGET_DESC& desc = colorRtDescs[i];
 
 		desc = {};
-		// desc.cpuDescriptor = rt.m_view->
+		desc.cpuDescriptor = static_cast<const TextureImpl&>(rt.m_textureView.getTexture())
+								 .getView(rt.m_textureView.getSubresource(), D3DTextureViewType::kRtv)
+								 .m_cpuHandle;
 		desc.BeginningAccess.Type = convertLoadOp(rt.m_loadOperation);
 		memcpy(&desc.BeginningAccess.Clear.ClearValue.Color, &rt.m_clearValue.m_colorf[0], sizeof(F32) * 4);
 		desc.EndingAccess.Type = convertStoreOp(rt.m_storeOperation);
 	}
 
-	// self.m_cmdList->BeginRenderPass(colorRts.getSize(), )
+	D3D12_RENDER_PASS_DEPTH_STENCIL_DESC dsDesc;
+	if(depthStencilRt)
+	{
+		dsDesc = {};
+		dsDesc.cpuDescriptor = static_cast<const TextureImpl&>(depthStencilRt->m_textureView.getTexture())
+								   .getView(depthStencilRt->m_textureView.getSubresource(), D3DTextureViewType::kDsv)
+								   .m_cpuHandle;
+
+		dsDesc.DepthBeginningAccess.Type = convertLoadOp(depthStencilRt->m_loadOperation);
+		dsDesc.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth, depthStencilRt->m_clearValue.m_depthStencil.m_depth;
+		dsDesc.DepthEndingAccess.Type = convertStoreOp(depthStencilRt->m_storeOperation);
+
+		dsDesc.StencilBeginningAccess.Type = convertLoadOp(depthStencilRt->m_stencilLoadOperation);
+		dsDesc.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = depthStencilRt->m_clearValue.m_depthStencil.m_stencil;
+		dsDesc.StencilEndingAccess.Type = convertStoreOp(depthStencilRt->m_stencilStoreOperation);
+	}
+
+	self.m_cmdList->BeginRenderPass(colorRts.getSize(), colorRtDescs.getBegin(), (depthStencilRt) ? &dsDesc : nullptr,
+									D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES);
 }
 
 void CommandBuffer::endRenderPass()
 {
-	ANKI_ASSERT(!"TODO");
+	ANKI_D3D_SELF(CommandBufferImpl);
+
+	self.m_cmdList->EndRenderPass();
 }
 
 void CommandBuffer::setVrsRate(VrsRate rate)
@@ -311,7 +337,35 @@ void CommandBuffer::upscale(GrUpscaler* upscaler, const TextureView& inColor, co
 void CommandBuffer::setPipelineBarrier(ConstWeakArray<TextureBarrierInfo> textures, ConstWeakArray<BufferBarrierInfo> buffers,
 									   ConstWeakArray<AccelerationStructureBarrierInfo> accelerationStructures)
 {
-	ANKI_ASSERT(!"TODO");
+	ANKI_D3D_SELF(CommandBufferImpl);
+	self.commandCommon();
+
+	DynamicArray<D3D12_RESOURCE_BARRIER, MemoryPoolPtrWrapper<StackMemoryPool>> resourceBarriers(self.m_fastPool);
+
+	for(const TextureBarrierInfo& barrier : textures)
+	{
+		const TextureImpl& impl = static_cast<const TextureImpl&>(barrier.m_textureView.getTexture());
+
+		D3D12_RESOURCE_BARRIER& d3dBarrier = *resourceBarriers.emplaceBack();
+		d3dBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+		d3dBarrier.Transition.pResource = &impl.getD3DResource();
+		d3dBarrier.Transition.Subresource = impl.calcD3DSubresourceIndex(barrier.m_textureView.getSubresource());
+		impl.computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, d3dBarrier.Transition.StateBefore, d3dBarrier.Transition.StateAfter);
+
+		if(d3dBarrier.Transition.StateBefore & D3D12_RESOURCE_STATE_UNORDERED_ACCESS
+		   && d3dBarrier.Transition.StateAfter & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)
+		{
+			D3D12_RESOURCE_BARRIER& d3dBarrier = *resourceBarriers.emplaceBack();
+			d3dBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
+			d3dBarrier.UAV.pResource = &impl.getD3DResource();
+		}
+	}
+
+	ANKI_ASSERT(buffers.getSize() == 0 && "TODO");
+	ANKI_ASSERT(accelerationStructures.getSize() == 0 && "TODO");
+
+	ANKI_ASSERT(resourceBarriers.getSize() > 0);
+	self.m_cmdList->ResourceBarrier(resourceBarriers.getSize(), resourceBarriers.getBegin());
 }
 
 void CommandBuffer::resetOcclusionQueries(ConstWeakArray<OcclusionQuery*> queries)
@@ -381,19 +435,28 @@ void CommandBuffer::popDebugMarker()
 
 CommandBufferImpl::~CommandBufferImpl()
 {
-	safeRelease(m_cmdList);
-	safeRelease(m_cmdAllocator);
 }
 
 Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 {
-	ANKI_D3D_CHECK(getDevice().CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_cmdAllocator)));
+	ANKI_CHECK(CommandBufferFactory::getSingleton().newCommandBuffer(init.m_flags, m_mcmdb));
 
-	ANKI_D3D_CHECK(getDevice().CreateCommandList(
-		0, !!(init.m_flags & CommandBufferFlag::kGeneralWork) ? D3D12_COMMAND_LIST_TYPE_DIRECT : D3D12_COMMAND_LIST_TYPE_COMPUTE, m_cmdAllocator,
-		nullptr, IID_PPV_ARGS(&m_cmdList)));
+	m_cmdList = &m_mcmdb->getCmdList();
+	m_fastPool = &m_mcmdb->getFastMemoryPool();
 
 	return Error::kNone;
 }
 
+void CommandBufferImpl::commandCommon()
+{
+	++m_commandCount;
+	if(m_commandCount >= kCommandBufferSmallBatchMaxCommands)
+	{
+		if((m_commandCount % 10) == 0) // Change the batch every 10 commands as an optimization
+		{
+			m_mcmdb->setBigBatch();
+		}
+	}
+}
+
 } // end namespace anki

+ 13 - 3
AnKi/Gr/D3D/D3DCommandBuffer.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <AnKi/Gr/CommandBuffer.h>
-#include <AnKi/Gr/D3D/D3DCommon.h>
+#include <AnKi/Gr/D3D/D3DCommandBufferFactory.h>
 
 namespace anki {
 
@@ -28,9 +28,19 @@ public:
 
 	Error init(const CommandBufferInitInfo& init);
 
+	MicroCommandBuffer& getMicroCommandBuffer()
+	{
+		return *m_mcmdb;
+	}
+
 private:
-	ID3D12CommandAllocator* m_cmdAllocator = nullptr;
-	ID3D12GraphicsCommandList7* m_cmdList = nullptr;
+	ID3D12GraphicsCommandList7* m_cmdList = nullptr; // Cache it.
+	U32 m_commandCount = 0;
+
+	StackMemoryPool* m_fastPool = nullptr; // Cache it.
+	MicroCommandBufferPtr m_mcmdb;
+
+	void commandCommon();
 };
 /// @}
 

+ 106 - 0
AnKi/Gr/D3D/D3DCommandBufferFactory.cpp

@@ -0,0 +1,106 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Gr/D3D/D3DCommandBufferFactory.h>
+#include <AnKi/Util/Tracer.h>
+
+namespace anki {
+
+MicroCommandBuffer::~MicroCommandBuffer()
+{
+	m_fastPool.destroy();
+
+	safeRelease(m_cmdList);
+	safeRelease(m_cmdAllocator);
+}
+
+Error MicroCommandBuffer::init(CommandBufferFlag flags)
+{
+	const D3D12_COMMAND_LIST_TYPE cmdListType =
+		!!(flags & CommandBufferFlag::kGeneralWork) ? D3D12_COMMAND_LIST_TYPE_DIRECT : D3D12_COMMAND_LIST_TYPE_COMPUTE;
+
+	ANKI_D3D_CHECK(getDevice().CreateCommandAllocator(cmdListType, IID_PPV_ARGS(&m_cmdAllocator)));
+
+	ComPtr<ID3D12GraphicsCommandList> cmdList;
+	ANKI_D3D_CHECK(getDevice().CreateCommandList(0, cmdListType, m_cmdAllocator, nullptr, IID_PPV_ARGS(&cmdList)));
+	ANKI_D3D_CHECK(cmdList->QueryInterface(IID_PPV_ARGS(&m_cmdList)));
+
+	return Error::kNone;
+}
+
+void MicroCommandBuffer::reset()
+{
+	ANKI_TRACE_SCOPED_EVENT(D3DCommandBufferReset);
+
+	ANKI_ASSERT(m_refcount.load() == 0);
+	ANKI_ASSERT(!m_fence.isCreated());
+
+	for(GrObjectType type : EnumIterable<GrObjectType>())
+	{
+		m_objectRefs[type].destroy();
+	}
+
+	m_fastPool.reset();
+
+	// Command list should already be reset on submit
+
+	m_cmdAllocator->Reset();
+
+	m_isSmallBatch = true;
+}
+
+void MicroCommandBufferPtrDeleter::operator()(MicroCommandBuffer* cmdb)
+{
+	if(cmdb)
+	{
+		CommandBufferFactory::getSingleton().deleteCommandBuffer(cmdb);
+	}
+}
+
+CommandBufferFactory::~CommandBufferFactory()
+{
+	for(U32 smallBatch = 0; smallBatch < 2; ++smallBatch)
+	{
+		for(GpuQueueType queue : EnumIterable<GpuQueueType>())
+		{
+			m_recyclers[smallBatch][queue].destroy();
+		}
+	}
+}
+
+void CommandBufferFactory::deleteCommandBuffer(MicroCommandBuffer* cmdb)
+{
+	ANKI_ASSERT(cmdb);
+
+	const Bool smallBatch = cmdb->m_isSmallBatch;
+	const GpuQueueType queue = (cmdb->m_cmdList->GetType() == D3D12_COMMAND_LIST_TYPE_DIRECT) ? GpuQueueType::kCompute : GpuQueueType::kCompute;
+
+	m_recyclers[smallBatch][queue].recycle(cmdb);
+}
+
+Error CommandBufferFactory::newCommandBuffer(CommandBufferFlag cmdbFlags, MicroCommandBufferPtr& ptr)
+{
+	const Bool smallBatch = !!(cmdbFlags & CommandBufferFlag::kSmallBatch);
+	const GpuQueueType queue = !!(cmdbFlags & CommandBufferFlag::kGeneralWork) ? GpuQueueType::kCompute : GpuQueueType::kCompute;
+
+	MicroCommandBuffer* cmdb = m_recyclers[smallBatch][queue].findToReuse();
+
+	if(cmdb == nullptr)
+	{
+		cmdb = newInstance<MicroCommandBuffer>(GrMemoryPool::getSingleton());
+		const Error err = cmdb->init(cmdbFlags);
+		if(err)
+		{
+			deleteInstance(GrMemoryPool::getSingleton(), cmdb);
+			cmdb = nullptr;
+			return err;
+		}
+	}
+
+	ptr.reset(cmdb);
+	return Error::kNone;
+}
+
+} // end namespace anki

+ 179 - 0
AnKi/Gr/D3D/D3DCommandBufferFactory.h

@@ -0,0 +1,179 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Gr/D3D/D3DFence.h>
+#include <AnKi/Gr/CommandBuffer.h>
+#include <AnKi/Gr/BackendCommon/MicroObjectRecycler.h>
+#include <AnKi/Util/List.h>
+
+namespace anki {
+
+/// @addtogroup directx
+/// @{
+
+/// Recycled object.
+class MicroCommandBuffer
+{
+	friend class CommandBufferFactory;
+
+public:
+	MicroCommandBuffer()
+	{
+		m_fastPool.init(GrMemoryPool::getSingleton().getAllocationCallback(), GrMemoryPool::getSingleton().getAllocationCallbackUserData(), 256_KB,
+						2.0f);
+
+		for(DynamicArray<GrObjectPtr, MemoryPoolPtrWrapper<StackMemoryPool>>& arr : m_objectRefs)
+		{
+			arr = DynamicArray<GrObjectPtr, MemoryPoolPtrWrapper<StackMemoryPool>>(&m_fastPool);
+		}
+	}
+
+	~MicroCommandBuffer();
+
+	Error init(CommandBufferFlag flags);
+
+	void retain() const
+	{
+		m_refcount.fetchAdd(1);
+	}
+
+	I32 release() const
+	{
+		return m_refcount.fetchSub(1);
+	}
+
+	I32 getRefcount() const
+	{
+		return m_refcount.load();
+	}
+
+	/// Interface method.
+	void onFenceDone()
+	{
+		reset();
+	}
+
+	void setFence(MicroFence* fence)
+	{
+		m_fence.reset(fence);
+	}
+
+	/// Interface method.
+	MicroFence* getFence() const
+	{
+		return m_fence.tryGet();
+	}
+
+	template<typename T>
+	void pushObjectRef(T* x)
+	{
+		ANKI_ASSERT(T::kClassType != GrObjectType::kTexture && T::kClassType != GrObjectType::kBuffer
+					&& "No need to push references of buffers and textures");
+		pushToArray(m_objectRefs[T::kClassType], x);
+	}
+
+	void setBigBatch()
+	{
+		m_isSmallBatch = false;
+	}
+
+	ID3D12GraphicsCommandList7& getCmdList() const
+	{
+		ANKI_ASSERT(m_cmdList);
+		return *m_cmdList;
+	}
+
+	StackMemoryPool& getFastMemoryPool()
+	{
+		return m_fastPool;
+	}
+
+	GpuQueueType getQueueType() const
+	{
+		return (m_cmdList->GetType() == D3D12_COMMAND_LIST_TYPE_COMPUTE) ? GpuQueueType::kCompute : GpuQueueType::kGeneral;
+	}
+
+	void resetCmdList()
+	{
+		m_cmdList->Reset(m_cmdAllocator, nullptr);
+	}
+
+private:
+	static constexpr U32 kMaxRefObjectSearch = 16;
+
+	mutable Atomic<I32> m_refcount = {0};
+	Bool m_isSmallBatch = true;
+
+	MicroFencePtr m_fence;
+	Array<DynamicArray<GrObjectPtr, MemoryPoolPtrWrapper<StackMemoryPool>>, U(GrObjectType::kCount)> m_objectRefs;
+
+	StackMemoryPool m_fastPool;
+
+	ID3D12CommandAllocator* m_cmdAllocator = nullptr;
+	ID3D12GraphicsCommandList7* m_cmdList = nullptr;
+
+	void reset();
+
+	static void pushToArray(DynamicArray<GrObjectPtr, MemoryPoolPtrWrapper<StackMemoryPool>>& arr, GrObject* grobj)
+	{
+		ANKI_ASSERT(grobj);
+
+		// Search the temp cache to avoid setting the ref again
+		if(arr.getSize() >= kMaxRefObjectSearch)
+		{
+			for(U32 i = arr.getSize() - kMaxRefObjectSearch; i < arr.getSize(); ++i)
+			{
+				if(arr[i].get() == grobj)
+				{
+					return;
+				}
+			}
+		}
+
+		// Not found in the temp cache, add it
+		arr.emplaceBack(grobj);
+	}
+};
+
+/// Deleter.
+class MicroCommandBufferPtrDeleter
+{
+public:
+	void operator()(MicroCommandBuffer* cmdb);
+};
+
+/// Micro command buffer pointer.
+using MicroCommandBufferPtr = IntrusivePtr<MicroCommandBuffer, MicroCommandBufferPtrDeleter>;
+
+/// Command bufffer object recycler.
+class CommandBufferFactory : public MakeSingleton<CommandBufferFactory>
+{
+	friend class MicroCommandBufferPtrDeleter;
+
+public:
+	CommandBufferFactory()
+	{
+	}
+
+	CommandBufferFactory(const CommandBufferFactory&) = delete; // Non-copyable
+
+	~CommandBufferFactory();
+
+	CommandBufferFactory& operator=(const CommandBufferFactory&) = delete; // Non-copyable
+
+	/// Request a new command buffer.
+	/// @note Thread-safe.
+	Error newCommandBuffer(CommandBufferFlag cmdbFlags, MicroCommandBufferPtr& ptr);
+
+private:
+	Array2d<MicroObjectRecycler<MicroCommandBuffer>, 2, U(GpuQueueType::kCount)> m_recyclers;
+
+	void deleteCommandBuffer(MicroCommandBuffer* cmdb);
+};
+/// @}
+
+} // end namespace anki

+ 22 - 2
AnKi/Gr/D3D/D3DCommon.h

@@ -62,8 +62,28 @@ namespace anki {
 		} \
 	} while(0)
 
-/// Backend specific constants
-constexpr U32 kMaxRtvDescriptors = 128;
+enum class D3DTextureViewType
+{
+	kSrv,
+	kRtv,
+	kDsv,
+	kUav,
+
+	kCount,
+	kFirst = 0
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(D3DTextureViewType)
+
+enum class D3DTextureBufferType
+{
+	kCbv,
+	kSrv,
+	kUav,
+
+	kCount,
+	kFirst = 0
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(D3DTextureBufferType)
 
 inline std::string ws2s(const std::wstring& wstr)
 {

+ 9 - 0
AnKi/Gr/D3D/D3DDescriptorHeap.h

@@ -23,6 +23,11 @@ public:
 #if ANKI_ASSERTIONS_ENABLED
 	DescriptorHeap* m_father = nullptr;
 #endif
+
+	[[nodiscard]] Bool isCreated() const
+	{
+		return m_cpuHandle.ptr != 0;
+	}
 };
 
 class DescriptorHeap
@@ -116,6 +121,10 @@ private:
 class RtvDescriptorHeap : public DescriptorHeap, public MakeSingleton<RtvDescriptorHeap>
 {
 };
+
+class CbvSrvUavDescriptorHeap : public DescriptorHeap, public MakeSingleton<CbvSrvUavDescriptorHeap>
+{
+};
 /// @}
 
 } // end namespace anki

+ 6 - 1
AnKi/Gr/D3D/D3DFence.cpp

@@ -19,11 +19,16 @@ MicroFence::MicroFence()
 	}
 }
 
-void MicroFence::signal(GpuQueueType queue)
+void MicroFence::gpuSignal(GpuQueueType queue)
 {
 	ANKI_D3D_CHECKF(getGrManagerImpl().getCommandQueue(queue).Signal(m_fence, m_value.fetchAdd(1) + 1));
 }
 
+void MicroFence::gpuWait(GpuQueueType queue)
+{
+	ANKI_D3D_CHECKF(getGrManagerImpl().getCommandQueue(queue).Wait(m_fence, m_value.load()));
+}
+
 Bool MicroFence::clientWait(Second seconds)
 {
 	Bool signaled = false;

+ 3 - 1
AnKi/Gr/D3D/D3DFence.h

@@ -53,7 +53,9 @@ public:
 		return cval == val;
 	}
 
-	void signal(GpuQueueType queue);
+	void gpuSignal(GpuQueueType queue);
+
+	void gpuWait(GpuQueueType queue);
 
 	Bool clientWait(Second seconds);
 

+ 72 - 8
AnKi/Gr/D3D/D3DGrManager.cpp

@@ -35,6 +35,10 @@ BoolCVar g_debugMarkersCVar(CVarSubsystem::kGr, "DebugMarkers", false, "Enable o
 BoolCVar g_meshShadersCVar(CVarSubsystem::kGr, "MeshShaders", false, "Enable or not mesh shaders");
 static NumericCVar<U8> g_deviceCVar(CVarSubsystem::kGr, "Device", 0, 0, 16, "Choose an available device. Devices are sorted by performance");
 
+static NumericCVar<U32> g_maxRtvDescriptors(CVarSubsystem::kGr, "MaxRvtDescriptors", 128, 8, 1024, "Max number of RTVs");
+static NumericCVar<U32> g_maxCbvSrvUavDescriptors(CVarSubsystem::kGr, "MaxCbvSrvUavDescriptors", 1024, 8, 1 * 1024 * 1024,
+												  "Max number of CBV/SRV/UAV descriptors");
+
 static LONG NTAPI vexHandler(PEXCEPTION_POINTERS exceptionInfo)
 {
 	PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
@@ -181,7 +185,7 @@ void GrManager::swapBuffers()
 	self.m_crntSwapchain->m_swapchain->Present((g_vsyncCVar.get()) ? 1 : 0, (g_vsyncCVar.get()) ? 0 : DXGI_PRESENT_ALLOW_TEARING);
 
 	MicroFencePtr presentFence = FenceFactory::getSingleton().newInstance();
-	presentFence->signal(GpuQueueType::kGeneral);
+	presentFence->gpuSignal(GpuQueueType::kGeneral);
 
 	auto& crntFrame = self.m_frames[self.m_crntFrame];
 
@@ -208,7 +212,7 @@ void GrManager::finish()
 #define ANKI_NEW_GR_OBJECT(type) \
 	type##Ptr GrManager::new##type(const type##InitInfo& init) \
 	{ \
-		type##Ptr ptr(nullptr); \
+		type##Ptr ptr(type::newInstance(init)); \
 		if(!ptr.isCreated()) [[unlikely]] \
 		{ \
 			ANKI_D3D_LOGF("Failed to create a " ANKI_STRINGIZE(type) " object"); \
@@ -219,7 +223,7 @@ void GrManager::finish()
 #define ANKI_NEW_GR_OBJECT_NO_INIT_INFO(type) \
 	type##Ptr GrManager::new##type() \
 	{ \
-		type##Ptr ptr(nullptr); \
+		type##Ptr ptr(type::newInstance()); \
 		if(!ptr.isCreated()) [[unlikely]] \
 		{ \
 			ANKI_D3D_LOGF("Failed to create a " ANKI_STRINGIZE(type) " object"); \
@@ -249,7 +253,57 @@ GrManagerImpl::~GrManagerImpl()
 
 void GrManager::submit(WeakArray<CommandBuffer*> cmdbs, WeakArray<Fence*> waitFences, FencePtr* signalFence)
 {
-	ANKI_ASSERT(!"TODO");
+	ANKI_D3D_SELF(GrManagerImpl);
+
+	// First thing, create a fence
+	MicroFencePtr fence = FenceFactory::getSingleton().newInstance();
+
+	// Gather command lists
+	GrDynamicArray<ID3D12CommandList*> d3dCmdLists;
+	d3dCmdLists.resizeStorage(cmdbs.getSize());
+	GpuQueueType queueType = GpuQueueType::kCount;
+	for(CommandBuffer* cmdb : cmdbs)
+	{
+		CommandBufferImpl& impl = static_cast<CommandBufferImpl&>(*cmdb);
+		MicroCommandBuffer& mcmdb = impl.getMicroCommandBuffer();
+
+		d3dCmdLists.emplaceBack(&mcmdb.getCmdList());
+		if(queueType == GpuQueueType::kCount)
+		{
+			queueType = mcmdb.getQueueType();
+		}
+		else
+		{
+			ANKI_ASSERT(queueType == mcmdb.getQueueType());
+		}
+
+		mcmdb.setFence(fence.get());
+	}
+
+	// Wait for fences
+	for(Fence* fence : waitFences)
+	{
+		FenceImpl& impl = static_cast<FenceImpl&>(*fence);
+		impl.m_fence->gpuWait(queueType);
+	}
+
+	// Submit command lists
+	self.m_queues[queueType]->ExecuteCommandLists(d3dCmdLists.getSize(), d3dCmdLists.getBegin());
+
+	// Rest command lists
+	for(CommandBuffer* cmdb : cmdbs)
+	{
+		static_cast<CommandBufferImpl&>(*cmdb).getMicroCommandBuffer().resetCmdList();
+	}
+
+	// Signal fence
+	fence->gpuSignal(queueType);
+
+	if(signalFence)
+	{
+		FenceImpl* fenceImpl = anki::newInstance<FenceImpl>(GrMemoryPool::getSingleton(), "SignalFence");
+		fenceImpl->m_fence = fence;
+	}
 }
 
 Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
@@ -372,15 +426,23 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	}
 
 	// Limits
-	m_limits.m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+	const U32 rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+	const U32 cbvSrvUavDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
 
 	// Other systems
 	RtvDescriptorHeap::allocateSingleton();
-	ANKI_CHECK(RtvDescriptorHeap::getSingleton().init(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, kMaxRtvDescriptors,
-													  m_limits.m_rtvDescriptorSize));
+	ANKI_CHECK(RtvDescriptorHeap::getSingleton().init(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, g_maxRtvDescriptors.get(),
+													  rtvDescriptorSize));
+
+	CbvSrvUavDescriptorHeap::allocateSingleton();
+	ANKI_CHECK(CbvSrvUavDescriptorHeap::getSingleton().init(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
+															g_maxCbvSrvUavDescriptors.get(), cbvSrvUavDescriptorSize));
 
 	SwapchainFactory::allocateSingleton();
+	m_crntSwapchain = SwapchainFactory::getSingleton().newInstance();
+
 	FenceFactory::allocateSingleton();
+	CommandBufferFactory::allocateSingleton();
 
 	return Error::kNone;
 }
@@ -389,8 +451,10 @@ void GrManagerImpl::destroy()
 {
 	ANKI_D3D_LOGI("Destroying D3D backend");
 
-	SwapchainFactory::freeSingleton();
+	CommandBufferFactory::freeSingleton();
 	RtvDescriptorHeap::freeSingleton();
+	CbvSrvUavDescriptorHeap::freeSingleton();
+	SwapchainFactory::freeSingleton();
 	FenceFactory::freeSingleton();
 
 	safeRelease(m_queues[GpuQueueType::kGeneral]);

+ 0 - 13
AnKi/Gr/D3D/D3DGrManager.h

@@ -15,12 +15,6 @@ namespace anki {
 /// @addtogroup directx
 /// @{
 
-class Limits
-{
-public:
-	U32 m_rtvDescriptorSize = 0;
-};
-
 /// DX implementation of GrManager.
 class GrManagerImpl : public GrManager
 {
@@ -40,11 +34,6 @@ public:
 		return *m_device;
 	}
 
-	const Limits& getLimits() const
-	{
-		return m_limits;
-	}
-
 	ID3D12CommandQueue& getCommandQueue(GpuQueueType q)
 	{
 		ANKI_ASSERT(m_queues[q]);
@@ -72,8 +61,6 @@ private:
 	Array<PerFrame, kMaxFramesInFlight> m_frames;
 	U8 m_crntFrame = 0;
 
-	Limits m_limits;
-
 	void destroy();
 };
 /// @}

+ 123 - 5
AnKi/Gr/D3D/D3DTexture.cpp

@@ -28,9 +28,35 @@ U32 Texture::getOrCreateBindlessTextureIndex(const TextureSubresourceDescriptor&
 
 TextureImpl::~TextureImpl()
 {
-	for(DescriptorHeapHandle& handle : m_rtvHandles)
+	auto deleteView = [](TextureViewEntry& entry, D3DTextureViewType type) {
+		DescriptorHeap* heap = nullptr;
+		switch(type)
+		{
+		case D3DTextureViewType::kSrv:
+		case D3DTextureViewType::kUav:
+			heap = &CbvSrvUavDescriptorHeap::getSingleton();
+			break;
+		case D3DTextureViewType::kRtv:
+			heap = &RtvDescriptorHeap::getSingleton();
+			break;
+		case D3DTextureViewType::kDsv:
+			heap = nullptr;
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
+
+		heap->free(entry.m_handle);
+	};
+
+	for(D3DTextureViewType c : EnumIterable<D3DTextureViewType>())
 	{
-		RtvDescriptorHeap::getSingleton().free(handle);
+		for(TextureViewEntry& entry : m_singleSurfaceOrVolumeViews[c])
+		{
+			deleteView(entry, c);
+		}
+
+		deleteView(m_wholeTextureViews[c], c);
 	}
 
 	const Bool external = !!(m_usage & TextureUsageBit::kPresent);
@@ -71,7 +97,7 @@ Error TextureImpl::initInternal(ID3D12Resource* external, const TextureInitInfo&
 		ANKI_ASSERT(!"TODO");
 	}
 
-	const U32 faceCount = (m_texType == TextureType::kCube || m_texType == TextureType::kCubeArray) ? 6 : 1;
+	const U32 faceCount = textureTypeIsCube(m_texType) ? 6 : 1;
 	U32 surfaceCount = 0;
 	if(m_texType != TextureType::k3D)
 	{
@@ -82,7 +108,10 @@ Error TextureImpl::initInternal(ID3D12Resource* external, const TextureInitInfo&
 	if(!!(m_usage & TextureUsageBit::kAllFramebuffer))
 	{
 		ANKI_ASSERT(m_texType != TextureType::k3D && m_texType != TextureType::k1D);
-		m_rtvHandles.resize(surfaceCount);
+		ANKI_ASSERT(!getFormatInfo(m_format).isDepthStencil() && "TODO");
+
+		m_singleSurfaceOrVolumeViews[D3DTextureViewType::kRtv].resize(surfaceCount);
+
 		for(U32 layer = 0; layer < m_layerCount; ++layer)
 		{
 			for(U32 face = 0; face < faceCount; ++face)
@@ -104,7 +133,8 @@ Error TextureImpl::initInternal(ID3D12Resource* external, const TextureInitInfo&
 						desc.Texture2DArray.FirstArraySlice = layer * m_layerCount + face;
 					}
 
-					DescriptorHeapHandle& handle = m_rtvHandles[layer * faceCount * m_mipCount + face * m_mipCount + mip];
+					DescriptorHeapHandle& handle =
+						m_singleSurfaceOrVolumeViews[D3DTextureViewType::kRtv][layer * faceCount * m_mipCount + face * m_mipCount + mip].m_handle;
 					handle = RtvDescriptorHeap::getSingleton().allocate();
 					getDevice().CreateRenderTargetView(m_resource, (external) ? nullptr : &desc, handle.m_cpuHandle);
 				}
@@ -115,4 +145,92 @@ Error TextureImpl::initInternal(ID3D12Resource* external, const TextureInitInfo&
 	return Error::kNone;
 }
 
+const TextureImpl::TextureViewEntry& TextureImpl::getViewEntry(const TextureSubresourceDescriptor& subresource, D3DTextureViewType viewType) const
+{
+	const TextureView view(this, subresource);
+	const U32 faceCount = textureTypeIsCube(m_texType) ? 6 : 1;
+
+	const TextureViewEntry* entry;
+	if(viewType == D3DTextureViewType::kRtv)
+	{
+		ANKI_ASSERT(view.isGoodForRenderTarget());
+		const U32 idx = subresource.m_layer * faceCount * m_mipCount + subresource.m_face * m_mipCount + subresource.m_mipmap;
+		entry = &m_singleSurfaceOrVolumeViews[D3DTextureViewType::kRtv][idx];
+	}
+	else
+	{
+		ANKI_ASSERT(!"TODO");
+	}
+
+	ANKI_ASSERT(entry);
+	return *entry;
+}
+
+void TextureImpl::computeResourceStates(TextureUsageBit usage, D3D12_RESOURCE_STATES& states) const
+{
+	ANKI_ASSERT((usage & m_usage) == usage);
+
+	if(usage == TextureUsageBit::kNone)
+	{
+		// D3D doesn't have a clean slade, figure something out
+
+		states |= D3D12_RESOURCE_STATE_COMMON;
+	}
+	else
+	{
+		states = D3D12_RESOURCE_STATES(0);
+		if(!!(usage & TextureUsageBit::kAllFramebuffer))
+		{
+			states |= D3D12_RESOURCE_STATE_RENDER_TARGET;
+
+			if(!!(usage & TextureUsageBit::kFramebufferWrite) && !!(m_aspect & DepthStencilAspectBit::kDepth))
+			{
+				states |= D3D12_RESOURCE_STATE_DEPTH_WRITE;
+			}
+
+			if(!!(usage & TextureUsageBit::kFramebufferRead) && !!(m_aspect & DepthStencilAspectBit::kDepth))
+			{
+				states |= D3D12_RESOURCE_STATE_DEPTH_READ;
+			}
+		}
+
+		if(!!(usage & TextureUsageBit::kAllStorage))
+		{
+			states |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+		}
+
+		if(!!(usage & TextureUsageBit::kSampledFragment))
+		{
+			states |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+		}
+
+		if(!!(usage & (TextureUsageBit::kAllSampled & ~TextureUsageBit::kSampledFragment)))
+		{
+			states |= D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+		}
+
+		if(!!(usage & TextureUsageBit::kTransferDestination))
+		{
+			states |= D3D12_RESOURCE_STATE_COPY_DEST;
+		}
+
+		if(!!(usage & TextureUsageBit::kFramebufferShadingRate))
+		{
+			states |= D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE;
+		}
+
+		if(!!(usage & TextureUsageBit::kPresent))
+		{
+			states |= D3D12_RESOURCE_STATE_PRESENT;
+		}
+	}
+}
+
+void TextureImpl::computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, D3D12_RESOURCE_STATES& statesBefore,
+									 D3D12_RESOURCE_STATES& statesAfter) const
+{
+	computeResourceStates(before, statesBefore);
+	computeResourceStates(after, statesAfter);
+}
+
 } // end namespace anki

+ 50 - 1
AnKi/Gr/D3D/D3DTexture.h

@@ -36,11 +36,60 @@ public:
 		return initInternal(external, init);
 	}
 
+	const DescriptorHeapHandle& getView(const TextureSubresourceDescriptor& subresource, D3DTextureViewType viewType) const
+	{
+		const TextureViewEntry& e = getViewEntry(subresource, viewType);
+		ANKI_ASSERT(e.m_handle.isCreated());
+		return e.m_handle;
+	}
+
+	U32 calcD3DSubresourceIndex(const TextureSubresourceDescriptor& subresource) const
+	{
+		const TextureView view(this, subresource);
+		if(view.isAllSurfacesOrVolumes() && view.getDepthStencilAspect() == m_aspect)
+		{
+			return D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+		}
+		else
+		{
+			const U32 faceCount = textureTypeIsCube(m_texType);
+			const U32 arraySize = faceCount * m_layerCount;
+			const U32 arraySlice = view.getFirstLayer() * faceCount + view.getFirstFace();
+			const U32 planeSlice =
+				(m_aspect == DepthStencilAspectBit::kDepthStencil && view.getDepthStencilAspect() == DepthStencilAspectBit::kStencil) ? 1 : 0;
+			return view.getFirstMipmap() + (arraySlice * m_mipCount) + (planeSlice * m_mipCount * arraySize);
+		}
+	}
+
+	/// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier.
+	void computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, D3D12_RESOURCE_STATES& statesBefore,
+							D3D12_RESOURCE_STATES& statesAfter) const;
+
+	ID3D12Resource& getD3DResource() const
+	{
+		return *m_resource;
+	}
+
 private:
+	class TextureViewEntry
+	{
+	public:
+		DescriptorHeapHandle m_handle;
+
+		mutable U32 m_bindlessIndex = kMaxU32;
+		mutable SpinLock m_bindlessIndexLock;
+	};
+
 	ID3D12Resource* m_resource = nullptr;
-	GrDynamicArray<DescriptorHeapHandle> m_rtvHandles;
+
+	Array<GrDynamicArray<TextureViewEntry>, U32(D3DTextureViewType::kCount)> m_singleSurfaceOrVolumeViews;
+	Array<TextureViewEntry, U32(D3DTextureViewType::kCount)> m_wholeTextureViews;
 
 	Error initInternal(ID3D12Resource* external, const TextureInitInfo& init);
+
+	const TextureViewEntry& getViewEntry(const TextureSubresourceDescriptor& subresource, D3DTextureViewType viewType) const;
+
+	void computeResourceStates(TextureUsageBit usage, D3D12_RESOURCE_STATES& states) const;
 };
 /// @}
 

+ 16 - 7
AnKi/Gr/Texture.h

@@ -382,22 +382,31 @@ public:
 	{
 		validate();
 		/// Can bound only one aspect at a time.
-		return m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kDepth
-			   || m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kStencil
-			   || m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kNone;
+		return (m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kDepth
+				|| m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kStencil
+				|| m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kNone)
+			   && !!(m_tex->getTextureUsage() & TextureUsageBit::kAllSampled);
 	}
 
-	/// Return true if the subresource can be used in CommandBuffer::copyBufferToTextureView.
-	[[nodiscard]] Bool isGoodForCopyFromBuffer() const
+	/// Return true if the subresource can be used in CommandBuffer::copyBufferToTexture.
+	[[nodiscard]] Bool isGoodForCopyBufferToTexture() const
 	{
 		validate();
-		return isSingleSurfaceOrVolume() && m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kNone;
+		return isSingleSurfaceOrVolume() && m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kNone
+			   && !!(m_tex->getTextureUsage() & TextureUsageBit::kTransferDestination);
 	}
 
 	[[nodiscard]] Bool isGoodForStorage() const
 	{
 		validate();
-		return isSingleSurfaceOrVolume() && m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kNone;
+		return isSingleSurfaceOrVolume() && m_subresource.m_depthStencilAspect == DepthStencilAspectBit::kNone
+			   && !!(m_tex->getTextureUsage() & TextureUsageBit::kAllStorage);
+	}
+
+	[[nodiscard]] Bool isGoodForRenderTarget() const
+	{
+		validate();
+		return isSingleSurfaceOrVolume() && !!(m_tex->getTextureUsage() & TextureUsageBit::kAllFramebuffer);
 	}
 
 	/// Returns true if there is a surface or volume that overlaps. It doesn't check the aspect.

+ 6 - 25
Tests/Framework/Framework.cpp

@@ -235,44 +235,25 @@ void deleteTesterSingleton()
 	delete g_testerInstance;
 }
 
-NativeWindow* createWindow()
+void initWindow()
 {
 	NativeWindowInitInfo inf;
 	inf.m_width = g_windowWidthCVar.get();
 	inf.m_height = g_windowHeightCVar.get();
 	inf.m_title = "AnKi unit tests";
 	NativeWindow* win = &NativeWindow::allocateSingleton();
-	const Error err = NativeWindow::getSingleton().init(inf);
-	if(err)
-	{
-		NativeWindow::freeSingleton();
-		return nullptr;
-	}
-
-	return win;
+	ANKI_TEST_EXPECT_NO_ERR(NativeWindow::getSingleton().init(inf));
 }
 
-GrManager* createGrManager(NativeWindow* win)
+void initGrManager()
 {
 	GrManagerInitInfo inf;
 	inf.m_allocCallback = allocAligned;
 	String home;
-	const Error err = getTempDirectory(home);
-	if(err)
-	{
-		return nullptr;
-	}
+	ANKI_TEST_EXPECT_NO_ERR(getTempDirectory(home));
 	inf.m_cacheDirectory = home;
-	GrManager* gr = &GrManager::allocateSingleton();
-	ANKI_TEST_EXPECT_NO_ERR(gr->init(inf));
-
-	return gr;
-}
-
-ResourceManager* createResourceManager(GrManager* gr)
-{
-	ANKI_TEST_EXPECT_NO_ERR(ResourceManager::allocateSingleton().init(allocAligned, nullptr));
-	return &ResourceManager::getSingleton();
+	GrManager::allocateSingleton();
+	ANKI_TEST_EXPECT_NO_ERR(GrManager::getSingleton().init(inf));
 }
 
 } // end namespace anki

+ 2 - 4
Tests/Framework/Framework.h

@@ -221,11 +221,9 @@ extern void deleteTesterSingleton();
 /// Check error code.
 #define ANKI_TEST_EXPECT_ERR(x_, y_) ANKI_TEST_EXPECT_EQ_IMPL(__FILE__, __LINE__, __func__, x_, y_)
 
-NativeWindow* createWindow();
+void initWindow();
 
-GrManager* createGrManager(NativeWindow* win);
-
-ResourceManager* createResourceManager(GrManager* gr);
+void initGrManager();
 
 /// Stolen from https://en.cppreference.com/w/cpp/algorithm/random_shuffle because std::random_suffle got deprecated
 template<class TRandomIt>

+ 56 - 451
Tests/Gr/Gr.cpp

@@ -20,371 +20,30 @@
 
 using namespace anki;
 
-const U WIDTH = 1024;
-const U HEIGHT = 768;
+const U kWidth = 1024;
+const U kHeight = 768;
 
-static const char* VERT_QUAD_STRIP_SRC = R"(
-out gl_PerVertex
-{
-	vec4 gl_Position;
-};
-
-layout(location = 0) out Vec2 out_uv;
-
-void main()
-{
-	const vec2 POSITIONS[4] = vec2[](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0));
-	gl_Position = vec4(POSITIONS[gl_VertexID % 4], 0.0, 1.0);
-	out_uv = gl_Position.xy / 2.0 + 0.5;
-})";
-
-static const char* VERT_UBO_SRC = R"(
-out gl_PerVertex
-{
-	vec4 gl_Position;
-};
-
-layout(set = 0, binding = 0) uniform u0_
-{
-	vec4 u_color[3];
-};
-
-layout(set = 0, binding = 1) uniform u1_
-{
-	vec4 u_rotation2d;
-};
-
-layout(location = 0) out vec3 out_color;
-
-void main()
-{
-	out_color = u_color[gl_VertexID].rgb;
-
-	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, 1.0), vec2(0.0, -1.0), vec2(1.0, 1.0));
-
-	mat2 rot = mat2(
-		u_rotation2d.x, u_rotation2d.y, u_rotation2d.z, u_rotation2d.w);
-	vec2 pos = rot * POSITIONS[gl_VertexID % 3];
-
-	gl_Position = vec4(pos, 0.0, 1.0);
-})";
-
-static const char* VERT_INP_SRC = R"(
-layout(location = 0) in vec3 in_position;
-layout(location = 1) in vec3 in_color0;
-layout(location = 2) in vec3 in_color1;
-
-out gl_PerVertex
-{
-	vec4 gl_Position;
-};
-
-layout(location = 0) out vec3 out_color0;
-layout(location = 1) out vec3 out_color1;
-
-void main()
-{
-	gl_Position = vec4(in_position, 1.0);
-
-	out_color0 = in_color0;
-	out_color1 = in_color1;
-})";
-
-static const char* VERT_QUAD_SRC = R"(
-out gl_PerVertex
-{
-	vec4 gl_Position;
-};
-
-layout(location = 0) out vec2 out_uv;
-
-void main()
-{
-	const vec2 POSITIONS[6] =
-		vec2[](vec2(-1.0, 1.0), vec2(-1.0, -1.0), vec2(1.0, -1.0),
-		vec2(1.0, -1.0), vec2(1.0, 1.0), vec2(-1.0, 1.0));
-
-	gl_Position = vec4(POSITIONS[gl_VertexID], 0.0, 1.0);
-	out_uv = POSITIONS[gl_VertexID] / 2.0 + 0.5;
-})";
-
-static const char* VERT_MRT_SRC = R"(
-out gl_PerVertex
-{
-	vec4 gl_Position;
-};
-
-layout(location = 0) in vec3 in_pos;
-
-layout(set = 0, binding = 0, std140, row_major) uniform u0_
-{
-	mat4 u_mvp;
-};
-
-void main()
-{
-	gl_Position = u_mvp * vec4(in_pos, 1.0);
-})";
-
-static const char* FRAG_UBO_SRC = R"(layout (location = 0) out vec4 out_color;
-
-layout(location = 0) in vec3 in_color;
-
-void main()
-{
-	out_color = vec4(in_color, 1.0);
-})";
-
-static const char* FRAG_INP_SRC = R"(layout (location = 0) out vec4 out_color;
-
-layout(location = 0) in vec3 in_color0;
-layout(location = 1) in vec3 in_color1;
-
-void main()
-{
-	out_color = vec4(in_color0 + in_color1, 1.0);
-})";
-
-static const char* FRAG_TEX_SRC = R"(layout (location = 0) out vec4 out_color;
-
-layout(location = 0) in vec2 in_uv;
-
-layout(set = 0, binding = 0) uniform sampler2D u_tex0;
-
-void main()
-{
-	out_color = texture(u_tex0, in_uv);
-})";
-
-static const char* FRAG_TEX3D_SRC = R"(layout (location = 0) out vec4 out_color;
-
-layout(set = 0, binding = 0) uniform u0_
-{
-	vec4 u_uv;
-};
-
-layout(set = 0, binding = 1) uniform sampler3D u_tex;
-
-void main()
-{
-	out_color = textureLod(u_tex, u_uv.xyz, u_uv.w);
-})";
-
-static const char* FRAG_MRT_SRC = R"(layout (location = 0) out vec4 out_color0;
-layout (location = 1) out vec4 out_color1;
-
-layout(set = 0, binding = 1, std140) uniform u1_
-{
-	vec4 u_color0;
-	vec4 u_color1;
-};
-
-void main()
+static void commonInit()
 {
-	out_color0 = u_color0;
-	out_color1 = u_color1;
-})";
-
-static const char* FRAG_MRT2_SRC = R"(layout (location = 0) out vec4 out_color;
-
-layout(location = 0) in vec2 in_uv;
-
-layout(set = 0, binding = 0) uniform sampler2D u_tex0;
-layout(set = 0, binding = 2) uniform sampler2D u_tex1;
-
-void main()
-{
-	vec2 uv = in_uv;
-#ifdef ANKI_VK
-	uv.y = 1.0 - uv.y;
-#endif
-	float factor = uv.x;
-	vec3 col0 = texture(u_tex0, uv).rgb;
-	vec3 col1 = texture(u_tex1, uv).rgb;
-
-	out_color = vec4(col1 + col0, 1.0);
-})";
-
-static const char* FRAG_SIMPLE_TEX_SRC = R"(
-layout (location = 0) out vec4 out_color;
-layout(location = 0) in vec2 in_uv;
-layout(set = 0, binding = 0) uniform sampler2D u_tex0;
-
-void main()
-{
-	out_color = textureLod(u_tex0, in_uv, 1.0);
-})";
-
-static const char* COMP_WRITE_IMAGE_SRC = R"(
-layout(set = 0, binding = 0, rgba8) writeonly uniform image2D u_img;
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-
-layout(set = 1, binding = 0) buffer ss1_
-{
-	vec4 u_color;
-};
-
-void main()
-{
-	imageStore(u_img, ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y), u_color);
-})";
-
-static NativeWindow* g_win = nullptr;
-static GrManager* g_gr = nullptr;
-static RebarTransientMemoryPool* stagingMem = nullptr;
-static Input* input = nullptr;
-
-#define COMMON_BEGIN() \
-	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr); \
-	ShaderCompilerMemoryPool::allocateSingleton(allocAligned, nullptr); \
-	g_windowWidthCVar.set(WIDTH); \
-	g_windowHeightCVar.set(HEIGHT); \
-	g_validationCVar.set(true); \
-	g_vsyncCVar.set(false); \
-	g_debugMarkersCVar.set(true); \
-	g_win = createWindow(); \
-	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init()); \
-	g_gr = createGrManager(g_win); \
-	RebarTransientMemoryPool::allocateSingleton().init(); \
-	stagingMem = &RebarTransientMemoryPool::getSingleton(); \
-	TransferGpuAllocator* transfAlloc = new TransferGpuAllocator(); \
-	ANKI_TEST_EXPECT_NO_ERR(transfAlloc->init(128_MB)); \
-	while(true) \
-	{
-
-#define COMMON_END() \
-	break; \
-	} \
-	g_gr->finish(); \
-	delete transfAlloc; \
-	RebarTransientMemoryPool::freeSingleton(); \
-	GrManager::freeSingleton(); \
-	Input::freeSingleton(); \
-	NativeWindow::freeSingleton(); \
-	ShaderCompilerMemoryPool::freeSingleton(); \
-	DefaultMemoryPool::freeSingleton(); \
-	g_win = nullptr; \
-	g_gr = nullptr;
-
-static void* setUniforms(PtrSize size, CommandBufferPtr& cmdb, U32 set, U32 binding)
-{
-	void* ptr;
-	const RebarAllocation token = stagingMem->allocateFrame(size, ptr);
-	cmdb->bindUniformBuffer(set, binding, token);
-	return ptr;
-}
-
-static void* setStorage(PtrSize size, CommandBufferPtr& cmdb, U32 set, U32 binding)
-{
-	void* ptr;
-	const RebarAllocation token = stagingMem->allocateFrame(size, ptr);
-	cmdb->bindStorageBuffer(set, binding, token);
-	return ptr;
-}
-
-#define SET_UNIFORMS(type_, size_, cmdb_, set_, binding_) static_cast<type_>(setUniforms(size_, cmdb_, set_, binding_))
-#define SET_STORAGE(type_, size_, cmdb_, set_, binding_) static_cast<type_>(setStorage(size_, cmdb_, set_, binding_))
-
-#define UPLOAD_TEX_SURFACE(cmdb_, tex_, surf_, ptr_, size_, handle_) \
-	do \
-	{ \
-		ANKI_TEST_EXPECT_NO_ERR(transfAlloc->allocate(size_, handle_)); \
-		void* f = handle_.getMappedMemory(); \
-		memcpy(f, ptr_, size_); \
-		TextureViewPtr view = g_gr->newTextureView(TextureViewInitInfo(tex_.get(), surf_)); \
-		cmdb_->copyBufferToTextureView(&handle_.getBuffer(), handle_.getOffset(), handle_.getRange(), view.get()); \
-	} while(0)
-
-#define UPLOAD_TEX_VOL(cmdb_, tex_, vol_, ptr_, size_, handle_) \
-	do \
-	{ \
-		ANKI_TEST_EXPECT_NO_ERR(transfAlloc->allocate(size_, handle_)); \
-		void* f = handle_.getMappedMemory(); \
-		memcpy(f, ptr_, size_); \
-		TextureViewPtr view = g_gr->newTextureView(TextureViewInitInfo(tex_.get(), vol_)); \
-		cmdb_->copyBufferToTextureView(&handle_.getBuffer(), handle_.getOffset(), handle_.getRange(), view.get()); \
-	} while(0)
-
-constexpr Format kDsFormat = Format::kD24_Unorm_S8_Uint;
-
-static ShaderProgramPtr createProgram(CString vertSrc, CString fragSrc, GrManager& gr)
-{
-	ShaderPtr vert = createShader(vertSrc, ShaderType::kVertex, gr);
-	ShaderPtr frag = createShader(fragSrc, ShaderType::kFragment, gr);
-	ShaderProgramInitInfo inf;
-	inf.m_graphicsShaders[ShaderType::kVertex] = vert.get();
-	inf.m_graphicsShaders[ShaderType::kFragment] = frag.get();
-	return gr.newShaderProgram(inf);
-}
-
-static void createCube(GrManager& gr, BufferPtr& verts, BufferPtr& indices)
-{
-	static const Array<F32, 8 * 3> pos = {{1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1}};
-
-	static const Array<U16, 6 * 2 * 3> idx = {
-		{0, 1, 3, 3, 1, 2, 1, 5, 6, 1, 6, 2, 7, 4, 0, 7, 0, 3, 6, 5, 7, 7, 5, 4, 0, 4, 5, 0, 5, 1, 3, 2, 6, 3, 6, 7}};
-
-	verts = gr.newBuffer(BufferInitInfo(sizeof(pos), BufferUsageBit::kVertex, BufferMapAccessBit::kWrite));
-
-	void* mapped = verts->map(0, sizeof(pos), BufferMapAccessBit::kWrite);
-	memcpy(mapped, &pos[0], sizeof(pos));
-	verts->unmap();
-
-	indices = gr.newBuffer(BufferInitInfo(sizeof(idx), BufferUsageBit::kIndex, BufferMapAccessBit::kWrite));
-	mapped = indices->map(0, sizeof(idx), BufferMapAccessBit::kWrite);
-	memcpy(mapped, &idx[0], sizeof(idx));
-	indices->unmap();
-}
-
-static void presentBarrierA(CommandBufferPtr cmdb, TexturePtr presentTex)
-{
-	TextureBarrierInfo barrier;
-	barrier.m_previousUsage = TextureUsageBit::kNone;
-	barrier.m_nextUsage = TextureUsageBit::kFramebufferWrite;
-	barrier.m_textureView = TextureView(presentTex.get(), TextureSubresourceDescriptor::all());
-	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
-}
-
-static void presentBarrierB(CommandBufferPtr cmdb, TexturePtr presentTex)
-{
-	TextureBarrierInfo barrier;
-	barrier.m_previousUsage = TextureUsageBit::kFramebufferWrite;
-	barrier.m_nextUsage = TextureUsageBit::kPresent;
-	barrier.m_textureView = TextureView(presentTex.get(), TextureSubresourceDescriptor::all());
-	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
-}
-
-static void setTextureBarrier(CommandBufferPtr& cmdb, TexturePtr tex, TextureUsageBit before, TextureUsageBit after,
-							  const TextureSubresourceDescriptor& surf)
-{
-	TextureBarrierInfo barrier;
-	barrier.m_previousUsage = before;
-	barrier.m_nextUsage = after;
-	barrier.m_textureView = TextureView(tex.get(), surf);
-
-	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
-}
-
-static void setBufferBarrier(CommandBufferPtr cmdb, BufferPtr buffer, BufferUsageBit before, BufferUsageBit after, PtrSize offset, PtrSize range)
-{
-	BufferBarrierInfo barrier;
-	barrier.m_previousUsage = before;
-	barrier.m_nextUsage = after;
-	barrier.m_bufferView = BufferView(buffer.get(), offset, range);
-
-	cmdb->setPipelineBarrier({}, {&barrier, 1}, {});
+	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
+	ShaderCompilerMemoryPool::allocateSingleton(allocAligned, nullptr);
+	g_windowWidthCVar.set(kWidth);
+	g_windowHeightCVar.set(kHeight);
+	g_validationCVar.set(true);
+	g_vsyncCVar.set(false);
+	g_debugMarkersCVar.set(true);
+	initWindow();
+	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init());
+	initGrManager();
 }
 
-static void setAccelerationStructureBarrier(CommandBufferPtr cmdb, AccelerationStructurePtr as, AccelerationStructureUsageBit before,
-											AccelerationStructureUsageBit after)
+static void commonDestroy()
 {
-	AccelerationStructureBarrierInfo barrier;
-	barrier.m_previousUsage = before;
-	barrier.m_nextUsage = after;
-	barrier.m_as = as.get();
-
-	cmdb->setPipelineBarrier({}, {}, {&barrier, 1});
+	GrManager::freeSingleton();
+	Input::freeSingleton();
+	NativeWindow::freeSingleton();
+	ShaderCompilerMemoryPool::freeSingleton();
+	DefaultMemoryPool::freeSingleton();
 }
 
 ANKI_TEST(Gr, GrManager)
@@ -392,9 +51,9 @@ ANKI_TEST(Gr, GrManager)
 	g_validationCVar.set(true);
 
 	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
-	g_win = createWindow();
+	initWindow();
 	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init());
-	g_gr = createGrManager(g_win);
+	initGrManager();
 
 	GrManager::freeSingleton();
 	Input::freeSingleton();
@@ -404,15 +63,18 @@ ANKI_TEST(Gr, GrManager)
 
 ANKI_TEST(Gr, Shader)
 {
+#if 0
 	COMMON_BEGIN()
 
 	ShaderPtr shader = createShader(FRAG_MRT_SRC, ShaderType::kFragment, *g_gr);
 
 	COMMON_END()
+#endif
 }
 
 ANKI_TEST(Gr, ShaderProgram)
 {
+#if 0
 	COMMON_BEGIN()
 
 	constexpr const char* kVertSrc = R"(
@@ -438,11 +100,12 @@ void main()
 	ShaderProgramPtr ppline = createProgram(kVertSrc, kFragSrc, *g_gr);
 
 	COMMON_END()
+#endif
 }
 
 ANKI_TEST(Gr, ClearScreen)
 {
-	COMMON_BEGIN()
+	commonInit();
 	ANKI_TEST_LOGI("Expect to see a magenta background");
 
 	constexpr U kIterations = 100;
@@ -452,26 +115,31 @@ ANKI_TEST(Gr, ClearScreen)
 		HighRezTimer timer;
 		timer.start();
 
-		TexturePtr presentTex = g_gr->acquireNextPresentableTexture();
+		TexturePtr presentTex = GrManager::getSingleton().acquireNextPresentableTexture();
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
-		CommandBufferPtr cmdb = g_gr->newCommandBuffer(cinit);
+		CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cinit);
 
-		presentBarrierA(cmdb, presentTex);
+		const TextureBarrierInfo barrier = {TextureView(presentTex.get(), TextureSubresourceDescriptor::all()), TextureUsageBit::kNone,
+											TextureUsageBit::kFramebufferWrite};
+		cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
 
 		RenderTarget rt;
 		rt.m_textureView = TextureView(presentTex.get(), TextureSubresourceDescriptor::all());
 		const F32 col = 1.0f - F32(iterations) / F32(kIterations);
 		rt.m_clearValue.m_colorf = {col, 0.0f, col, 1.0f};
 		cmdb->beginRenderPass({rt});
-
 		cmdb->endRenderPass();
-		presentBarrierB(cmdb, presentTex);
+
+		const TextureBarrierInfo barrier2 = {TextureView(presentTex.get(), TextureSubresourceDescriptor::all()), TextureUsageBit::kFramebufferWrite,
+											 TextureUsageBit::kPresent};
+		cmdb->setPipelineBarrier({&barrier2, 1}, {}, {});
+
 		cmdb->endRecording();
 		GrManager::getSingleton().submit(cmdb.get());
 
-		g_gr->swapBuffers();
+		GrManager::getSingleton().swapBuffers();
 
 		timer.stop();
 		const F32 TICK = 1.0f / 30.0f;
@@ -481,7 +149,7 @@ ANKI_TEST(Gr, ClearScreen)
 		}
 	}
 
-	COMMON_END()
+	commonDestroy();
 }
 
 ANKI_TEST(Gr, SimpleDrawcall)
@@ -762,6 +430,7 @@ void main()
 
 ANKI_TEST(Gr, Buffer)
 {
+#if 0
 	COMMON_BEGIN()
 
 	BufferInitInfo buffInit("a");
@@ -789,6 +458,7 @@ ANKI_TEST(Gr, Buffer)
 	b->unmap();
 
 	COMMON_END()
+#endif
 }
 
 ANKI_TEST(Gr, DrawWithUniforms)
@@ -989,6 +659,7 @@ ANKI_TEST(Gr, DrawWithVertex)
 
 ANKI_TEST(Gr, Sampler)
 {
+#if 0
 	COMMON_BEGIN()
 
 	SamplerInitInfo init;
@@ -996,10 +667,12 @@ ANKI_TEST(Gr, Sampler)
 	SamplerPtr b = g_gr->newSampler(init);
 
 	COMMON_END()
+#endif
 }
 
 ANKI_TEST(Gr, Texture)
 {
+#if 0
 	COMMON_BEGIN()
 
 	TextureInitInfo init;
@@ -1017,6 +690,7 @@ ANKI_TEST(Gr, Texture)
 	TexturePtr b = g_gr->newTexture(init);
 
 	COMMON_END()
+#endif
 }
 
 ANKI_TEST(Gr, DrawWithTexture)
@@ -1207,6 +881,7 @@ void main()
 #endif
 }
 
+#if 0
 static void drawOffscreenDrawcalls([[maybe_unused]] GrManager& gr, ShaderProgramPtr prog, CommandBufferPtr cmdb, U32 viewPortSize,
 								   BufferPtr indexBuff, BufferPtr vertBuff)
 {
@@ -1246,6 +921,7 @@ static void drawOffscreenDrawcalls([[maybe_unused]] GrManager& gr, ShaderProgram
 
 	cmdb->drawIndexed(PrimitiveTopology::kTriangles, 6 * 2 * 3);
 }
+#endif
 
 static void drawOffscreen(GrManager& gr)
 {
@@ -1366,11 +1042,13 @@ static void drawOffscreen(GrManager& gr)
 
 ANKI_TEST(Gr, DrawOffscreen)
 {
+#if 0
 	COMMON_BEGIN()
 
 	drawOffscreen(*g_gr);
 
-	COMMON_END()
+	COMMON_END();
+#endif
 }
 
 ANKI_TEST(Gr, ImageLoadStore)
@@ -2057,6 +1735,7 @@ void main()
 
 ANKI_TEST(Gr, BindingWithArray)
 {
+#if 0
 	COMMON_BEGIN()
 
 	// Create result buffer
@@ -2128,6 +1807,7 @@ void main()
 	resBuff->unmap();
 
 	COMMON_END();
+#endif
 }
 
 ANKI_TEST(Gr, Bindless)
@@ -2260,83 +1940,6 @@ void main()
 #endif
 }
 
-ANKI_TEST(Gr, BufferAddress)
-{
-	COMMON_BEGIN()
-
-	// Create program
-	static const char* PROG_SRC = R"(
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-
-ANKI_DEFINE_LOAD_STORE(Vec4, 4)
-
-layout(push_constant) uniform u_
-{
-	U64 u_bufferAddressRead;
-	U64 u_bufferAddressWrite;
-};
-
-void main()
-{
-	Vec4 a;
-	load(u_bufferAddressRead, a);
-	Vec4 b;
-	load(u_bufferAddressRead + 16ul, b);
-
-	store(u_bufferAddressWrite, a + b);
-})";
-
-	ShaderPtr shader = createShader(PROG_SRC, ShaderType::kCompute, *g_gr);
-	ShaderProgramInitInfo sprogInit;
-	sprogInit.m_computeShader = shader.get();
-	ShaderProgramPtr prog = g_gr->newShaderProgram(sprogInit);
-
-	// Create buffers
-	BufferInitInfo info;
-	info.m_size = sizeof(Vec4) * 2;
-	info.m_usage = BufferUsageBit::kAllCompute;
-	info.m_mapAccess = BufferMapAccessBit::kWrite;
-	BufferPtr ptrBuff = g_gr->newBuffer(info);
-
-	Vec4* mapped = static_cast<Vec4*>(ptrBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
-	const Vec4 VEC(123.456f, -1.1f, 100.0f, -666.0f);
-	*mapped = VEC;
-	++mapped;
-	*mapped = VEC * 10.0f;
-	ptrBuff->unmap();
-
-	BufferPtr resBuff = g_gr->newBuffer(BufferInitInfo(sizeof(Vec4), BufferUsageBit::kAllCompute, BufferMapAccessBit::kRead));
-
-	// Run
-	CommandBufferInitInfo cinit;
-	cinit.m_flags = CommandBufferFlag::kComputeWork | CommandBufferFlag::kSmallBatch;
-	CommandBufferPtr cmdb = g_gr->newCommandBuffer(cinit);
-
-	cmdb->bindShaderProgram(prog.get());
-
-	struct Address
-	{
-		PtrSize m_addressRead;
-		PtrSize m_addressWrite;
-	} address;
-	address.m_addressRead = ptrBuff->getGpuAddress();
-	address.m_addressWrite = resBuff->getGpuAddress();
-	cmdb->setPushConstants(&address, sizeof(address));
-
-	cmdb->dispatchCompute(1, 1, 1);
-
-	cmdb->endRecording();
-	GrManager::getSingleton().submit(cmdb.get());
-	g_gr->finish();
-
-	// Check
-	mapped = static_cast<Vec4*>(resBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kRead));
-	ANKI_TEST_EXPECT_EQ(*mapped, VEC + VEC * 10.0f);
-	resBuff->unmap();
-
-	COMMON_END();
-}
-
 ANKI_TEST(Gr, RayQuery)
 {
 #if 0
@@ -3466,6 +3069,7 @@ void main()
 
 ANKI_TEST(Gr, AsyncCompute)
 {
+#if 0
 	COMMON_BEGIN()
 
 	constexpr U32 ARRAY_SIZE = 1000 * 1024 * 8;
@@ -3568,7 +3172,7 @@ void main()
 	incrementCmdb2->dispatchCompute(ARRAY_SIZE / 8, 1, 1);
 
 	// Submit
-#if 1
+#	if 1
 	FencePtr fence;
 	incrementCmdb->endRecording();
 	GrManager::getSingleton().submit(incrementCmdb.get(), {}, &fence);
@@ -3579,14 +3183,14 @@ void main()
 	pFence = fence.get();
 	GrManager::getSingleton().submit(incrementCmdb2.get(), {&pFence, 1}, &fence);
 	fence->clientWait(kMaxSecond);
-#else
+#	else
 	incrementCmdb->flush();
 	gr->finish();
 	checkCmdb->flush();
 	gr->finish();
 	incrementCmdb2->flush();
 	gr->finish();
-#endif
+#	endif
 
 	// Verify
 	memcpy(atomicsBufferCpu.getBegin(), values, atomicsBufferCpu.getSizeInBytes());
@@ -3604,4 +3208,5 @@ void main()
 	ANKI_TEST_EXPECT_EQ(correct, true);
 
 	COMMON_END()
+#endif
 }

+ 2 - 2
Tests/Gr/GrCommon.h

@@ -11,7 +11,7 @@
 
 namespace anki {
 
-inline ShaderPtr createShader(CString src, ShaderType type, GrManager& gr, ConstWeakArray<ShaderSpecializationConstValue> specVals = {})
+inline ShaderPtr createShader(CString src, ShaderType type, ConstWeakArray<ShaderSpecializationConstValue> specVals = {})
 {
 	ShaderCompilerString header;
 	ShaderProgramParser::generateAnkiShaderHeader(type, header);
@@ -29,7 +29,7 @@ inline ShaderPtr createShader(CString src, ShaderType type, GrManager& gr, Const
 	ShaderInitInfo initInf(type, spirv);
 	initInf.m_constValues = specVals;
 
-	return gr.newShader(initInf);
+	return GrManager::getSingleton().newShader(initInf);
 }
 
 } // end namespace anki

+ 13 - 13
Tests/Gr/GrMeshShaders.cpp

@@ -21,8 +21,8 @@ ANKI_TEST(Gr, MeshShaders)
 
 	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
 	ShaderCompilerMemoryPool::allocateSingleton(allocAligned, nullptr);
-	NativeWindow* win = createWindow();
-	GrManager* gr = createGrManager(win);
+	initWindow();
+	initGrManager();
 
 	{
 		const CString taskShaderSrc = R"(
@@ -122,15 +122,15 @@ float3 main(VertOut input) : SV_TARGET0
 
 		ShaderProgramPtr prog;
 		{
-			ShaderPtr taskShader = createShader(taskShaderSrc, ShaderType::kTask, *gr);
-			ShaderPtr meshShader = createShader(meshShaderSrc, ShaderType::kMesh, *gr);
-			ShaderPtr fragShader = createShader(fragShaderSrc, ShaderType::kFragment, *gr);
+			ShaderPtr taskShader = createShader(taskShaderSrc, ShaderType::kTask);
+			ShaderPtr meshShader = createShader(meshShaderSrc, ShaderType::kMesh);
+			ShaderPtr fragShader = createShader(fragShaderSrc, ShaderType::kFragment);
 
 			ShaderProgramInitInfo progInit("Program");
 			progInit.m_graphicsShaders[ShaderType::kTask] = taskShader.get();
 			progInit.m_graphicsShaders[ShaderType::kMesh] = meshShader.get();
 			progInit.m_graphicsShaders[ShaderType::kFragment] = fragShader.get();
-			prog = gr->newShaderProgram(progInit);
+			prog = GrManager::getSingleton().newShaderProgram(progInit);
 		}
 
 		BufferPtr indexBuff;
@@ -139,7 +139,7 @@ float3 main(VertOut input) : SV_TARGET0
 			buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
 			buffInit.m_usage = BufferUsageBit::kStorageGeometryRead;
 			buffInit.m_size = sizeof(U32) * 6;
-			indexBuff = gr->newBuffer(buffInit);
+			indexBuff = GrManager::getSingleton().newBuffer(buffInit);
 
 			void* mapped = indexBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite);
 			const U32 indices[] = {0, 1, 2, 2, 1, 3};
@@ -153,7 +153,7 @@ float3 main(VertOut input) : SV_TARGET0
 			buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
 			buffInit.m_usage = BufferUsageBit::kStorageGeometryRead;
 			buffInit.m_size = kVertCount * sizeof(Vec4) * kTileCount;
-			positionsBuff = gr->newBuffer(buffInit);
+			positionsBuff = GrManager::getSingleton().newBuffer(buffInit);
 
 			Vec4* mapped = static_cast<Vec4*>(positionsBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
 
@@ -178,7 +178,7 @@ float3 main(VertOut input) : SV_TARGET0
 			buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
 			buffInit.m_usage = BufferUsageBit::kStorageGeometryRead;
 			buffInit.m_size = kVertCount * sizeof(Vec4) * kTileCount;
-			colorsBuff = gr->newBuffer(buffInit);
+			colorsBuff = GrManager::getSingleton().newBuffer(buffInit);
 
 			Vec4* mapped = static_cast<Vec4*>(colorsBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
 
@@ -207,7 +207,7 @@ float3 main(VertOut input) : SV_TARGET0
 			buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
 			buffInit.m_usage = BufferUsageBit::kStorageGeometryRead;
 			buffInit.m_size = sizeof(Meshlet) * kTileCount;
-			meshletsBuff = gr->newBuffer(buffInit);
+			meshletsBuff = GrManager::getSingleton().newBuffer(buffInit);
 
 			Meshlet* mapped = static_cast<Meshlet*>(meshletsBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
 
@@ -222,10 +222,10 @@ float3 main(VertOut input) : SV_TARGET0
 
 		for(U32 i = 0; i < 100; ++i)
 		{
-			TexturePtr swapchainTex = gr->acquireNextPresentableTexture();
+			TexturePtr swapchainTex = GrManager::getSingleton().acquireNextPresentableTexture();
 
 			CommandBufferInitInfo cmdbinit;
-			CommandBufferPtr cmdb = gr->newCommandBuffer(cmdbinit);
+			CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbinit);
 
 			cmdb->setViewport(0, 0, g_windowWidthCVar.get(), g_windowHeightCVar.get());
 
@@ -258,7 +258,7 @@ float3 main(VertOut input) : SV_TARGET0
 			cmdb->endRecording();
 			GrManager::getSingleton().submit(cmdb.get());
 
-			gr->swapBuffers();
+			GrManager::getSingleton().swapBuffers();
 
 			HighRezTimer::sleep(1.0_sec / 60.0);
 		}

+ 8 - 8
Tests/Gr/GrTextureBuffer.cpp

@@ -11,8 +11,8 @@ ANKI_TEST(Gr, TextureBuffer)
 {
 	g_validationCVar.set(true);
 
-	NativeWindow* win = createWindow();
-	GrManager* gr = createGrManager(win);
+	initWindow();
+	initGrManager();
 
 	{
 		const CString shaderSrc = R"(
@@ -28,17 +28,17 @@ void main()
 }
 	)";
 
-		ShaderPtr shader = createShader(shaderSrc, ShaderType::kCompute, *gr);
+		ShaderPtr shader = createShader(shaderSrc, ShaderType::kCompute);
 
 		ShaderProgramInitInfo progInit;
 		progInit.m_computeShader = shader.get();
-		ShaderProgramPtr prog = gr->newShaderProgram(progInit);
+		ShaderProgramPtr prog = GrManager::getSingleton().newShaderProgram(progInit);
 
 		BufferInitInfo buffInit;
 		buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
 		buffInit.m_size = sizeof(U8) * 4;
 		buffInit.m_usage = BufferUsageBit::kAllTexel;
-		BufferPtr texBuff = gr->newBuffer(buffInit);
+		BufferPtr texBuff = GrManager::getSingleton().newBuffer(buffInit);
 
 		I8* data = static_cast<I8*>(texBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
 		const Vec4 values(-1.0f, -0.25f, 0.1345f, 0.8952f);
@@ -52,11 +52,11 @@ void main()
 		buffInit.m_mapAccess = BufferMapAccessBit::kRead;
 		buffInit.m_size = sizeof(F32) * 4;
 		buffInit.m_usage = BufferUsageBit::kAllStorage;
-		BufferPtr storageBuff = gr->newBuffer(buffInit);
+		BufferPtr storageBuff = GrManager::getSingleton().newBuffer(buffInit);
 
 		CommandBufferInitInfo cmdbInit;
 		cmdbInit.m_flags = CommandBufferFlag::kSmallBatch | CommandBufferFlag::kGeneralWork;
-		CommandBufferPtr cmdb = gr->newCommandBuffer(cmdbInit);
+		CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
 
 		cmdb->bindReadOnlyTexelBuffer(0, 0, BufferView(texBuff.get()), Format::kR8G8B8A8_Snorm);
 		cmdb->bindStorageBuffer(0, 1, BufferView(storageBuff.get()));
@@ -64,7 +64,7 @@ void main()
 		cmdb->dispatchCompute(1, 1, 1);
 		cmdb->endRecording();
 		GrManager::getSingleton().submit(cmdb.get());
-		gr->finish();
+		GrManager::getSingleton().finish();
 
 		const Vec4* inData = static_cast<const Vec4*>(storageBuff->map(0, kMaxPtrSize, BufferMapAccessBit::kRead));
 		for(U i = 0; i < 4; ++i)

+ 7 - 7
Tests/Ui/Ui.cpp

@@ -62,10 +62,10 @@ ANKI_TEST(Ui, Ui)
 	g_windowHeightCVar.set(760);
 	g_dataPathsCVar.set("EngineAssets");
 
-	NativeWindow* win = createWindow();
+	initWindow();
 	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init());
-	GrManager* gr = createGrManager(win);
-	createResourceManager(gr);
+	initGrManager();
+	ANKI_TEST_EXPECT_NO_ERR(ResourceManager::allocateSingleton().init(allocAligned, nullptr));
 	UiManager* ui = &UiManager::allocateSingleton();
 
 	RebarTransientMemoryPool::allocateSingleton().init();
@@ -77,7 +77,7 @@ ANKI_TEST(Ui, Ui)
 		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(font, "UbuntuRegular.ttf", Array<U32, 4>{10, 20, 30, 60}));
 
 		CanvasPtr canvas;
-		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(canvas, font, 20, win->getWidth(), win->getHeight()));
+		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(canvas, font, 20, NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight()));
 
 		IntrusivePtr<Label, UiObjectDeleter> label;
 		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(label));
@@ -98,11 +98,11 @@ ANKI_TEST(Ui, Ui)
 			canvas->beginBuilding();
 			label->build(canvas);
 
-			TexturePtr presentTex = gr->acquireNextPresentableTexture();
+			TexturePtr presentTex = GrManager::getSingleton().acquireNextPresentableTexture();
 
 			CommandBufferInitInfo cinit;
 			cinit.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
-			CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
+			CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cinit);
 
 			TextureBarrierInfo barrier;
 			barrier.m_previousUsage = TextureUsageBit::kNone;
@@ -125,7 +125,7 @@ ANKI_TEST(Ui, Ui)
 			cmdb->endRecording();
 			GrManager::getSingleton().submit(cmdb.get());
 
-			gr->swapBuffers();
+			GrManager::getSingleton().swapBuffers();
 			RebarTransientMemoryPool::getSingleton().endFrame();
 
 			timer.stop();