VkPipeline simple implementation

Added a few class members and adjusted the VkPipeline constructor
to extract basic parameters which will be used for rendering, like:
- Basic sw::Context parameters
- Scissor
- Viewport
- BlendConstants

Note: sw::Context should eventually be replaced by VkPipeline and be
      used directly by sw::Renderer once all existing OpenGL ES 3.0
      has been converted from VkPipeline.

(Chris: rebase + build system fixes for CMake path)

Change-Id: I7e7a9ff3c768da8e8c1e9461e140af4986429602
Reviewed-on: https://swiftshader-review.googlesource.com/c/22613
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Corentin Wallez <cwallez@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d277cd2..0068ffb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1977,10 +1977,30 @@
     ${VULKAN_DIR}/*.cpp
     ${VULKAN_DIR}/*.h
     ${VULKAN_DIR}/*.hpp
-    ${SOURCE_DIR}/System/Memory.cpp
-    ${SOURCE_DIR}/System/Memory.hpp
+    ${SOURCE_DIR}/System/CPUID.cpp
+    ${SOURCE_DIR}/System/CPUID.hpp
+    ${SOURCE_DIR}/System/Configurator.cpp
+    ${SOURCE_DIR}/System/Configurator.hpp
     ${SOURCE_DIR}/System/Debug.cpp
     ${SOURCE_DIR}/System/Debug.hpp
+    ${SOURCE_DIR}/System/Half.cpp
+    ${SOURCE_DIR}/System/Half.hpp
+    ${SOURCE_DIR}/System/Math.cpp
+    ${SOURCE_DIR}/System/Math.hpp
+    ${SOURCE_DIR}/System/Memory.cpp
+    ${SOURCE_DIR}/System/Memory.hpp
+    ${SOURCE_DIR}/System/Resource.cpp
+    ${SOURCE_DIR}/System/Resource.hpp
+    ${SOURCE_DIR}/System/Socket.cpp
+    ${SOURCE_DIR}/System/Socket.hpp
+    ${SOURCE_DIR}/System/Thread.cpp
+    ${SOURCE_DIR}/System/Thread.hpp
+    ${SOURCE_DIR}/System/Timer.cpp
+    ${SOURCE_DIR}/System/Timer.hpp
+    ${SOURCE_DIR}/Device/*.cpp
+    ${SOURCE_DIR}/Device/*.hpp
+    ${SOURCE_DIR}/Pipeline/*.cpp
+    ${SOURCE_DIR}/Pipeline/*.hpp
     ${CMAKE_CURRENT_SOURCE_DIR}/include/vulkan/*.h}
 )
 
@@ -2153,7 +2173,7 @@
         PREFIX ""
     )
     set_shared_library_export_map(libvk_swiftshader ${SOURCE_DIR}/Vulkan)
-    target_link_libraries(libvk_swiftshader ${OS_LIBS})
+    target_link_libraries(libvk_swiftshader ${Reactor} ${OS_LIBS})
     add_custom_command(
         TARGET libvk_swiftshader
         POST_BUILD
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 04b96d8..2282df2 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -13,12 +13,354 @@
 // limitations under the License.
 
 #include "VkPipeline.hpp"
+#include "VkShaderModule.hpp"
+
+namespace
+{
+
+sw::DrawType Convert(VkPrimitiveTopology topology)
+{
+	switch(topology)
+	{
+	case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
+		return sw::DRAW_POINTLIST;
+	case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
+		return sw::DRAW_LINELIST;
+	case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+		return sw::DRAW_LINESTRIP;
+	case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
+		return sw::DRAW_TRIANGLELIST;
+	case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
+		return sw::DRAW_TRIANGLESTRIP;
+	case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+		return sw::DRAW_TRIANGLEFAN;
+	case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
+	case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
+	case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
+	case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
+		// geometry shader specific
+		ASSERT(false);
+		break;
+	case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
+		// tesselation shader specific
+		ASSERT(false);
+		break;
+	default:
+		UNIMPLEMENTED();
+	}
+
+	return sw::DRAW_TRIANGLELIST;
+}
+
+sw::Rect Convert(const VkRect2D& rect)
+{
+	return sw::Rect(rect.offset.x, rect.offset.y, rect.offset.x + rect.extent.width, rect.offset.y + rect.extent.height);
+}
+
+sw::StreamType getStreamType(VkFormat format)
+{
+	switch(format)
+	{
+	case VK_FORMAT_R8_UNORM:
+	case VK_FORMAT_R8G8_UNORM:
+	case VK_FORMAT_R8G8B8A8_UNORM:
+	case VK_FORMAT_R8_UINT:
+	case VK_FORMAT_R8G8_UINT:
+	case VK_FORMAT_R8G8B8A8_UINT:
+	case VK_FORMAT_B8G8R8A8_UNORM:
+	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
+	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
+		return sw::STREAMTYPE_BYTE;
+	case VK_FORMAT_R8_SNORM:
+	case VK_FORMAT_R8_SINT:
+	case VK_FORMAT_R8G8_SNORM:
+	case VK_FORMAT_R8G8_SINT:
+	case VK_FORMAT_R8G8B8A8_SNORM:
+	case VK_FORMAT_R8G8B8A8_SINT:
+	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
+	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
+		return sw::STREAMTYPE_SBYTE;
+	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+		return sw::STREAMTYPE_2_10_10_10_UINT;
+	case VK_FORMAT_R16_UNORM:
+	case VK_FORMAT_R16_UINT:
+	case VK_FORMAT_R16G16_UNORM:
+	case VK_FORMAT_R16G16_UINT:
+	case VK_FORMAT_R16G16B16A16_UNORM:
+	case VK_FORMAT_R16G16B16A16_UINT:
+		return sw::STREAMTYPE_USHORT;
+	case VK_FORMAT_R16_SNORM:
+	case VK_FORMAT_R16_SINT:
+	case VK_FORMAT_R16G16_SNORM:
+	case VK_FORMAT_R16G16_SINT:
+	case VK_FORMAT_R16G16B16A16_SNORM:
+	case VK_FORMAT_R16G16B16A16_SINT:
+		return sw::STREAMTYPE_SHORT;
+	case VK_FORMAT_R16_SFLOAT:
+	case VK_FORMAT_R16G16_SFLOAT:
+	case VK_FORMAT_R16G16B16A16_SFLOAT:
+		return sw::STREAMTYPE_HALF;
+	case VK_FORMAT_R32_UINT:
+	case VK_FORMAT_R32G32_UINT:
+	case VK_FORMAT_R32G32B32_UINT:
+	case VK_FORMAT_R32G32B32A32_UINT:
+		return sw::STREAMTYPE_UINT;
+	case VK_FORMAT_R32_SINT:
+	case VK_FORMAT_R32G32_SINT:
+	case VK_FORMAT_R32G32B32_SINT:
+	case VK_FORMAT_R32G32B32A32_SINT:
+		return sw::STREAMTYPE_INT;
+	case VK_FORMAT_R32_SFLOAT:
+	case VK_FORMAT_R32G32_SFLOAT:
+	case VK_FORMAT_R32G32B32_SFLOAT:
+	case VK_FORMAT_R32G32B32A32_SFLOAT:
+		return sw::STREAMTYPE_FLOAT;
+	default:
+		UNIMPLEMENTED();
+	}
+
+	return sw::STREAMTYPE_BYTE;
+}
+
+uint32_t getNumberOfChannels(VkFormat format)
+{
+	switch(format)
+	{
+	case VK_FORMAT_R8_UNORM:
+	case VK_FORMAT_R8_SNORM:
+	case VK_FORMAT_R8_UINT:
+	case VK_FORMAT_R8_SINT:
+	case VK_FORMAT_R16_UNORM:
+	case VK_FORMAT_R16_SNORM:
+	case VK_FORMAT_R16_UINT:
+	case VK_FORMAT_R16_SINT:
+	case VK_FORMAT_R16_SFLOAT:
+	case VK_FORMAT_R32_UINT:
+	case VK_FORMAT_R32_SINT:
+	case VK_FORMAT_R32_SFLOAT:
+		return 1;
+	case VK_FORMAT_R8G8_UNORM:
+	case VK_FORMAT_R8G8_SNORM:
+	case VK_FORMAT_R8G8_UINT:
+	case VK_FORMAT_R8G8_SINT:
+	case VK_FORMAT_R16G16_UNORM:
+	case VK_FORMAT_R16G16_SNORM:
+	case VK_FORMAT_R16G16_UINT:
+	case VK_FORMAT_R16G16_SINT:
+	case VK_FORMAT_R16G16_SFLOAT:
+	case VK_FORMAT_R32G32_UINT:
+	case VK_FORMAT_R32G32_SINT:
+	case VK_FORMAT_R32G32_SFLOAT:
+		return 2;
+	case VK_FORMAT_R32G32B32_UINT:
+	case VK_FORMAT_R32G32B32_SINT:
+	case VK_FORMAT_R32G32B32_SFLOAT:
+		return 3;
+	case VK_FORMAT_R8G8B8A8_UNORM:
+	case VK_FORMAT_R8G8B8A8_SNORM:
+	case VK_FORMAT_R8G8B8A8_UINT:
+	case VK_FORMAT_R8G8B8A8_SINT:
+	case VK_FORMAT_B8G8R8A8_UNORM:
+	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
+	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
+	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
+	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
+	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+	case VK_FORMAT_R16G16B16A16_UNORM:
+	case VK_FORMAT_R16G16B16A16_SNORM:
+	case VK_FORMAT_R16G16B16A16_UINT:
+	case VK_FORMAT_R16G16B16A16_SINT:
+	case VK_FORMAT_R16G16B16A16_SFLOAT:
+	case VK_FORMAT_R32G32B32A32_UINT:
+	case VK_FORMAT_R32G32B32A32_SINT:
+	case VK_FORMAT_R32G32B32A32_SFLOAT:
+		return 4;
+	default:
+		UNIMPLEMENTED();
+	}
+
+	return 0;
+}
+
+}
 
 namespace vk
 {
 
 GraphicsPipeline::GraphicsPipeline(const VkGraphicsPipelineCreateInfo* pCreateInfo, void* mem)
 {
+	if((pCreateInfo->flags != 0) ||
+	   (pCreateInfo->stageCount != 2) ||
+	   (pCreateInfo->pTessellationState != nullptr) ||
+	   (pCreateInfo->pDynamicState != nullptr) ||
+	   (pCreateInfo->subpass != 0) ||
+	   (pCreateInfo->basePipelineHandle != VK_NULL_HANDLE) ||
+	   (pCreateInfo->basePipelineIndex != 0))
+	{
+		UNIMPLEMENTED();
+	}
+
+	const VkPipelineShaderStageCreateInfo& vertexStage = pCreateInfo->pStages[0];
+	if((vertexStage.stage != VK_SHADER_STAGE_VERTEX_BIT) ||
+	   (vertexStage.flags != 0) ||
+	   (vertexStage.pSpecializationInfo != nullptr))
+	{
+		UNIMPLEMENTED();
+	}
+
+	const VkPipelineShaderStageCreateInfo& fragmentStage = pCreateInfo->pStages[1];
+	if((fragmentStage.stage != VK_SHADER_STAGE_FRAGMENT_BIT) ||
+	   (fragmentStage.flags != 0) ||
+	   (fragmentStage.pSpecializationInfo != nullptr))
+	{
+		UNIMPLEMENTED();
+	}
+
+	const VkPipelineVertexInputStateCreateInfo* vertexInputState = pCreateInfo->pVertexInputState;
+	if(vertexInputState->flags != 0)
+	{
+		UNIMPLEMENTED();
+	}
+
+	for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++)
+	{
+		const VkVertexInputBindingDescription* vertexBindingDescription = vertexInputState->pVertexBindingDescriptions;
+		context.input[vertexBindingDescription->binding].stride = vertexBindingDescription->stride;
+		if(vertexBindingDescription->inputRate != VK_VERTEX_INPUT_RATE_VERTEX)
+		{
+			UNIMPLEMENTED();
+		}
+	}
+
+	for(uint32_t i = 0; i < vertexInputState->vertexAttributeDescriptionCount; i++)
+	{
+		const VkVertexInputAttributeDescription* vertexAttributeDescriptions = vertexInputState->pVertexAttributeDescriptions;
+		sw::Stream& input = context.input[vertexAttributeDescriptions->binding];
+		input.count = getNumberOfChannels(vertexAttributeDescriptions->format);
+		input.type = getStreamType(vertexAttributeDescriptions->format);
+		input.normalized = !sw::Surface::isNonNormalizedInteger(vertexAttributeDescriptions->format);
+
+		if(vertexAttributeDescriptions->location != vertexAttributeDescriptions->binding)
+		{
+			UNIMPLEMENTED();
+		}
+		if(vertexAttributeDescriptions->offset != 0)
+		{
+			UNIMPLEMENTED();
+		}
+	}
+
+	const VkPipelineInputAssemblyStateCreateInfo* assemblyState = pCreateInfo->pInputAssemblyState;
+	if((assemblyState->flags != 0) ||
+	   (assemblyState->primitiveRestartEnable != 0))
+	{
+		UNIMPLEMENTED();
+	}
+
+	context.drawType = Convert(assemblyState->topology);
+
+	const VkPipelineViewportStateCreateInfo* viewportState = pCreateInfo->pViewportState;
+	if((viewportState->flags != 0) ||
+	   (viewportState->viewportCount != 1) ||
+	   (viewportState->scissorCount	!= 1))
+	{
+		UNIMPLEMENTED();
+	}
+
+	scissor = Convert(viewportState->pScissors[0]);
+	viewport = viewportState->pViewports[0];
+
+	const VkPipelineRasterizationStateCreateInfo* rasterizationState = pCreateInfo->pRasterizationState;
+	if((rasterizationState->flags != 0) ||
+	   (rasterizationState->depthClampEnable != 0) ||
+	   (rasterizationState->polygonMode != VK_POLYGON_MODE_FILL))
+	{
+		UNIMPLEMENTED();
+	}
+
+	context.rasterizerDiscard = rasterizationState->rasterizerDiscardEnable;
+	context.frontFacingCCW = rasterizationState->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE;
+	context.depthBias = (rasterizationState->depthBiasEnable ? rasterizationState->depthBiasConstantFactor : 0.0f);
+	context.slopeDepthBias = (rasterizationState->depthBiasEnable ? rasterizationState->depthBiasSlopeFactor : 0.0f);
+
+	const VkPipelineMultisampleStateCreateInfo* multisampleState = pCreateInfo->pMultisampleState;
+	if((multisampleState->flags != 0) ||
+	   (multisampleState->rasterizationSamples != VK_SAMPLE_COUNT_1_BIT) ||
+	   (multisampleState->sampleShadingEnable != 0) ||
+	   (multisampleState->pSampleMask != nullptr) ||
+	   (multisampleState->alphaToCoverageEnable != 0) ||
+	   (multisampleState->alphaToOneEnable != 0))
+	{
+		UNIMPLEMENTED();
+	}
+
+	const VkPipelineDepthStencilStateCreateInfo* depthStencilState = pCreateInfo->pDepthStencilState;
+	if((depthStencilState->flags != 0) ||
+	   (depthStencilState->depthBoundsTestEnable != 0) ||
+	   (depthStencilState->minDepthBounds != 0.0f) ||
+	   (depthStencilState->maxDepthBounds != 1.0f))
+	{
+		UNIMPLEMENTED();
+	}
+
+	context.depthBufferEnable = depthStencilState->depthTestEnable;
+	context.depthWriteEnable = depthStencilState->depthWriteEnable;
+	context.depthCompareMode = depthStencilState->depthCompareOp;
+
+	context.stencilEnable = context.twoSidedStencil = depthStencilState->stencilTestEnable;
+	if(context.stencilEnable)
+	{
+		context.stencilMask = depthStencilState->front.compareMask;
+		context.stencilCompareMode = depthStencilState->front.compareOp;
+		context.stencilZFailOperation = depthStencilState->front.depthFailOp;
+		context.stencilFailOperation = depthStencilState->front.failOp;
+		context.stencilPassOperation = depthStencilState->front.passOp;
+		context.stencilReference = depthStencilState->front.reference;
+		context.stencilWriteMask = depthStencilState->front.writeMask;
+
+		context.stencilMaskCCW = depthStencilState->back.compareMask;
+		context.stencilCompareModeCCW = depthStencilState->back.compareOp;
+		context.stencilZFailOperationCCW = depthStencilState->back.depthFailOp;
+		context.stencilFailOperationCCW = depthStencilState->back.failOp;
+		context.stencilPassOperationCCW = depthStencilState->back.passOp;
+		context.stencilReferenceCCW = depthStencilState->back.reference;
+		context.stencilWriteMaskCCW = depthStencilState->back.writeMask;
+	}
+
+	const VkPipelineColorBlendStateCreateInfo* colorBlendState = pCreateInfo->pColorBlendState;
+	if((colorBlendState->flags != 0) ||
+	   ((colorBlendState->logicOpEnable != 0) &&
+	    (colorBlendState->attachmentCount > 1)))
+	{
+		UNIMPLEMENTED();
+	}
+
+	context.colorLogicOpEnabled = colorBlendState->logicOpEnable;
+	context.logicalOperation = colorBlendState->logicOp;
+	blendConstants.r = colorBlendState->blendConstants[0];
+	blendConstants.g = colorBlendState->blendConstants[1];
+	blendConstants.b = colorBlendState->blendConstants[2];
+	blendConstants.a = colorBlendState->blendConstants[3];
+
+	if(colorBlendState->attachmentCount == 1)
+	{
+		const VkPipelineColorBlendAttachmentState& attachment = colorBlendState->pAttachments[0];
+		if(attachment.colorWriteMask != (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT))
+		{
+			UNIMPLEMENTED();
+		}
+
+		context.alphaBlendEnable = attachment.blendEnable;
+		context.separateAlphaBlendEnable = (attachment.alphaBlendOp != attachment.colorBlendOp) ||
+		                                   (attachment.dstAlphaBlendFactor != attachment.dstColorBlendFactor) ||
+		                                   (attachment.srcAlphaBlendFactor != attachment.srcColorBlendFactor);
+		context.blendOperationStateAlpha = attachment.alphaBlendOp;
+		context.blendOperationState = attachment.colorBlendOp;
+		context.destBlendFactorStateAlpha = attachment.dstAlphaBlendFactor;
+		context.destBlendFactorState = attachment.dstColorBlendFactor;
+		context.sourceBlendFactorStateAlpha = attachment.srcAlphaBlendFactor;
+		context.sourceBlendFactorState = attachment.srcColorBlendFactor;
+	}
 }
 
 void GraphicsPipeline::destroy(const VkAllocationCallbacks* pAllocator)
@@ -30,6 +372,32 @@
 	return 0;
 }
 
+void GraphicsPipeline::compileShaders(const VkAllocationCallbacks* pAllocator, const VkGraphicsPipelineCreateInfo* pCreateInfo)
+{
+	vertexRoutine = Cast(pCreateInfo->pStages[0].module)->compile(pAllocator);
+	fragmentRoutine = Cast(pCreateInfo->pStages[1].module)->compile(pAllocator);
+}
+
+const sw::Context& GraphicsPipeline::getContext() const
+{
+	return context;
+}
+
+const sw::Rect& GraphicsPipeline::getScissor() const
+{
+	return scissor;
+}
+
+const VkViewport& GraphicsPipeline::getViewport() const
+{
+	return viewport;
+}
+
+const sw::Color<float>& GraphicsPipeline::getBlendConstants() const
+{
+	return blendConstants;
+}
+
 ComputePipeline::ComputePipeline(const VkComputePipelineCreateInfo* pCreateInfo, void* mem)
 {
 }
diff --git a/src/Vulkan/VkPipeline.hpp b/src/Vulkan/VkPipeline.hpp
index 725e109..18327ef 100644
--- a/src/Vulkan/VkPipeline.hpp
+++ b/src/Vulkan/VkPipeline.hpp
@@ -16,6 +16,7 @@
 #define VK_PIPELINE_HPP_
 
 #include "VkObject.hpp"
+#include "Device/Renderer.hpp"
 
 namespace vk
 {
@@ -44,6 +45,21 @@
 #endif
 
 	static size_t ComputeRequiredAllocationSize(const VkGraphicsPipelineCreateInfo* pCreateInfo);
+
+	void compileShaders(const VkAllocationCallbacks* pAllocator, const VkGraphicsPipelineCreateInfo* pCreateInfo);
+
+	const sw::Context& getContext() const;
+	const sw::Rect& getScissor() const;
+	const VkViewport& getViewport() const;
+	const sw::Color<float>& getBlendConstants() const;
+
+private:
+	rr::Routine* vertexRoutine;

+	rr::Routine* fragmentRoutine;
+	sw::Context context;
+	sw::Rect scissor;
+	VkViewport viewport;
+	sw::Color<float> blendConstants;
 };
 
 class ComputePipeline : public Pipeline, public Object<ComputePipeline, VkPipeline>
diff --git a/src/Vulkan/VkShaderModule.cpp b/src/Vulkan/VkShaderModule.cpp
index 29bce29..4c824a3 100644
--- a/src/Vulkan/VkShaderModule.cpp
+++ b/src/Vulkan/VkShaderModule.cpp
@@ -34,4 +34,10 @@
 	return pCreateInfo->codeSize;
 }
 
+rr::Routine* ShaderModule::compile(const VkAllocationCallbacks* pAllocator)
+{
+	// FIXME: Compile the code here
+	return nullptr;
+}
+
 } // namespace vk
diff --git a/src/Vulkan/VkShaderModule.hpp b/src/Vulkan/VkShaderModule.hpp
index b179cbe..f7a4de7 100644
--- a/src/Vulkan/VkShaderModule.hpp
+++ b/src/Vulkan/VkShaderModule.hpp
@@ -17,6 +17,11 @@
 
 #include "VkObject.hpp"
 
+namespace rr
+{
+	class Routine;
+}
+
 namespace vk
 {
 
@@ -27,6 +32,8 @@
 	~ShaderModule() = delete;
 	void destroy(const VkAllocationCallbacks* pAllocator);
 
+	rr::Routine* compile(const VkAllocationCallbacks* pAllocator);
+
 	static size_t ComputeRequiredAllocationSize(const VkShaderModuleCreateInfo* pCreateInfo);
 
 private:
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 2b8f84c..249afe4 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -896,6 +896,10 @@
 			pPipelines[i] = VK_NULL_HANDLE;
 			errorResult = result;
 		}
+		else
+		{
+			static_cast<vk::GraphicsPipeline*>(vk::Cast(pPipelines[i]))->compileShaders(pAllocator, &pCreateInfos[i]);
+		}
 	}
 
 	return errorResult;