ソースを参照

Vulkan graphics pipeline creation

BearishSun 9 年 前
コミット
952a02e2f2

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

@@ -224,4 +224,4 @@ namespace BansheeEngine
 	};
 	};
 
 
 	/** @} */
 	/** @} */
-}
+}

+ 16 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanFramebuffer.h

@@ -64,10 +64,26 @@ namespace BansheeEngine
 		/** Gets internal Vulkan framebuffer object. */
 		/** Gets internal Vulkan framebuffer object. */
 		VkFramebuffer getFramebuffer() const { return mFramebuffer; }
 		VkFramebuffer getFramebuffer() const { return mFramebuffer; }
 
 
+		/** Gets the total number of frame-buffer attachments, including both color and depth. */
+		UINT32 getNumAttachments() const { return mNumAttachments; }
+
+		/** Gets the number of color frame-buffer attachments. */
+		UINT32 getNumColorAttachments() const { return mNumColorAttachments; }
+
+		/** Returns true if the framebuffer has a depth attachment. */
+		bool hasDepthAttachment() const { return mHasDepth; }
+
+		/** Returns sample flags that determine if the framebuffer supports multi-sampling, and for how many samples. */
+		VkSampleCountFlagBits getSampleFlags() const { return mSampleFlags; }
 	private:
 	private:
 		VkRenderPass mRenderPass;
 		VkRenderPass mRenderPass;
 		VkFramebuffer mFramebuffer;
 		VkFramebuffer mFramebuffer;
 		VkDevice mDevice;
 		VkDevice mDevice;
+
+		UINT32 mNumAttachments;
+		UINT32 mNumColorAttachments;
+		bool mHasDepth;
+		VkSampleCountFlagBits mSampleFlags;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 46 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuPipelineState.h

@@ -3,6 +3,7 @@
 #pragma once
 #pragma once
 
 
 #include "BsVulkanPrerequisites.h"
 #include "BsVulkanPrerequisites.h"
+#include "BsVulkanResource.h"
 #include "BsGpuPipelineState.h"
 #include "BsGpuPipelineState.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -11,6 +12,20 @@ namespace BansheeEngine
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	 /** Wrapper around a Vulkan graphics pipeline that manages its usage and lifetime. */
+	class VulkanPipeline : public VulkanResource
+	{
+	public:
+		VulkanPipeline(VulkanResourceManager* owner, VkPipeline pipeline);
+		~VulkanPipeline();
+
+		/** Returns the internal handle to the Vulkan object. */
+		VkPipeline getHandle() const { return mPipeline; }
+
+	private:
+		VkPipeline mPipeline;
+	};
+
 	/**	Vulkan implementation of a GPU pipeline state. */
 	/**	Vulkan implementation of a GPU pipeline state. */
 	class VulkanGpuPipelineStateCore : public GpuPipelineStateCore
 	class VulkanGpuPipelineStateCore : public GpuPipelineStateCore
 	{
 	{
@@ -21,6 +36,37 @@ namespace BansheeEngine
 		friend class VulkanRenderStateCoreManager;
 		friend class VulkanRenderStateCoreManager;
 
 
 		VulkanGpuPipelineStateCore(const PIPELINE_STATE_CORE_DESC& desc, GpuDeviceFlags deviceMask);
 		VulkanGpuPipelineStateCore(const PIPELINE_STATE_CORE_DESC& desc, GpuDeviceFlags deviceMask);
+
+		/**	@copydoc GpuPipelineStateCore::initialize */
+		void initialize() override;
+
+		/** 
+		 * Create a new Vulkan graphics pipeline. 
+		 * 
+		 * @param[in]	device				Device to create 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]	pipelineLayout		Layout describing the resources used by the pipeline.
+		 * @param[in]	vertexInputState	State describing inputs to the vertex program.
+		 * @return							Vulkan graphics pipeline object.
+		 */
+		VkPipeline createPipeline(VkDevice device, VulkanFramebuffer* framebuffer, bool readOnlyDepth,
+								  DrawOperationType drawOp, VkPipelineLayout pipelineLayout,
+								  VkPipelineVertexInputStateCreateInfo* vertexInputState);
+
+		VkPipelineShaderStageCreateInfo mShaderStageInfos[5];
+		VkPipelineInputAssemblyStateCreateInfo mInputAssemblyInfo;
+		VkPipelineTessellationStateCreateInfo mTesselationInfo;
+		VkPipelineViewportStateCreateInfo mViewportInfo;
+		VkPipelineRasterizationStateCreateInfo mRasterizationInfo;
+		VkPipelineMultisampleStateCreateInfo mMultiSampleInfo;
+		VkPipelineDepthStencilStateCreateInfo mDepthStencilInfo;
+		VkPipelineColorBlendAttachmentState mAttachmentBlendStates[BS_MAX_MULTIPLE_RENDER_TARGETS];
+		VkPipelineColorBlendStateCreateInfo mColorBlendStateInfo;
+		VkPipelineDynamicStateCreateInfo mDynamicStateInfo;
+		VkDynamicState mDynamicStates[3];
+		VkGraphicsPipelineCreateInfo mPipelineInfo;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 3 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuProgram.h

@@ -17,6 +17,9 @@ namespace BansheeEngine
 	public:
 	public:
 		virtual ~VulkanGpuProgramCore();
 		virtual ~VulkanGpuProgramCore();
 
 
+		/** Returns a handle to the Vulkan shader module. */
+		VkShaderModule getHandle() const;
+
 	protected:
 	protected:
 		friend class VulkanGLSLProgramFactory;
 		friend class VulkanGLSLProgramFactory;
 
 

+ 15 - 12
Source/BansheeVulkanRenderAPI/Source/BsVulkanFramebuffer.cpp

@@ -7,7 +7,8 @@
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	VulkanFramebuffer::VulkanFramebuffer(const SPtr<VulkanDevice>& device, const VULKAN_FRAMEBUFFER_DESC& desc)
 	VulkanFramebuffer::VulkanFramebuffer(const SPtr<VulkanDevice>& device, const VULKAN_FRAMEBUFFER_DESC& desc)
-		:mDevice(device->getLogical())
+		: mDevice(device->getLogical()), mNumAttachments(0), mNumColorAttachments(0), mHasDepth(false)
+		, mSampleFlags(VK_SAMPLE_COUNT_1_BIT)
 	{
 	{
 		// Create render state
 		// Create render state
 		VkAttachmentDescription attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
 		VkAttachmentDescription attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
@@ -15,7 +16,7 @@ namespace BansheeEngine
 		VkAttachmentReference colorReferences[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		VkAttachmentReference colorReferences[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		VkAttachmentReference depthReference;
 		VkAttachmentReference depthReference;
 
 
-		VkSampleCountFlagBits sampleFlags = VulkanUtility::getSampleFlags(desc.numSamples);
+		mSampleFlags = VulkanUtility::getSampleFlags(desc.numSamples);
 
 
 		UINT32 attachmentIdx = 0;
 		UINT32 attachmentIdx = 0;
 		for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
 		for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
@@ -26,7 +27,7 @@ namespace BansheeEngine
 			VkAttachmentDescription& attachmentDesc = attachments[attachmentIdx];
 			VkAttachmentDescription& attachmentDesc = attachments[attachmentIdx];
 			attachmentDesc.flags = 0;
 			attachmentDesc.flags = 0;
 			attachmentDesc.format = desc.color[i].format;
 			attachmentDesc.format = desc.color[i].format;
-			attachmentDesc.samples = sampleFlags;
+			attachmentDesc.samples = mSampleFlags;
 			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 			attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 			attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@@ -47,15 +48,15 @@ namespace BansheeEngine
 ;			attachmentIdx++;
 ;			attachmentIdx++;
 		}
 		}
 
 
-		UINT32 numColorAttachments = attachmentIdx;
-		bool hasDepthAttachment = desc.depth.view != VK_NULL_HANDLE;
+		mNumColorAttachments = attachmentIdx;
+		mHasDepth = desc.depth.view != VK_NULL_HANDLE;
 
 
-		if (hasDepthAttachment)
+		if (mHasDepth)
 		{
 		{
 			VkAttachmentDescription& attachmentDesc = attachments[attachmentIdx];
 			VkAttachmentDescription& attachmentDesc = attachments[attachmentIdx];
 			attachmentDesc.flags = 0;
 			attachmentDesc.flags = 0;
 			attachmentDesc.format = desc.depth.format;
 			attachmentDesc.format = desc.depth.format;
-			attachmentDesc.samples = sampleFlags;
+			attachmentDesc.samples = mSampleFlags;
 			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 			attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 			attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
@@ -71,22 +72,24 @@ namespace BansheeEngine
 			attachmentIdx++;
 			attachmentIdx++;
 		}
 		}
 
 
+		mNumAttachments = attachmentIdx;
+
 		VkSubpassDescription subpassDesc;
 		VkSubpassDescription subpassDesc;
 		subpassDesc.flags = 0;
 		subpassDesc.flags = 0;
 		subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
 		subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
-		subpassDesc.colorAttachmentCount = numColorAttachments;
+		subpassDesc.colorAttachmentCount = mNumColorAttachments;
 		subpassDesc.inputAttachmentCount = 0;
 		subpassDesc.inputAttachmentCount = 0;
 		subpassDesc.pInputAttachments = nullptr;
 		subpassDesc.pInputAttachments = nullptr;
 		subpassDesc.preserveAttachmentCount = 0;
 		subpassDesc.preserveAttachmentCount = 0;
 		subpassDesc.pPreserveAttachments = nullptr;
 		subpassDesc.pPreserveAttachments = nullptr;
 		subpassDesc.pResolveAttachments = nullptr;
 		subpassDesc.pResolveAttachments = nullptr;
 
 
-		if (numColorAttachments > 0)
+		if (mNumColorAttachments > 0)
 			subpassDesc.pColorAttachments = colorReferences;
 			subpassDesc.pColorAttachments = colorReferences;
 		else
 		else
 			subpassDesc.pColorAttachments = nullptr;
 			subpassDesc.pColorAttachments = nullptr;
 
 
-		if (hasDepthAttachment)
+		if (mHasDepth)
 			subpassDesc.pDepthStencilAttachment = &depthReference;
 			subpassDesc.pDepthStencilAttachment = &depthReference;
 		else
 		else
 			subpassDesc.pDepthStencilAttachment = nullptr;
 			subpassDesc.pDepthStencilAttachment = nullptr;
@@ -114,7 +117,7 @@ namespace BansheeEngine
 		renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
 		renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
 		renderPassCI.pNext = nullptr;
 		renderPassCI.pNext = nullptr;
 		renderPassCI.flags = 0;
 		renderPassCI.flags = 0;
-		renderPassCI.attachmentCount = attachmentIdx;
+		renderPassCI.attachmentCount = mNumAttachments;
 		renderPassCI.pAttachments = attachments;
 		renderPassCI.pAttachments = attachments;
 		renderPassCI.subpassCount = 1;
 		renderPassCI.subpassCount = 1;
 		renderPassCI.pSubpasses = &subpassDesc;
 		renderPassCI.pSubpasses = &subpassDesc;
@@ -130,7 +133,7 @@ namespace BansheeEngine
 		framebufferCI.pNext = nullptr;
 		framebufferCI.pNext = nullptr;
 		framebufferCI.flags = 0;
 		framebufferCI.flags = 0;
 		framebufferCI.renderPass = mRenderPass;
 		framebufferCI.renderPass = mRenderPass;
-		framebufferCI.attachmentCount = attachmentIdx;
+		framebufferCI.attachmentCount = mNumAttachments;
 		framebufferCI.pAttachments = attachmentViews;
 		framebufferCI.pAttachments = attachmentViews;
 		framebufferCI.width = desc.width;
 		framebufferCI.width = desc.width;
 		framebufferCI.height = desc.height;
 		framebufferCI.height = desc.height;

+ 260 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuPipelineState.cpp

@@ -1,18 +1,277 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanGpuPipelineState.h"
 #include "BsVulkanGpuPipelineState.h"
+#include "BsVulkanDevice.h"
+#include "BsVulkanGpuProgram.h"
+#include "BsVulkanFramebuffer.h"
+#include "BsVulkanUtility.h"
+#include "BsRasterizerState.h"
+#include "BsDepthStencilState.h"
+#include "BsBlendState.h"
 #include "BsRenderStats.h"
 #include "BsRenderStats.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	VulkanPipeline::VulkanPipeline(VulkanResourceManager* owner, VkPipeline pipeline)
+		:VulkanResource(owner, true), mPipeline(pipeline)
+	{ }
+
+	VulkanPipeline::~VulkanPipeline()
+	{
+		vkDestroyPipeline(mOwner->getDevice().getLogical(), mPipeline, gVulkanAllocator);
+	}
+
 	VulkanGpuPipelineStateCore::VulkanGpuPipelineStateCore(const PIPELINE_STATE_CORE_DESC& desc, GpuDeviceFlags deviceMask)
 	VulkanGpuPipelineStateCore::VulkanGpuPipelineStateCore(const PIPELINE_STATE_CORE_DESC& desc, GpuDeviceFlags deviceMask)
 		:GpuPipelineStateCore(desc, deviceMask)
 		:GpuPipelineStateCore(desc, deviceMask)
 	{
 	{
-		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState);
+		
 	}
 	}
 
 
 	VulkanGpuPipelineStateCore::~VulkanGpuPipelineStateCore()
 	VulkanGpuPipelineStateCore::~VulkanGpuPipelineStateCore()
 	{
 	{
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_PipelineState);
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_PipelineState);
 	}
 	}
+
+	void VulkanGpuPipelineStateCore::initialize()
+	{
+		std::pair<VkShaderStageFlagBits, GpuProgramCore*> stages[] =
+			{ 
+				{ VK_SHADER_STAGE_VERTEX_BIT, mData.vertexProgram.get() },
+				{ VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, mData.hullProgram.get() },
+				{ VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, mData.domainProgram.get() },
+				{ VK_SHADER_STAGE_GEOMETRY_BIT, mData.geometryProgram.get() },
+				{ VK_SHADER_STAGE_FRAGMENT_BIT, mData.fragmentProgram.get() }
+			};
+
+		UINT32 stageOutputIdx = 0;
+		UINT32 numStages = sizeof(stages) / sizeof(stages[0]);
+		for(UINT32 i = 0; i < numStages; i++)
+		{
+			VulkanGpuProgramCore* program = static_cast<VulkanGpuProgramCore*>(stages[i].second);
+			if (program == nullptr)
+				continue;
+
+			VkPipelineShaderStageCreateInfo& stageCI = mShaderStageInfos[stageOutputIdx];
+			stageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+			stageCI.pNext = nullptr;
+			stageCI.flags = 0;
+			stageCI.stage = stages[i].first;
+			stageCI.module = program->getHandle();
+			stageCI.pName = program->getProperties().getEntryPoint().c_str();
+			stageCI.pSpecializationInfo = nullptr;
+
+			stageOutputIdx++;
+		}
+
+		UINT32 numUsedStages = stageOutputIdx;
+
+		bool tesselationEnabled = mData.hullProgram != nullptr && mData.domainProgram != nullptr;
+
+		mInputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+		mInputAssemblyInfo.pNext = nullptr;
+		mInputAssemblyInfo.flags = 0;
+		mInputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // Assigned at runtime
+		mInputAssemblyInfo.primitiveRestartEnable = false;
+
+		mTesselationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+		mTesselationInfo.patchControlPoints = 3; // Assigned at runtime
+
+		mViewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+		mViewportInfo.pNext = nullptr;
+		mViewportInfo.flags = 0;
+		mViewportInfo.viewportCount = 1; // Spec says this need to be at least 1...
+		mViewportInfo.scissorCount = 1;
+		mViewportInfo.pViewports = nullptr; // Dynamic
+		mViewportInfo.pScissors = nullptr; // Dynamic
+
+		const RasterizerProperties& rstProps = getRasterizerState()->getProperties();
+		const BlendProperties& blendProps = getBlendState()->getProperties();
+		const DepthStencilProperties dsProps = getDepthStencilState()->getProperties();
+
+		mRasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+		mRasterizationInfo.pNext = nullptr;
+		mRasterizationInfo.flags = 0;
+		mRasterizationInfo.depthClampEnable = !rstProps.getDepthClipEnable();
+		mRasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
+		mRasterizationInfo.polygonMode = VulkanUtility::getPolygonMode(rstProps.getPolygonMode());
+		mRasterizationInfo.cullMode = VulkanUtility::getCullMode(rstProps.getCullMode());
+		mRasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+		mRasterizationInfo.depthBiasEnable = rstProps.getDepthBias() != 0.0f;
+		mRasterizationInfo.depthBiasConstantFactor = rstProps.getDepthBias();
+		mRasterizationInfo.depthBiasSlopeFactor = rstProps.getSlopeScaledDepthBias();
+		mRasterizationInfo.depthBiasClamp = mRasterizationInfo.depthClampEnable ? rstProps.getDepthBiasClamp() : 0.0f;
+		mRasterizationInfo.lineWidth = 1.0f;
+
+		mMultiSampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+		mMultiSampleInfo.pNext = nullptr;
+		mMultiSampleInfo.flags = 0;
+		mMultiSampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; // Assigned at runtime
+		mMultiSampleInfo.sampleShadingEnable = VK_FALSE; // When enabled, perform shading per sample instead of per pixel (more expensive, essentially FSAA)
+		mMultiSampleInfo.minSampleShading = 1.0f; // Minimum percent of samples to run full shading for when sampleShadingEnable is enabled (1.0f to run for all)
+		mMultiSampleInfo.pSampleMask = nullptr; // Normally one bit for each sample: e.g. 0x0000000F to enable all samples in a 4-sample setup
+		mMultiSampleInfo.alphaToCoverageEnable = blendProps.getAlphaToCoverageEnabled();
+		mMultiSampleInfo.alphaToOneEnable = VK_FALSE;
+
+		VkStencilOpState stencilFrontInfo;
+		stencilFrontInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilFrontCompFunc());
+		stencilFrontInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontZFailOp());
+		stencilFrontInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontPassOp());
+		stencilFrontInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontFailOp());
+		stencilFrontInfo.reference = 0; // Dynamic
+		stencilFrontInfo.compareMask = (UINT32)dsProps.getStencilReadMask();
+		stencilFrontInfo.writeMask = (UINT32)dsProps.getStencilWriteMask();
+
+		VkStencilOpState stencilBackInfo;
+		stencilBackInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilBackCompFunc());
+		stencilBackInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilBackZFailOp());
+		stencilBackInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilBackPassOp());
+		stencilBackInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilBackFailOp());
+		stencilBackInfo.reference = 0; // Dynamic
+		stencilBackInfo.compareMask = (UINT32)dsProps.getStencilReadMask();
+		stencilBackInfo.writeMask = (UINT32)dsProps.getStencilWriteMask();
+
+		mDepthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+		mDepthStencilInfo.pNext = nullptr;
+		mDepthStencilInfo.flags = 0;
+		mDepthStencilInfo.depthBoundsTestEnable = false;
+		mDepthStencilInfo.minDepthBounds = 0.0f;
+		mDepthStencilInfo.maxDepthBounds = 1.0f;
+		mDepthStencilInfo.depthTestEnable = dsProps.getDepthReadEnable();
+		mDepthStencilInfo.depthWriteEnable = dsProps.getDepthWriteEnable();
+		mDepthStencilInfo.depthCompareOp = VulkanUtility::getCompareOp(dsProps.getDepthComparisonFunc());
+		mDepthStencilInfo.front = stencilFrontInfo;
+		mDepthStencilInfo.back = stencilBackInfo;
+		mDepthStencilInfo.stencilTestEnable = dsProps.getStencilEnable();
+
+		for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
+		{
+			UINT32 rtIdx = 0;
+			if (blendProps.getIndependantBlendEnable())
+				rtIdx = i;
+
+			VkPipelineColorBlendAttachmentState& blendState = mAttachmentBlendStates[i];
+			blendState.blendEnable = blendProps.getBlendEnabled(rtIdx);
+			blendState.colorBlendOp = VulkanUtility::getBlendOp(blendProps.getBlendOperation(rtIdx));
+			blendState.srcColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getSrcBlend(rtIdx));
+			blendState.dstColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getDstBlend(rtIdx));
+			blendState.alphaBlendOp = VulkanUtility::getBlendOp(blendProps.getAlphaBlendOperation(rtIdx));
+			blendState.srcAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaSrcBlend(rtIdx));
+			blendState.dstAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaDstBlend(rtIdx));
+			blendState.colorWriteMask = blendProps.getRenderTargetWriteMask(rtIdx) & 0xF;
+		}
+
+		mColorBlendStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+		mColorBlendStateInfo.pNext = nullptr;
+		mColorBlendStateInfo.flags = 0;
+		mColorBlendStateInfo.logicOpEnable = VK_FALSE;
+		mColorBlendStateInfo.logicOp = VK_LOGIC_OP_NO_OP;
+		mColorBlendStateInfo.attachmentCount = 0; // Assigned at runtime
+		mColorBlendStateInfo.pAttachments = mAttachmentBlendStates;
+		mColorBlendStateInfo.blendConstants[0] = 0.0f;
+		mColorBlendStateInfo.blendConstants[1] = 0.0f;
+		mColorBlendStateInfo.blendConstants[2] = 0.0f;
+		mColorBlendStateInfo.blendConstants[3] = 0.0f;
+
+		mDynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT;
+		mDynamicStates[1] = VK_DYNAMIC_STATE_SCISSOR;
+		mDynamicStates[2] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
+
+		UINT32 numDynamicStates = sizeof(mDynamicStates) / sizeof(mDynamicStates[0]);
+		assert(numDynamicStates == 3);
+
+		mDynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+		mDynamicStateInfo.pNext = nullptr;
+		mDynamicStateInfo.flags = 0;
+		mDynamicStateInfo.dynamicStateCount = numDynamicStates;
+		mDynamicStateInfo.pDynamicStates = mDynamicStates;
+
+		mPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+		mPipelineInfo.pNext = nullptr;
+		mPipelineInfo.flags = 0;
+		mPipelineInfo.stageCount = numUsedStages;
+		mPipelineInfo.pStages = mShaderStageInfos;
+		mPipelineInfo.pVertexInputState = nullptr; // Assigned at runtime
+		mPipelineInfo.pInputAssemblyState = &mInputAssemblyInfo;
+		mPipelineInfo.pTessellationState = tesselationEnabled ? &mTesselationInfo : nullptr;
+		mPipelineInfo.pViewportState = &mViewportInfo;
+		mPipelineInfo.pRasterizationState = &mRasterizationInfo;
+		mPipelineInfo.pMultisampleState = &mMultiSampleInfo;
+		mPipelineInfo.pDepthStencilState = nullptr; // Assigned at runtime
+		mPipelineInfo.pColorBlendState = nullptr; // Assigned at runtime
+		mPipelineInfo.pDynamicState = &mDynamicStateInfo;
+		mPipelineInfo.renderPass = VK_NULL_HANDLE; // Assigned at runtime
+		mPipelineInfo.layout = VK_NULL_HANDLE; // Assigned at runtime
+		mPipelineInfo.subpass = 0;
+		mPipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+		mPipelineInfo.basePipelineIndex = -1;
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState);
+		GpuPipelineStateCore::initialize();
+	}
+
+	VkPipeline VulkanGpuPipelineStateCore::createPipeline(VkDevice device, VulkanFramebuffer* framebuffer,
+														  bool readOnlyDepth, DrawOperationType drawOp,
+														  VkPipelineLayout pipelineLayout,
+														  VkPipelineVertexInputStateCreateInfo* vertexInputState)
+	{
+		mInputAssemblyInfo.topology = VulkanUtility::getDrawOp(drawOp);
+		mTesselationInfo.patchControlPoints = 3; // Not provided by our shaders for now
+		mMultiSampleInfo.rasterizationSamples = framebuffer->getSampleFlags();
+		mColorBlendStateInfo.attachmentCount = framebuffer->getNumAttachments();
+
+		const DepthStencilProperties dsProps = getDepthStencilState()->getProperties();
+		bool enableDepthWrites = dsProps.getDepthWriteEnable() && !readOnlyDepth;
+
+		mDepthStencilInfo.depthWriteEnable = enableDepthWrites; // If depth stencil attachment is read only, depthWriteEnable must be VK_FALSE
+
+		// Save stencil ops as we might need to change them if depth/stencil is read-only
+		VkStencilOp oldFrontPassOp = mDepthStencilInfo.front.passOp;
+		VkStencilOp oldFrontFailOp = mDepthStencilInfo.front.failOp;
+		VkStencilOp oldFrontZFailOp = mDepthStencilInfo.front.depthFailOp;
+
+		VkStencilOp oldBackPassOp = mDepthStencilInfo.back.passOp;
+		VkStencilOp oldBackFailOp = mDepthStencilInfo.back.failOp;
+		VkStencilOp oldBackZFailOp = mDepthStencilInfo.back.depthFailOp;
+
+		if(!enableDepthWrites)
+		{
+			// Disable any stencil writes
+			mDepthStencilInfo.front.passOp = VK_STENCIL_OP_KEEP;
+			mDepthStencilInfo.front.failOp = VK_STENCIL_OP_KEEP;
+			mDepthStencilInfo.front.depthFailOp = VK_STENCIL_OP_KEEP;
+
+			mDepthStencilInfo.back.passOp = VK_STENCIL_OP_KEEP;
+			mDepthStencilInfo.back.failOp = VK_STENCIL_OP_KEEP;
+			mDepthStencilInfo.back.depthFailOp = VK_STENCIL_OP_KEEP;
+		}
+
+		mPipelineInfo.renderPass = framebuffer->getRenderPass();
+		mPipelineInfo.layout = pipelineLayout;
+		mPipelineInfo.pVertexInputState = vertexInputState;
+
+		if (framebuffer->hasDepthAttachment())
+			mPipelineInfo.pDepthStencilState = &mDepthStencilInfo;
+		else
+			mPipelineInfo.pDepthStencilState = nullptr;
+
+		if (framebuffer->getNumColorAttachments() > 0)
+			mPipelineInfo.pColorBlendState = &mColorBlendStateInfo;
+		else
+			mPipelineInfo.pColorBlendState = nullptr;
+
+		VkPipeline pipeline;
+		VkResult result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &mPipelineInfo, gVulkanAllocator, &pipeline);
+		assert(result != VK_SUCCESS);
+
+		// Restore previous stencil op states
+		mDepthStencilInfo.front.passOp = oldFrontPassOp;
+		mDepthStencilInfo.front.failOp = oldFrontFailOp;
+		mDepthStencilInfo.front.depthFailOp = oldFrontZFailOp;
+
+		mDepthStencilInfo.back.passOp = oldBackPassOp;
+		mDepthStencilInfo.back.failOp = oldBackFailOp;
+		mDepthStencilInfo.back.depthFailOp = oldBackZFailOp;
+
+		return pipeline;
+	}
 }
 }

+ 6 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuProgram.cpp

@@ -34,4 +34,10 @@ namespace BansheeEngine
 
 
 		GpuProgramCore::initialize();
 		GpuProgramCore::initialize();
 	}
 	}
+
+	VkShaderModule VulkanGpuProgramCore::getHandle() const
+	{
+		// TODO
+		return VK_NULL_HANDLE;
+	}
 }
 }