소스 검색

Hooking up various Vulkan RenderAPI methods

BearishSun 9 년 전
부모
커밋
643f494d3a

+ 1 - 1
Source/BansheeCore/Include/BsRenderAPICapabilities.h

@@ -11,7 +11,7 @@
 #define CAPS_CATEGORY_MASK (((INT64_C(1) << CAPS_CATEGORY_SIZE) - INT64_C(1)) << BS_CAPS_BITSHIFT)
 #define BS_CAPS_VALUE(cat, val) ((cat << BS_CAPS_BITSHIFT) | (INT64_C(1) << val))
 
-#define MAX_BOUND_VERTEX_BUFFERS 32
+#define BS_MAX_BOUND_VERTEX_BUFFERS 16
 
 namespace BansheeEngine 
 {

+ 3 - 3
Source/BansheeD3D11RenderAPI/Source/BsD3D11RenderAPI.cpp

@@ -642,9 +642,9 @@ namespace BansheeEngine
 					". Valid range is 0 .. " + toString(maxBoundVertexBuffers - 1));
 			}
 
-			ID3D11Buffer* dx11buffers[MAX_BOUND_VERTEX_BUFFERS];
-			UINT32 strides[MAX_BOUND_VERTEX_BUFFERS];
-			UINT32 offsets[MAX_BOUND_VERTEX_BUFFERS];
+			ID3D11Buffer* dx11buffers[BS_MAX_BOUND_VERTEX_BUFFERS];
+			UINT32 strides[BS_MAX_BOUND_VERTEX_BUFFERS];
+			UINT32 offsets[BS_MAX_BOUND_VERTEX_BUFFERS];
 
 			for (UINT32 i = 0; i < numBuffers; i++)
 			{

+ 6 - 6
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -154,13 +154,13 @@ namespace BansheeEngine
 		auto& vertexBuffers = vertexData->getBuffers();
 		if (vertexBuffers.size() > 0)
 		{
-			SPtr<VertexBufferCore> buffers[MAX_BOUND_VERTEX_BUFFERS];
+			SPtr<VertexBufferCore> buffers[BS_MAX_BOUND_VERTEX_BUFFERS];
 
 			UINT32 endSlot = 0;
-			UINT32 startSlot = MAX_BOUND_VERTEX_BUFFERS;
+			UINT32 startSlot = BS_MAX_BOUND_VERTEX_BUFFERS;
 			for (auto iter = vertexBuffers.begin(); iter != vertexBuffers.end(); ++iter)
 			{
-				if (iter->first >= MAX_BOUND_VERTEX_BUFFERS)
+				if (iter->first >= BS_MAX_BOUND_VERTEX_BUFFERS)
 					BS_EXCEPT(InvalidParametersException, "Buffer index out of range");
 
 				startSlot = std::min(iter->first, startSlot);
@@ -197,13 +197,13 @@ namespace BansheeEngine
 		rapi.setVertexDeclaration(morphVertexDeclaration);
 
 		auto& meshBuffers = vertexData->getBuffers();
-		SPtr<VertexBufferCore> allBuffers[MAX_BOUND_VERTEX_BUFFERS];
+		SPtr<VertexBufferCore> allBuffers[BS_MAX_BOUND_VERTEX_BUFFERS];
 
 		UINT32 endSlot = 0;
-		UINT32 startSlot = MAX_BOUND_VERTEX_BUFFERS;
+		UINT32 startSlot = BS_MAX_BOUND_VERTEX_BUFFERS;
 		for (auto iter = meshBuffers.begin(); iter != meshBuffers.end(); ++iter)
 		{
-			if (iter->first >= MAX_BOUND_VERTEX_BUFFERS)
+			if (iter->first >= BS_MAX_BOUND_VERTEX_BUFFERS)
 				BS_EXCEPT(InvalidParametersException, "Buffer index out of range");
 
 			startSlot = std::min(iter->first, startSlot);

+ 79 - 8
Source/BansheeVulkanRenderAPI/Include/BsVulkanCommandBuffer.h

@@ -6,6 +6,7 @@
 #include "BsCommandBuffer.h"
 #include "BsVulkanRenderAPI.h"
 #include "BsVulkanResource.h"
+#include "BsVulkanGpuPipelineState.h"
 
 namespace BansheeEngine
 {
@@ -133,12 +134,6 @@ namespace BansheeEngine
 		/** Checks the internal fence and changes command buffer state if done executing. */
 		void refreshFenceStatus();
 
-		/** 
-		 * Assigns a render target the the command buffer. This render target's framebuffer and render pass will be used
-		 * when beginRenderPass() is called. Command buffer must not be currently recording a render pass.
-		 */
-		void setRenderTarget(const SPtr<RenderTargetCore>& rt);
-
 		/** 
 		 * Lets the command buffer know that the provided resource has been queued on it, and will be used by the
 		 * device when the command buffer is submitted. If a resource is an image or a buffer use the more specific
@@ -161,6 +156,55 @@ namespace BansheeEngine
 		 */
 		void registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags);
 
+		/************************************************************************/
+		/* 								COMMANDS	                     		*/
+		/************************************************************************/
+
+		/** 
+		 * Assigns a render target the the command buffer. This render target's framebuffer and render pass will be used
+		 * when beginRenderPass() is called. Command buffer must not be currently recording a render pass.
+		 */
+		void setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil);
+
+		/** Assigns a pipeline state to use for subsequent draw commands. */
+		void setPipelineState(const SPtr<GraphicsPipelineStateCore>& state);
+
+		/** Assigns a pipeline state to use for subsequent dispatch commands. */
+		void setPipelineState(const SPtr<ComputePipelineStateCore>& state);
+
+		/** Sets the current viewport which determine to which portion of the render target to render to. */
+		void setViewport(const Rect2& area);
+
+		/** 
+		 * Sets the scissor rectangle area which determines in which area if the viewport are the fragments allowed to be
+		 * generated. Only relevant if enabled on the pipeline state.
+		 */
+		void setScissorRect(const Rect2I& area);
+
+		/** Sets a stencil reference value that will be used for comparisons in stencil operations, if enabled. */
+		void setStencilRef(UINT32 value);
+
+		/** Changes how are primitives interpreted as during rendering. */
+		void setDrawOp(DrawOperationType drawOp);
+
+		/** Sets one or multiple vertex buffers that will be used for subsequent draw() or drawIndexed() calls. */
+		void setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers);
+
+		/** Sets an index buffer that will be used for subsequent drawIndexed() calls. */
+		void setIndexBuffer(const SPtr<IndexBufferCore>& buffer);
+
+		/** Sets a declaration that determines how are vertex buffer contents interpreted. */
+		void setVertexDeclaration(const SPtr<VertexDeclarationCore>& decl);
+
+		/** Executes a draw command using the currently bound graphics pipeline, vertex buffer and render target. */
+		void draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount);
+
+		/** Executes a draw command using the currently bound graphics pipeline, index & vertex buffer and render target. */
+		void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount);
+
+		/** Executes a dispatch command using the currently bound compute pipeline. */
+		void dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ);
+
 	private:
 		friend class VulkanCmdBufferPool;
 		friend class VulkanCommandBuffer;
@@ -188,6 +232,18 @@ namespace BansheeEngine
 			ResourceUseHandle useHandle;
 		};
 
+		/** Checks if all the prerequisites for rendering have been made (e.g. render target and pipeline state are set. */
+		bool isReadyForRender();
+
+		/** Binds the current graphics pipeline to the command buffer. */
+		void bindGraphicsPipeline();
+
+		/** Binds any dynamic states to the pipeline, as required. 
+		 *
+		 * @param[in]	forceAll	If true all states will be bound. If false only states marked as dirty will be bound.
+		 */
+		void bindDynamicStates(bool forceAll);
+
 		UINT32 mId;
 		UINT32 mQueueFamily;
 		State mState;
@@ -198,18 +254,33 @@ namespace BansheeEngine
 		VkSemaphore mSemaphore;
 		UINT32 mFenceCounter;
 
-		VkFramebuffer mFramebuffer;
-		VkRenderPass mRenderPass;
+		VulkanFramebuffer* mFramebuffer;
 		VkSemaphore mPresentSemaphore;
 		UINT32 mRenderTargetWidth;
 		UINT32 mRenderTargetHeight;
+		bool mRenderTargetDepthReadOnly;
 
 		UnorderedMap<VulkanResource*, ResourceUseHandle> mResources;
 		UnorderedMap<VulkanResource*, ImageInfo> mImages;
 		UnorderedMap<VulkanResource*, BufferInfo> mBuffers;
 		UINT32 mGlobalQueueIdx;
 
+		SPtr<VulkanGraphicsPipelineStateCore> mGraphicsPipeline;
+		SPtr<VulkanComputePipelineStateCore> mComputePipeline;
+		SPtr<VertexDeclarationCore> mVertexDecl;
+		Rect2 mViewport;
+		Rect2I mScissor;
+		UINT32 mStencilRef;
+		DrawOperationType mDrawOp;
+		bool mGfxPipelineRequiresBind : 1;
+		bool mCmpPipelineRequiresBind : 1;
+		bool mViewportRequiresBind : 1;
+		bool mStencilRefRequiresBind : 1;
+		bool mScissorRequiresBind : 1;
+
 		VkSemaphore mSemaphoresTemp[BS_MAX_UNIQUE_QUEUES + 1]; // +1 for present semaphore
+		VkBuffer mVertexBuffersTemp[BS_MAX_BOUND_VERTEX_BUFFERS];
+		VkDeviceSize mVertexBufferOffsetsTemp[BS_MAX_BOUND_VERTEX_BUFFERS];
 		UnorderedMap<UINT32, TransitionInfo> mTransitionInfoTemp;
 	};
 

+ 11 - 6
Source/BansheeVulkanRenderAPI/Include/BsVulkanFramebuffer.h

@@ -3,6 +3,7 @@
 #pragma once
 
 #include "BsVulkanPrerequisites.h"
+#include "BsVulkanResource.h"
 
 namespace BansheeEngine
 {
@@ -46,18 +47,20 @@ namespace BansheeEngine
 	};
 
 	/** Vulkan frame buffer containing one or multiple color surfaces, and an optional depth surface. */
-	class VulkanFramebuffer : INonCopyable
+	class VulkanFramebuffer : public VulkanResource
 	{
 	public:
 		/** Creates a new frame buffer with the specified image views attached. 
 		 *
-		 * @param[in]	device	Device to create the frame buffer on. All attachment images provided in the @p desc
-		 *						parameter must also belong to this device.
+		 * @param[in]	owner	Resource manager that allocated this resource.
 		 * @param[in]	desc	Description of the frame buffer.
 		 */
-		VulkanFramebuffer(const SPtr<VulkanDevice>& device, const VULKAN_FRAMEBUFFER_DESC& desc);
+		VulkanFramebuffer(VulkanResourceManager* owner, const VULKAN_FRAMEBUFFER_DESC& desc);
 		~VulkanFramebuffer();
 
+		/** Returns a unique ID of this framebuffer. */
+		UINT32 getId() const { return mId; }
+
 		/** Gets internal Vulkan render pass object. */
 		VkRenderPass getRenderPass() const { return mRenderPass; }
 
@@ -76,15 +79,17 @@ namespace BansheeEngine
 		/** Returns sample flags that determine if the framebuffer supports multi-sampling, and for how many samples. */
 		VkSampleCountFlagBits getSampleFlags() const { return mSampleFlags; }
 	private:
+		UINT32 mId;
 		VkRenderPass mRenderPass;
 		VkFramebuffer mFramebuffer;
-		VkDevice mDevice;
 
 		UINT32 mNumAttachments;
 		UINT32 mNumColorAttachments;
 		bool mHasDepth;
 		VkSampleCountFlagBits mSampleFlags;
+
+		static UINT32 sNextValidId;
 	};
 
 	/** @} */
-}
+}

+ 35 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuPipelineState.h

@@ -32,6 +32,28 @@ namespace BansheeEngine
 	public:
 		~VulkanGraphicsPipelineStateCore();
 
+		/** Checks does the pipeline enable scissor tests. */
+		bool isScissorEnabled() const { return mScissorEnabled; }
+
+		/** Returns the vertex input declaration from the vertex GPU program bound on the pipeline. */
+		SPtr<VertexDeclarationCore> getInputDeclaration() const { return mVertexDecl; }
+
+		/** 
+		 * Attempts to find an existing pipeline matching the provided parameters, or creates a new one if one cannot be 
+		 * found.
+		 * 
+		 * @param[in]	deviceIdx			Index of the device to retrieve the pipeline for.
+		 * @param[in]	framebuffer			Framebuffer object that defines the surfaces this pipeline will render to.
+		 * @param[in]	readOnlyDepth		True if the pipeline is only allowed to read the depth buffer, without writes.
+		 * @param[in]	drawOp				Type of geometry that will be drawn using the pipeline.
+		 * @param[in]	vertexInputState	State describing inputs to the vertex program.
+		 * @return							Vulkan graphics pipeline object.
+		 * 
+		 * @note	Thread safe.
+		 */
+		VulkanPipeline* getPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth, 
+			DrawOperationType drawOp, VkPipelineVertexInputStateCreateInfo* vertexInputState);
+
 	protected:
 		friend class VulkanRenderStateCoreManager;
 
@@ -49,8 +71,10 @@ namespace BansheeEngine
 		 * @param[in]	drawOp				Type of geometry that will be drawn using the pipeline.
 		 * @param[in]	vertexInputState	State describing inputs to the vertex program.
 		 * @return							Vulkan graphics pipeline object.
+		 * 
+		 * @note	Thread safe.
 		 */
-		VkPipeline createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth,
+		VulkanPipeline* createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth,
 								  DrawOperationType drawOp, VkPipelineVertexInputStateCreateInfo* vertexInputState);
 
 		/** Contains pipeline data specific to a single Vulkan device. */
@@ -72,9 +96,13 @@ namespace BansheeEngine
 		VkPipelineDynamicStateCreateInfo mDynamicStateInfo;
 		VkDynamicState mDynamicStates[3];
 		VkGraphicsPipelineCreateInfo mPipelineInfo;
+		bool mScissorEnabled;
+		SPtr<VertexDeclarationCore> mVertexDecl;
 
 		GpuDeviceFlags mDeviceMask;
 		PerDeviceData mPerDeviceData[BS_MAX_DEVICES];
+
+		Mutex mMutex;
 	};
 
 	/**	Vulkan implementation of a compute pipeline state. */
@@ -83,6 +111,12 @@ namespace BansheeEngine
 	public:
 		~VulkanComputePipelineStateCore();
 
+		/** 
+		 * Returns a pipeline object for the specified device index. If the device index doesn't match a bit in the
+		 * device mask provided on pipeline creation, null is returned.
+		 */
+		VulkanPipeline* getPipeline(UINT32 deviceIdx) const;
+
 	protected:
 		friend class VulkanRenderStateCoreManager;
 

+ 0 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanPrerequisites.h

@@ -36,7 +36,6 @@ namespace BansheeEngine
 	class Win32RenderWindow;
 	class VulkanTextureCore;
 	class Win32VideoMode;
-	class VulkanIndexBuffer;
 	class VulkanVertexDeclaration;
 	class VulkanHardwareBuffer;
 	class VulkanDevice;

+ 259 - 9
Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp

@@ -7,7 +7,10 @@
 #include "BsVulkanGpuParams.h"
 #include "BsVulkanQueue.h"
 #include "BsVulkanTexture.h"
+#include "BsVulkanIndexBuffer.h"
+#include "BsVulkanVertexBuffer.h"
 #include "BsVulkanHardwareBuffer.h"
+#include "BsVulkanFramebuffer.h"
 
 namespace BansheeEngine
 {
@@ -99,8 +102,11 @@ namespace BansheeEngine
 
 	VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
 		: mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool), mFenceCounter(0)
-		, mFramebuffer(VK_NULL_HANDLE), mRenderPass(VK_NULL_HANDLE), mPresentSemaphore(VK_NULL_HANDLE)
-		, mRenderTargetWidth(0), mRenderTargetHeight(0), mGlobalQueueIdx(-1)
+		, mFramebuffer(nullptr), mPresentSemaphore(VK_NULL_HANDLE), mRenderTargetWidth(0), mRenderTargetHeight(0)
+		, mRenderTargetDepthReadOnly(false), mGlobalQueueIdx(-1), mViewport(0.0f, 0.0f, 1.0f, 1.0f), mScissor(0, 0, 0, 0)
+		, mStencilRef(0), mDrawOp(DOT_TRIANGLE_LIST), mGfxPipelineRequiresBind(true), mCmpPipelineRequiresBind(true)
+		, mViewportRequiresBind(true), mStencilRefRequiresBind(true), mScissorRequiresBind(true), mVertexBuffersTemp()
+		, mVertexBufferOffsetsTemp()
 	{
 		VkCommandBufferAllocateInfo cmdBufferAllocInfo;
 		cmdBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -214,7 +220,7 @@ namespace BansheeEngine
 	{
 		assert(mState == State::Recording);
 
-		if (mFramebuffer == VK_NULL_HANDLE || mRenderPass == VK_NULL_HANDLE)
+		if (mFramebuffer == nullptr)
 		{
 			LOGWRN("Attempting to begin a render pass but no render target is bound to the command buffer.");
 			return;
@@ -223,8 +229,8 @@ namespace BansheeEngine
 		VkRenderPassBeginInfo renderPassBeginInfo;
 		renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
 		renderPassBeginInfo.pNext = nullptr;
-		renderPassBeginInfo.framebuffer = mFramebuffer;
-		renderPassBeginInfo.renderPass = mRenderPass;
+		renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer();
+		renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass();
 		renderPassBeginInfo.renderArea.offset.x = 0;
 		renderPassBeginInfo.renderArea.offset.y = 0;
 		renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
@@ -461,6 +467,11 @@ namespace BansheeEngine
 			entry.second.imageBarriers.clear();
 			entry.second.bufferBarriers.clear();
 		}
+
+		mGraphicsPipeline = nullptr;
+		mComputePipeline = nullptr;
+		mGfxPipelineRequiresBind = true;
+		mCmpPipelineRequiresBind = true;
 	}
 
 	void VulkanCmdBuffer::refreshFenceStatus()
@@ -515,22 +526,21 @@ namespace BansheeEngine
 			assert(!signaled); // We reset the fence along with mState so this shouldn't be possible
 	}
 
-	void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt)
+	void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil)
 	{
 		assert(mState != State::RecordingRenderPass && mState != State::Submitted);
 
 		if(rt == nullptr)
 		{
-			mFramebuffer = VK_NULL_HANDLE;
-			mRenderPass = VK_NULL_HANDLE;
+			mFramebuffer = nullptr;
 			mPresentSemaphore = VK_NULL_HANDLE;
 			mRenderTargetWidth = 0;
 			mRenderTargetHeight = 0;
+			mRenderTargetDepthReadOnly = false;
 		}
 		else
 		{
 			rt->getCustomAttribute("FB", &mFramebuffer);
-			rt->getCustomAttribute("RP", &mRenderPass);
 			
 			if (rt->getProperties().isWindow())
 				rt->getCustomAttribute("PS", &mPresentSemaphore);
@@ -539,11 +549,251 @@ namespace BansheeEngine
 
 			mRenderTargetWidth = rt->getProperties().getWidth();
 			mRenderTargetHeight = rt->getProperties().getHeight();
+			mRenderTargetDepthReadOnly = readOnlyDepthStencil;
+
+			registerResource(mFramebuffer, VulkanUseFlag::Write);
+		}
+
+		mGfxPipelineRequiresBind = true;
+	}
+
+	void VulkanCmdBuffer::setPipelineState(const SPtr<GraphicsPipelineStateCore>& state)
+	{
+		if (mGraphicsPipeline == state)
+			return;
+
+		mGraphicsPipeline = std::static_pointer_cast<VulkanGraphicsPipelineStateCore>(state);
+		mGfxPipelineRequiresBind = true; 
+	}
+
+	void VulkanCmdBuffer::setPipelineState(const SPtr<ComputePipelineStateCore>& state)
+	{
+		if (mComputePipeline == state)
+			return;
+
+		mComputePipeline = std::static_pointer_cast<VulkanComputePipelineStateCore>(state);
+		mCmpPipelineRequiresBind = true;
+	}
+
+	void VulkanCmdBuffer::setViewport(const Rect2& area)
+	{
+		if (mViewport == area)
+			return;
+
+		mViewport = area;
+		mViewportRequiresBind = true;
+	}
+
+	void VulkanCmdBuffer::setScissorRect(const Rect2I& value)
+	{
+		if (mScissor == value)
+			return;
+
+		mScissor = value;
+		mScissorRequiresBind = true;
+	}
+
+	void VulkanCmdBuffer::setStencilRef(UINT32 value)
+	{
+		if (mStencilRef == value)
+			return;
+
+		mStencilRef = value;
+		mStencilRefRequiresBind = true;
+	}
+
+	void VulkanCmdBuffer::setDrawOp(DrawOperationType drawOp)
+	{
+		if (mDrawOp == drawOp)
+			return;
+
+		mDrawOp = drawOp;
+		mGfxPipelineRequiresBind = true;
+	}
+
+	void VulkanCmdBuffer::setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers)
+	{
+		if (numBuffers == 0)
+			return;
+
+		for(UINT32 i = 0; i < numBuffers; i++)
+		{
+			VulkanVertexBufferCore* vertexBuffer = static_cast<VulkanVertexBufferCore*>(buffers[i].get());
+
+			if (vertexBuffer != nullptr)
+			{
+				VulkanBuffer* resource = vertexBuffer->getResource(mDevice.getIndex());
+				if (resource != nullptr)
+				{
+					mVertexBuffersTemp[i] = resource->getHandle();
+
+					registerResource(resource, VulkanUseFlag::Read);
+				}
+				else
+					mVertexBuffersTemp[i] = VK_NULL_HANDLE;
+			}
+			else
+				mVertexBuffersTemp[i] = VK_NULL_HANDLE;
 		}
 
+		vkCmdBindVertexBuffers(mCmdBuffer, index, numBuffers, mVertexBuffersTemp, mVertexBufferOffsetsTemp);
+	}
+
+	void VulkanCmdBuffer::setIndexBuffer(const SPtr<IndexBufferCore>& buffer)
+	{
+		VulkanIndexBufferCore* indexBuffer = static_cast<VulkanIndexBufferCore*>(buffer.get());
+
+		VkBuffer vkBuffer = VK_NULL_HANDLE;
+		VkIndexType indexType = VK_INDEX_TYPE_UINT32;
+		if (indexBuffer != nullptr)
+		{
+			VulkanBuffer* resource = indexBuffer->getResource(mDevice.getIndex());
+			if (resource != nullptr)
+			{
+				vkBuffer = resource->getHandle();
+				indexType = VulkanUtility::getIndexType(buffer->getProperties().getType());
+
+				registerResource(resource, VulkanUseFlag::Read);
+			}
+		}
+
+		vkCmdBindIndexBuffer(mCmdBuffer, vkBuffer, 0, indexType);
+	}
+
+	void VulkanCmdBuffer::setVertexDeclaration(const SPtr<VertexDeclarationCore>& decl)
+	{
+		if (mVertexDecl == decl)
+			return;
+
+		mVertexDecl = decl;
+		mGfxPipelineRequiresBind = true;
+	}
+
+	bool VulkanCmdBuffer::isReadyForRender()
+	{
+		if (mGraphicsPipeline == nullptr)
+			return false;
+
+		SPtr<VertexDeclarationCore> inputDecl = mGraphicsPipeline->getInputDeclaration();
+		if (inputDecl == nullptr)
+			return false;
+
+		return mFramebuffer != nullptr && mVertexDecl != nullptr;
+	}
+
+	void VulkanCmdBuffer::bindGraphicsPipeline()
+	{
+
+		
+		// TODO - Begin render pass as needed
+		// TODO - Retrieve and bind pipeline
+		bindDynamicStates(true);
+
 
 
 		// TODO
+		// TODO - Bind GPU params
+
+		mGfxPipelineRequiresBind = false;
+	}
+
+	void VulkanCmdBuffer::bindDynamicStates(bool forceAll)
+	{
+		if (mViewportRequiresBind || forceAll)
+		{
+			VkViewport viewport;
+			viewport.x = mViewport.x * mRenderTargetWidth;
+			viewport.y = mViewport.y * mRenderTargetHeight;
+			viewport.width = mViewport.width * mRenderTargetWidth;
+			viewport.height = mViewport.height * mRenderTargetHeight;
+			viewport.minDepth = 0.0f;
+			viewport.maxDepth = 1.0f;
+
+			vkCmdSetViewport(mCmdBuffer, 0, 1, &viewport);
+			mViewportRequiresBind = false;
+		}
+
+		if(mStencilRefRequiresBind || forceAll)
+		{
+			vkCmdSetStencilReference(mCmdBuffer, VK_STENCIL_FRONT_AND_BACK, mStencilRef);
+			mStencilRefRequiresBind = false;
+		}
+
+		if(mScissorRequiresBind || forceAll)
+		{
+			VkRect2D scissorRect;
+			if(mGraphicsPipeline->isScissorEnabled())
+			{
+				scissorRect.offset.x = mScissor.x;
+				scissorRect.offset.y = mScissor.y;
+				scissorRect.extent.width = mScissor.width;
+				scissorRect.extent.height = mScissor.height;
+			}
+			else
+			{
+				scissorRect.offset.x = 0;
+				scissorRect.offset.y = 0;
+				scissorRect.extent.width = mRenderTargetWidth;
+				scissorRect.extent.height = mRenderTargetHeight;
+			}
+
+			vkCmdSetScissor(mCmdBuffer, 0, 1, &scissorRect);
+
+			mScissorRequiresBind = false;
+		}
+	}
+
+	void VulkanCmdBuffer::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount)
+	{
+		if (!isReadyForRender())
+			return;
+
+		if (mGfxPipelineRequiresBind)
+			bindGraphicsPipeline();
+		else
+			bindDynamicStates(false);
+
+		vkCmdDraw(mCmdBuffer, vertexCount, instanceCount, vertexOffset, 0);
+	}
+
+	void VulkanCmdBuffer::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount)
+	{
+		if (!isReadyForRender())
+			return;
+
+		if (mGfxPipelineRequiresBind)
+			bindGraphicsPipeline();
+		else
+			bindDynamicStates(false);
+
+		vkCmdDrawIndexed(mCmdBuffer, indexCount, instanceCount, startIndex, vertexOffset, 0);
+	}
+
+	void VulkanCmdBuffer::dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ)
+	{
+		if (mComputePipeline == nullptr)
+			return;
+
+		if (isInRenderPass())
+			endRenderPass();
+
+		if(mCmpPipelineRequiresBind)
+		{
+			UINT32 deviceIdx = mDevice.getIndex();
+
+			VulkanPipeline* pipeline = mComputePipeline->getPipeline(deviceIdx);
+			if (pipeline == nullptr)
+				return;
+
+			registerResource(pipeline, VulkanUseFlag::Read);
+
+			vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getHandle());
+			mCmpPipelineRequiresBind = false;
+		}
+
+		// TODO - Bind GpuParams
+
+		vkCmdDispatch(mCmdBuffer, numGroupsX, numGroupsY, numGroupsZ);
 	}
 
 	void VulkanCmdBuffer::registerResource(VulkanResource* res, VulkanUseFlags flags)

+ 14 - 6
Source/BansheeVulkanRenderAPI/Source/BsVulkanFramebuffer.cpp

@@ -6,10 +6,14 @@
 
 namespace BansheeEngine
 {
-	VulkanFramebuffer::VulkanFramebuffer(const SPtr<VulkanDevice>& device, const VULKAN_FRAMEBUFFER_DESC& desc)
-		: mDevice(device->getLogical()), mNumAttachments(0), mNumColorAttachments(0), mHasDepth(false)
+	UINT32 VulkanFramebuffer::sNextValidId = 1;
+
+	VulkanFramebuffer::VulkanFramebuffer(VulkanResourceManager* owner, const VULKAN_FRAMEBUFFER_DESC& desc)
+		: VulkanResource(owner, false), mNumAttachments(0), mNumColorAttachments(0), mHasDepth(false)
 		, mSampleFlags(VK_SAMPLE_COUNT_1_BIT)
 	{
+		mId = sNextValidId++;
+
 		// Create render state
 		VkAttachmentDescription attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
 		VkImageView attachmentViews[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
@@ -124,7 +128,9 @@ namespace BansheeEngine
 		renderPassCI.dependencyCount = 2;
 		renderPassCI.pDependencies = dependencies;
 
-		VkResult result = vkCreateRenderPass(mDevice, &renderPassCI, gVulkanAllocator, &mRenderPass);
+		VkDevice device = mOwner->getDevice().getLogical();
+
+		VkResult result = vkCreateRenderPass(device, &renderPassCI, gVulkanAllocator, &mRenderPass);
 		assert(result == VK_SUCCESS);
 
 		// Create frame buffer
@@ -139,13 +145,15 @@ namespace BansheeEngine
 		framebufferCI.height = desc.height;
 		framebufferCI.layers = desc.layers;
 
-		result = vkCreateFramebuffer(mDevice, &framebufferCI, gVulkanAllocator, &mFramebuffer);
+		result = vkCreateFramebuffer(device, &framebufferCI, gVulkanAllocator, &mFramebuffer);
 		assert(result == VK_SUCCESS);
 	}
 
 	VulkanFramebuffer::~VulkanFramebuffer()
 	{
-		vkDestroyFramebuffer(mDevice, mFramebuffer, gVulkanAllocator);
-		vkDestroyRenderPass(mDevice, mRenderPass, gVulkanAllocator);
+		VkDevice device = mOwner->getDevice().getLogical();
+
+		vkDestroyFramebuffer(device, mFramebuffer, gVulkanAllocator);
+		vkDestroyRenderPass(device, mRenderPass, gVulkanAllocator);
 	}
 }

+ 27 - 5
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuPipelineState.cpp

@@ -25,7 +25,7 @@ namespace BansheeEngine
 
 	VulkanGraphicsPipelineStateCore::VulkanGraphicsPipelineStateCore(const PIPELINE_STATE_CORE_DESC& desc,
 																	 GpuDeviceFlags deviceMask)
-		:GraphicsPipelineStateCore(desc, deviceMask), mDeviceMask(deviceMask)
+		:GraphicsPipelineStateCore(desc, deviceMask), mScissorEnabled(false), mDeviceMask(deviceMask)
 	{
 		
 	}
@@ -39,6 +39,8 @@ namespace BansheeEngine
 
 	void VulkanGraphicsPipelineStateCore::initialize()
 	{
+		Lock(mMutex);
+
 		std::pair<VkShaderStageFlagBits, GpuProgramCore*> stages[] =
 			{ 
 				{ VK_SHADER_STAGE_VERTEX_BIT, mData.vertexProgram.get() },
@@ -210,6 +212,11 @@ namespace BansheeEngine
 		mPipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
 		mPipelineInfo.basePipelineIndex = -1;
 
+		mScissorEnabled = rstProps.getScissorEnable();
+
+		if(mData.vertexProgram != nullptr)
+			mVertexDecl = mData.vertexProgram->getInputDeclaration();
+
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
 
 		VulkanDevice* devices[BS_MAX_DEVICES];
@@ -244,7 +251,16 @@ namespace BansheeEngine
 		GraphicsPipelineStateCore::initialize();
 	}
 
-	VkPipeline VulkanGraphicsPipelineStateCore::createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer,
+	VulkanPipeline* VulkanGraphicsPipelineStateCore::getPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth,
+								DrawOperationType drawOp, VkPipelineVertexInputStateCreateInfo* vertexInputState)
+	{
+		Lock(mMutex);
+
+		// TODO
+		return nullptr;
+	}
+
+	VulkanPipeline* VulkanGraphicsPipelineStateCore::createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer,
 														  bool readOnlyDepth, DrawOperationType drawOp,
 														  VkPipelineVertexInputStateCreateInfo* vertexInputState)
 	{
@@ -316,10 +332,11 @@ namespace BansheeEngine
 			stageOutputIdx++;
 		}
 
-		VkDevice device = mPerDeviceData[deviceIdx].device->getLogical();
+		VulkanDevice* device = mPerDeviceData[deviceIdx].device;
+		VkDevice vkDevice = mPerDeviceData[deviceIdx].device->getLogical();
 
 		VkPipeline pipeline;
-		VkResult result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &mPipelineInfo, gVulkanAllocator, &pipeline);
+		VkResult result = vkCreateGraphicsPipelines(vkDevice, VK_NULL_HANDLE, 1, &mPipelineInfo, gVulkanAllocator, &pipeline);
 		assert(result != VK_SUCCESS);
 
 		// Restore previous stencil op states
@@ -331,7 +348,7 @@ namespace BansheeEngine
 		mDepthStencilInfo.back.failOp = oldBackFailOp;
 		mDepthStencilInfo.back.depthFailOp = oldBackZFailOp;
 
-		return pipeline;
+		return device->getResourceManager().create<VulkanPipeline>(pipeline);
 	}
 
 	VulkanComputePipelineStateCore::VulkanComputePipelineStateCore(const SPtr<GpuProgramCore>& program, 
@@ -413,4 +430,9 @@ namespace BansheeEngine
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState);
 		ComputePipelineStateCore::initialize();
 	}
+
+	VulkanPipeline* VulkanComputePipelineStateCore::getPipeline(UINT32 deviceIdx) const
+	{
+		return mPerDeviceData[deviceIdx].pipeline;
+	}
 }

+ 50 - 17
Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderAPI.cpp

@@ -307,7 +307,10 @@ namespace BansheeEngine
 	void VulkanRenderAPI::setGraphicsPipeline(const SPtr<GraphicsPipelineStateCore>& pipelineState,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setPipelineState(pipelineState);
 
 		BS_INC_RENDER_STAT(NumPipelineStateChanges);
 	}
@@ -315,7 +318,10 @@ namespace BansheeEngine
 	void VulkanRenderAPI::setComputePipeline(const SPtr<ComputePipelineStateCore>& pipelineState,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setPipelineState(pipelineState);
 
 		BS_INC_RENDER_STAT(NumPipelineStateChanges);
 	}
@@ -342,20 +348,29 @@ namespace BansheeEngine
 
 	void VulkanRenderAPI::setViewport(const Rect2& vp, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setViewport(vp);
 	}
 
 	void VulkanRenderAPI::setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setVertexBuffers(index, buffers, numBuffers);
 
 		BS_INC_RENDER_STAT(NumVertexBufferBinds);
 	}
 
 	void VulkanRenderAPI::setIndexBuffer(const SPtr<IndexBufferCore>& buffer, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setIndexBuffer(buffer);
 
 		BS_INC_RENDER_STAT(NumIndexBufferBinds);
 	}
@@ -363,12 +378,18 @@ namespace BansheeEngine
 	void VulkanRenderAPI::setVertexDeclaration(const SPtr<VertexDeclarationCore>& vertexDeclaration,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setVertexDeclaration(vertexDeclaration);
 	}
 
 	void VulkanRenderAPI::setDrawOperation(DrawOperationType op, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setDrawOp(op);
 	}
 
 	void VulkanRenderAPI::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount,
@@ -376,7 +397,10 @@ namespace BansheeEngine
 	{
 		UINT32 primCount = 0;
 
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->draw(vertexOffset, vertexCount, instanceCount);
 
 		BS_INC_RENDER_STAT(NumDrawCalls);
 		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
@@ -388,7 +412,10 @@ namespace BansheeEngine
 	{
 		UINT32 primCount = 0;
 
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->drawIndexed(startIndex, indexCount, vertexOffset, instanceCount);
 
 		BS_INC_RENDER_STAT(NumDrawCalls);
 		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
@@ -398,7 +425,10 @@ namespace BansheeEngine
 	void VulkanRenderAPI::dispatchCompute(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->dispatch(numGroupsX, numGroupsY, numGroupsZ);
 
 		BS_INC_RENDER_STAT(NumComputeCalls);
 	}
@@ -406,12 +436,19 @@ namespace BansheeEngine
 	void VulkanRenderAPI::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		Rect2I area(left, top, right - left, bottom - top);
+		vkCB->setScissorRect(area);
 	}
 
 	void VulkanRenderAPI::setStencilRef(UINT32 value, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->setStencilRef(value);
 	}
 
 	void VulkanRenderAPI::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask,
@@ -438,11 +475,7 @@ namespace BansheeEngine
 		VulkanCommandBuffer* cb = getCB(commandBuffer);
 		VulkanCmdBuffer* vkCB = cb->getInternal();
 
-		if(vkCB->isInRenderPass())
-			vkCB->endRenderPass();
-
-		// We don't actually begin a new render pass until the next render-pass specific command gets queued on the CB
-		vkCB->setRenderTarget(target);
+		vkCB->setRenderTarget(target, readOnlyDepthStencil);
 		
 		BS_INC_RENDER_STAT(NumRenderTargetChanges);
 	}

+ 5 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanSwapChain.cpp

@@ -211,6 +211,8 @@ namespace BansheeEngine
 			mDepthStencilMemory = VK_NULL_HANDLE;
 		}
 
+		VulkanResourceManager& resManager = device->getResourceManager();
+
 		// Create a framebuffer for each swap chain buffer
 		UINT32 numFramebuffers = (UINT32)mSurfaces.size();
 		for (UINT32 i = 0; i < numFramebuffers; i++)
@@ -227,7 +229,7 @@ namespace BansheeEngine
 			desc.depth.format = depthFormat;
 			desc.depth.view = mDepthStencilView;
 
-			mSurfaces[i].framebuffer = bs_new<VulkanFramebuffer>(device, desc);
+			mSurfaces[i].framebuffer = resManager.create<VulkanFramebuffer>(device, desc);
 		}
 	}
 
@@ -288,7 +290,8 @@ namespace BansheeEngine
 		{
 			for (auto& surface : mSurfaces)
 			{
-				bs_delete(surface.framebuffer);
+				surface.framebuffer->destroy();
+				surface.framebuffer = nullptr;
 
 				vkDestroySemaphore(logicalDevice, surface.sync, gVulkanAllocator);
 				vkDestroyImageView(logicalDevice, surface.view, gVulkanAllocator);

+ 5 - 9
Source/BansheeVulkanRenderAPI/Source/Win32/BsWin32RenderWindow.cpp

@@ -29,6 +29,9 @@ namespace BansheeEngine
 
 	Win32RenderWindowCore::~Win32RenderWindowCore()
 	{ 
+		SPtr<VulkanDevice> presentDevice = mRenderAPI._getPresentDevice();
+		presentDevice->waitIdle();
+
 		Win32RenderWindowProperties& props = mProperties;
 		props.mActive = false;
 
@@ -492,15 +495,8 @@ namespace BansheeEngine
 	{
 		if (name == "FB")
 		{
-			VkFramebuffer* fb = (VkFramebuffer*)data;
-			*fb = mSwapChain->getBackBuffer().framebuffer->getFramebuffer();
-			return;
-		}
-
-		if (name == "RP")
-		{
-			VkRenderPass* renderPass = (VkRenderPass*)data;
-			*renderPass = mSwapChain->getBackBuffer().framebuffer->getRenderPass();
+			VulkanFramebuffer** fb = (VulkanFramebuffer**)data;
+			*fb = mSwapChain->getBackBuffer().framebuffer;
 			return;
 		}