unit vPipelineManager; {$mode ObjFPC}{$H+} interface uses SysUtils, g23tree, Vulkan, vDevice, vDependence, vPipeline, vShader, vShaderExt, si_ci_vi_merged_enum; type TvColorBlendState=packed record logicOp :Byte; attachmentCount:Byte; blendConstants :array[0..3] of TVkFloat; end; TvVertexInput=packed record vertexBindingDescriptionCount :Byte; vertexAttributeDescriptionCount:Byte; VertexBindingDescriptions :AvVertexInputBindingDescription; VertexAttributeDescriptions :AvVertexInputAttributeDescription; end; PvGraphicsPipelineKey=^TvGraphicsPipelineKey; TvGraphicsPipelineKey=packed object FRenderPass :TvRenderPass; FShaderGroup:TvShaderGroup; Viewports:array[0..15] of TVkViewport; //viewportState.viewportCount Scissors :array[0..15] of TVkRect2D; //viewportState.scissorCount ColorBlends:array[0..7] of TVkPipelineColorBlendAttachmentState; //colorBlending.attachmentCount inputAssembly :TVkPipelineInputAssemblyStateCreateInfo; rasterizer :TVkPipelineRasterizationStateCreateInfo; ClipSpace :TVkBool32; DepthClip :TVkBool32; multisampling :TVkPipelineMultisampleStateCreateInfo; DepthStencil :TVkPipelineDepthStencilStateCreateInfo; vertexInputInfo:TvVertexInput; colorBlending :TvColorBlendState; viewportCount :Byte; provokingVertex :Byte; emulate_primtype:ShortInt; shader_primtype :ShortInt; Procedure Clear; Procedure SetVertexInput(const FAttrBuilder:TvAttrBuilder); Procedure SetPrimType(t,s:Integer); Procedure SetPrimReset(enable:TVkBool32); Procedure SetProvoking(t:TVkProvokingVertexModeEXT); Procedure AddVPort(const V:TVkViewport;const S:TVkRect2D); Procedure AddBlend(const b:TVkPipelineColorBlendAttachmentState); procedure SetBlendInfo(logicOp:TVkLogicOp;P:PSingle); end; TvGraphicsPipeline2=class(TvPipeline) Key:TvGraphicsPipelineKey; // Function Compile:Boolean; end; // PvComputePipelineKey=^TvComputePipelineKey; TvComputePipelineKey=packed object FShaderGroup:TvShaderGroup; end; TvComputePipeline2=class(TvPipeline) Key:TvComputePipelineKey; // Function Compile:Boolean; end; function FetchGraphicsPipeline(cmd:TvDependenciesObject;P:PvGraphicsPipelineKey):TvGraphicsPipeline2; function FetchComputePipeline (cmd:TvDependenciesObject;P:PvComputePipelineKey ):TvComputePipeline2; implementation // uses kern_rwlock; type TvGraphicsPipelineKey2Compare=object function c(a,b:PvGraphicsPipelineKey):Integer; static; end; TvComputePipelineKey2Compare=object function c(a,b:PvComputePipelineKey):Integer; static; end; TvGraphicsPipeline2Set=specialize T23treeSet; TvComputePipeline2Set =specialize T23treeSet; var global_lock_rt:Pointer=nil; global_lock_cs:Pointer=nil; FGlobalCache_rt:TvPipelineCache=nil; FGlobalCache_cs:TvPipelineCache=nil; FGraphicsPipeline2Set:TvGraphicsPipeline2Set; FComputePipeline2Set :TvComputePipeline2Set; // function TvGraphicsPipelineKey2Compare.c(a,b:PvGraphicsPipelineKey):Integer; begin Result:=CompareByte(a^,b^,SizeOf(TvGraphicsPipelineKey)); end; function TvComputePipelineKey2Compare.c(a,b:PvComputePipelineKey):Integer; begin Result:=Integer(Pointer(a^)>Pointer(b^))-Integer(Pointer(a^)-1) then begin inputAssembly.topology:=TVkPrimitiveTopology(s); shader_primtype:=s; end else begin inputAssembly.topology:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; shader_primtype :=-1; end; end; DI_PT_LINELOOP , DI_PT_QUADLIST , DI_PT_QUADSTRIP, DI_PT_POLYGON : begin inputAssembly.topology:=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; emulate_primtype:=ord(t); shader_primtype :=-1; end; end; end; Procedure TvGraphicsPipelineKey.SetPrimReset(enable:TVkBool32); begin inputAssembly.primitiveRestartEnable:=enable; end; Procedure TvGraphicsPipelineKey.SetProvoking(t:TVkProvokingVertexModeEXT); begin provokingVertex:=ord(t); end; Procedure TvGraphicsPipelineKey.AddVPort(const V:TVkViewport;const S:TVkRect2D); begin if (s.extent.width=0) or (s.extent.height=0) then Assert(false); if (viewportCount>15) then Exit; Viewports[viewportCount]:=V; Scissors [viewportCount]:=S; Inc(viewportCount); end; Procedure TvGraphicsPipelineKey.AddBlend(const b:TVkPipelineColorBlendAttachmentState); begin if (colorBlending.attachmentCount>7) then Exit; ColorBlends[colorBlending.attachmentCount]:=b; Inc(colorBlending.attachmentCount); end; type PVec4f=^TVec4f; TVec4f=array[0..3] of Single; procedure TvGraphicsPipelineKey.SetBlendInfo(logicOp:TVkLogicOp;P:PSingle); begin colorBlending.logicOp:=ord(logicOp); if (P=nil) then Exit; colorBlending.blendConstants:=PVec4f(P)^; end; /// Function TvGraphicsPipeline2.Compile:Boolean; type AVkPipelineShaderStageCreateInfo=array[0..6] of TVkPipelineShaderStageCreateInfo; var FLayout:TvPipelineLayout; FCache :TVkPipelineCache; r:TVkResult; Stages:AVkPipelineShaderStageCreateInfo; // info.stageCount info :TVkGraphicsPipelineCreateInfo; vertexInputInfo:TVkPipelineVertexInputStateCreateInfo; viewportState :TVkPipelineViewportStateCreateInfo; colorBlending :TVkPipelineColorBlendStateCreateInfo; dynamicState :TVkPipelineDynamicStateCreateInfo; rasterizer :TVkPipelineRasterizationStateCreateInfo; ProvokingVertex:TVkPipelineRasterizationProvokingVertexStateCreateInfoEXT; ClipSpace :TVkPipelineViewportDepthClipControlCreateInfoEXT; DepthClip :TVkPipelineRasterizationDepthClipStateCreateInfoEXT; pFeature:PAbstractFeature; dynamicStates :array[0..0] of TVkDynamicState; //dynamicState.dynamicStateCount procedure add_feature(P:PVkVoid); begin PAbstractFeature(P)^.pNext:=pFeature; pFeature:=P; end; begin Result:=False; if (FHandle<>VK_NULL_HANDLE) then Exit(True); if (Key.FRenderPass =nil) then Exit; if (Key.FShaderGroup=nil) then Exit; if (Key.viewportCount=0) then Exit; if (Key.FRenderPass.FHandle=VK_NULL_HANDLE) then Exit; FLayout:=Key.FShaderGroup.FLayout; if (FLayout=nil) then Exit; if (FLayout.FHandle=VK_NULL_HANDLE) then Exit; info:=Default(TVkGraphicsPipelineCreateInfo); Stages:=Default(AVkPipelineShaderStageCreateInfo); Key.FShaderGroup.FKey.ExportStages(@Stages,@info.stageCount); if (info.stageCount=0) then Exit; // vertexInputInfo:=Default(TVkPipelineVertexInputStateCreateInfo); vertexInputInfo.sType :=VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.vertexBindingDescriptionCount :=Key.vertexInputInfo.vertexBindingDescriptionCount; vertexInputInfo.vertexAttributeDescriptionCount:=Key.vertexInputInfo.vertexAttributeDescriptionCount; vertexInputInfo.pVertexBindingDescriptions :=@Key.vertexInputInfo.VertexBindingDescriptions[0]; vertexInputInfo.pVertexAttributeDescriptions :=@Key.vertexInputInfo.VertexAttributeDescriptions[0]; viewportState:=Default(TVkPipelineViewportStateCreateInfo); viewportState.sType :=VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewportState.viewportCount:=Key.viewportCount; viewportState.pViewports :=@Key.Viewports; viewportState.scissorCount :=Key.viewportCount; viewportState.pScissors :=@Key.Scissors; pFeature:=nil; //init ext if limits.VK_EXT_depth_clip_control then if (Key.ClipSpace=VK_TRUE) then begin ClipSpace:=Default(TVkPipelineViewportDepthClipControlCreateInfoEXT); ClipSpace.sType :=VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT; ClipSpace.negativeOneToOne:=Key.ClipSpace; // add_feature(@ClipSpace); end; viewportState.pNext:=pFeature; //save ext colorBlending:=Default(TVkPipelineColorBlendStateCreateInfo); colorBlending.sType :=VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.logicOpEnable :=ord(Key.colorBlending.logicOp<>ord(VK_LOGIC_OP_COPY)); colorBlending.logicOp :=TVkLogicOp(Key.colorBlending.logicOp); colorBlending.attachmentCount:=Key.colorBlending.attachmentCount; colorBlending.pAttachments :=@Key.ColorBlends; dynamicState:=Default(TVkPipelineDynamicStateCreateInfo); dynamicState.sType:=VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; if limits.VK_EXT_vertex_input_dynamic_state then begin dynamicStates[0]:=VK_DYNAMIC_STATE_VERTEX_INPUT_EXT; // dynamicState.dynamicStateCount:=1; dynamicState.pDynamicStates :=@dynamicStates[0]; end; rasterizer:=Key.rasterizer; pFeature:=nil; //init ext if limits.VK_EXT_provoking_vertex then begin ProvokingVertex:=Default(TVkPipelineRasterizationProvokingVertexStateCreateInfoEXT); ProvokingVertex.sType :=VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT; ProvokingVertex.provokingVertexMode:=TVkProvokingVertexModeEXT(Key.provokingVertex); // add_feature(@ProvokingVertex); end; if limits.VK_EXT_depth_clip_enable then begin DepthClip:=Default(TVkPipelineRasterizationDepthClipStateCreateInfoEXT); DepthClip.sType :=VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT; DepthClip.depthClipEnable:=Key.DepthClip; // add_feature(@DepthClip); end; rasterizer.pNext:=pFeature; //save ext info.sType :=VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; info.pStages :=@Stages; info.pVertexInputState :=@vertexInputInfo; info.pInputAssemblyState:=@Key.inputAssembly; info.pViewportState :=@viewportState; info.pRasterizationState:=@rasterizer; info.pMultisampleState :=@Key.multisampling; info.pDepthStencilState :=@Key.DepthStencil; info.pColorBlendState :=@colorBlending; info.pDynamicState :=@dynamicState; info.layout :=FLayout.FHandle; info.renderPass :=Key.FRenderPass.FHandle; info.subpass :=0; info.basePipelineHandle :=VK_NULL_HANDLE; info.basePipelineIndex :=-1; FCache:=VK_NULL_HANDLE; if (FPCache<>nil) then begin FCache:=FPCache.FHandle; end; r:=vkCreateGraphicsPipelines(Device.FHandle,FCache,1,@info,nil,@FHandle); if (r<>VK_SUCCESS) then begin Writeln(StdErr,'vkCreateGraphicsPipelines:',r); Exit; end; Result:=True; end; /// function TvComputePipeline2.Compile:Boolean; var FLayout:TvPipelineLayout; FCache :TVkPipelineCache; FShader:TvShaderExt; info:TVkComputePipelineCreateInfo; r:TVkResult; begin Result:=False; if (FHandle<>VK_NULL_HANDLE) then Exit(True); if (Key.FShaderGroup=nil) then Exit; FLayout:=Key.FShaderGroup.FLayout; if (FLayout=nil) then Exit; if (FLayout.FHandle=VK_NULL_HANDLE) then Exit; FShader:=Key.FShaderGroup.FKey.FShaders[vShaderStageCs]; if (FShader=nil) then Exit; if (FShader.FHandle=VK_NULL_HANDLE) then Exit; info:=Default(TVkComputePipelineCreateInfo); info.sType :=VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; info.stage.sType :=VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; info.stage.stage :=VK_SHADER_STAGE_COMPUTE_BIT; info.stage.module:=FShader.FHandle; info.stage.pName :=PChar(FShader.FEntry); info.layout :=FLayout.FHandle; FCache:=VK_NULL_HANDLE; if (FPCache<>nil) then begin FCache:=FPCache.FHandle; end; r:=vkCreateComputePipelines(Device.FHandle,FCache,1,@info,nil,@FHandle); if (r<>VK_SUCCESS) then begin Writeln(StdErr,'vkCreateComputePipelines:',r); Exit; end; Result:=True; end; /// function _FindGraphics(P:PvGraphicsPipelineKey):TvGraphicsPipeline2; var i:TvGraphicsPipeline2Set.Iterator; begin Result:=nil; i:=FGraphicsPipeline2Set.find(P); if (i.Item<>nil) then begin Result:=TvGraphicsPipeline2(ptruint(i.Item^)-ptruint(@TvGraphicsPipeline2(nil).key)); end; end; function _FetchGraphicsPipeline(P:PvGraphicsPipelineKey):TvGraphicsPipeline2; var t:TvGraphicsPipeline2; begin Result:=nil; t:=_FindGraphics(P); if (t=nil) then begin if (FGlobalCache_rt=nil) then begin FGlobalCache_rt:=TvPipelineCache.Create(nil,0); end; t:=TvGraphicsPipeline2.Create; t.FPCache:=FGlobalCache_rt; t.key:=P^; if not t.Compile then begin FreeAndNil(t); end else begin t.Acquire(nil); //map ref FGraphicsPipeline2Set.Insert(@t.key); end; end; Result:=t; end; function FetchGraphicsPipeline(cmd:TvDependenciesObject;P:PvGraphicsPipelineKey):TvGraphicsPipeline2; begin Result:=nil; if (P=nil) then Exit; rw_wlock(global_lock_rt); Result:=_FetchGraphicsPipeline(P); cmd.RefTo(Result); rw_wunlock(global_lock_rt); end; // function _FindCompute(P:PvComputePipelineKey):TvComputePipeline2; var i:TvComputePipeline2Set.Iterator; begin Result:=nil; i:=FComputePipeline2Set.find(P); if (i.Item<>nil) then begin Result:=TvComputePipeline2(ptruint(i.Item^)-ptruint(@TvComputePipeline2(nil).key)); end; end; function _FetchComputePipeline(P:PvComputePipelineKey):TvComputePipeline2; var t:TvComputePipeline2; begin Result:=nil; t:=_FindCompute(P); if (t=nil) then begin if (FGlobalCache_cs=nil) then begin FGlobalCache_cs:=TvPipelineCache.Create(nil,0); end; t:=TvComputePipeline2.Create; t.FPCache:=FGlobalCache_cs; t.key:=P^; if not t.Compile then begin FreeAndNil(t); end else begin t.Acquire(nil); //map ref FComputePipeline2Set.Insert(@t.key); end; end; Result:=t; end; function FetchComputePipeline(cmd:TvDependenciesObject;P:PvComputePipelineKey):TvComputePipeline2; begin Result:=nil; if (P=nil) then Exit; rw_wlock(global_lock_cs); Result:=_FetchComputePipeline(P); cmd.RefTo(Result); rw_wunlock(global_lock_cs); end; end.