1 module pipeline; 2 3 import buffer; 4 5 import gfx.core; 6 import gfx.graal; 7 import gfx.math; 8 9 class DeferredPipelines : AtomicRefCounted 10 { 11 struct Pl { 12 DescriptorSetLayout[] descriptorLayouts; 13 PipelineLayout layout; 14 Pipeline pipeline; 15 16 void release() 17 { 18 releaseObj(pipeline); 19 releaseObj(layout); 20 releaseArr(descriptorLayouts); 21 } 22 } 23 24 Pl[] pls; 25 26 this(Device device, RenderPass deferredRp, RenderPass bloomRp, RenderPass blendRp) 27 { 28 import std.algorithm : map; 29 import std.array : array; 30 31 auto infos = [ 32 geomInfo(device, deferredRp), 33 lightInfo(device, deferredRp), 34 bloomInfo(device, bloomRp), 35 blendInfo(device, blendRp), 36 ]; 37 38 pls = device.createPipelines(infos) 39 .map!(pl => Pl([], null, retainObj(pl))) 40 .array; 41 42 foreach(i; 0 .. infos.length) 43 { 44 pls[i].layout = infos[i].layout; 45 pls[i].descriptorLayouts = infos[i].layout.descriptorLayouts; 46 releaseObj(infos[i].shaders.vertex); 47 releaseObj(infos[i].shaders.fragment); 48 } 49 } 50 51 override void dispose() 52 { 53 foreach(ref pl; pls) { 54 pl.release(); 55 } 56 pls = []; 57 } 58 59 @property Pl geom() 60 { 61 return pls[0]; 62 } 63 64 @property Pl light() 65 { 66 return pls[1]; 67 } 68 69 @property Pl bloom() 70 { 71 return pls[2]; 72 } 73 74 @property Pl blend() 75 { 76 return pls[3]; 77 } 78 79 final PipelineInfo geomInfo(Device device, RenderPass renderPass) 80 { 81 import std.typecons : No, Yes; 82 83 const shaderSpv = [ 84 import("geom.vert.spv"), import("geom.frag.spv"), 85 ]; 86 87 const layoutBindings = [ 88 PipelineLayoutBinding( 89 0, DescriptorType.uniformBuffer, 1, ShaderStage.vertex 90 ), 91 PipelineLayoutBinding( 92 1, DescriptorType.uniformBufferDynamic, 1, ShaderStage.vertex 93 ), 94 ]; 95 96 auto descriptorLayouts = [ 97 retainObj(device.createDescriptorSetLayout(layoutBindings)) 98 ]; 99 auto layout = retainObj(device.createPipelineLayout( descriptorLayouts, [] )); 100 101 PipelineInfo info; 102 info.shaders.vertex = retainObj(device.createShaderModule( 103 cast(immutable(uint)[])shaderSpv[0], "main" 104 )); 105 info.shaders.fragment = retainObj(device.createShaderModule( 106 cast(immutable(uint)[])shaderSpv[1], "main" 107 )); 108 info.inputBindings = [ 109 VertexInputBinding(0, P3N3Vertex.sizeof, No.instanced) 110 ]; 111 info.inputAttribs = [ 112 VertexInputAttrib(0, 0, Format.rgb32_sFloat, 0), 113 VertexInputAttrib(1, 0, Format.rgb32_sFloat, P3N3Vertex.normal.offsetof), 114 ]; 115 info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart); 116 info.rasterizer = Rasterizer( 117 PolygonMode.fill, Cull.back, FrontFace.ccw, No.depthClamp, 118 none!DepthBias, 1f 119 ); 120 info.depthInfo = DepthInfo( 121 Yes.enabled, Yes.write, CompareOp.less, No.boundsTest, 0f, 1f 122 ); 123 info.blendInfo = ColorBlendInfo( 124 none!LogicOp, [ 125 ColorBlendAttachment.solid(), 126 ColorBlendAttachment.solid(), 127 ColorBlendAttachment.solid(), 128 ], 129 ); 130 info.dynamicStates = [ DynamicState.viewport, DynamicState.scissor ]; 131 info.layout = layout; 132 info.renderPass = renderPass; 133 info.subpassIndex = 0; 134 135 return info; 136 } 137 138 final PipelineInfo lightInfo(Device device, RenderPass renderPass) 139 { 140 import std.typecons : No, Yes; 141 142 const shaderSpv = [ 143 import("light.vert.spv"), import("light.frag.spv"), 144 ]; 145 146 const bufLayoutBindings = [ 147 PipelineLayoutBinding( 148 0, DescriptorType.uniformBuffer, 1, ShaderStage.fragment 149 ), 150 PipelineLayoutBinding( 151 1, DescriptorType.uniformBufferDynamic, 1, ShaderStage.vertex | ShaderStage.fragment 152 ), 153 ]; 154 const attachLayoutBindings = [ 155 PipelineLayoutBinding( 156 0, DescriptorType.inputAttachment, 3, ShaderStage.fragment 157 ), 158 ]; 159 160 auto descriptorLayouts = [ 161 retainObj(device.createDescriptorSetLayout(bufLayoutBindings)), 162 retainObj(device.createDescriptorSetLayout(attachLayoutBindings)), 163 ]; 164 auto layout = retainObj(device.createPipelineLayout( descriptorLayouts, [] )); 165 166 PipelineInfo info; 167 info.shaders.vertex = retainObj(device.createShaderModule( 168 cast(immutable(uint)[])shaderSpv[0], "main" 169 )); 170 info.shaders.fragment = retainObj(device.createShaderModule( 171 cast(immutable(uint)[])shaderSpv[1], "main" 172 )); 173 info.inputBindings = [ 174 VertexInputBinding(0, FVec3.sizeof, No.instanced) 175 ]; 176 info.inputAttribs = [ 177 VertexInputAttrib(0, 0, Format.rgb32_sFloat, 0), 178 ]; 179 info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart); 180 // culling so that we run the shader once per fragment 181 // front instead of back culling to also run the shader if the camera is within a sphere 182 info.rasterizer = Rasterizer( 183 PolygonMode.fill, Cull.front, FrontFace.ccw 184 ); 185 info.blendInfo = ColorBlendInfo( 186 none!LogicOp, [ 187 ColorBlendAttachment.blend( 188 BlendState( 189 trans(BlendFactor.one, BlendFactor.one), 190 BlendOp.add, 191 ), 192 ), 193 ColorBlendAttachment.blend( 194 BlendState( 195 trans(BlendFactor.one, BlendFactor.one), 196 BlendOp.add, 197 ), 198 ), 199 ], 200 ); 201 info.dynamicStates = [ DynamicState.viewport, DynamicState.scissor ]; 202 info.layout = layout; 203 info.renderPass = renderPass; 204 info.subpassIndex = 1; 205 206 return info; 207 } 208 209 final PipelineInfo bloomInfo(Device device, RenderPass renderPass) 210 { 211 import std.typecons : No, Yes; 212 213 const shaderSpv = [ 214 import("bloom.vert.spv"), import("bloom.frag.spv"), 215 ]; 216 217 const layoutBindings = [ 218 PipelineLayoutBinding( 219 0, DescriptorType.combinedImageSampler, 1, ShaderStage.fragment 220 ), 221 ]; 222 223 auto descriptorLayouts = [ 224 retainObj(device.createDescriptorSetLayout(layoutBindings)), 225 ]; 226 // pc holds horizontal-vertical boolean 227 const pushConstants = [ 228 PushConstantRange(ShaderStage.fragment, 0, uint.sizeof), 229 ]; 230 auto layout = retainObj(device.createPipelineLayout( descriptorLayouts, pushConstants )); 231 232 PipelineInfo info; 233 info.shaders.vertex = retainObj(device.createShaderModule( 234 cast(immutable(uint)[])shaderSpv[0], "main" 235 )); 236 info.shaders.fragment = retainObj(device.createShaderModule( 237 cast(immutable(uint)[])shaderSpv[1], "main" 238 )); 239 info.inputBindings = [ 240 VertexInputBinding(0, P2T2Vertex.sizeof, No.instanced) 241 ]; 242 info.inputAttribs = [ 243 VertexInputAttrib(0, 0, Format.rg32_sFloat, 0), 244 VertexInputAttrib(1, 0, Format.rg32_sFloat, P2T2Vertex.texCoord.offsetof), 245 ]; 246 info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart); 247 info.rasterizer = Rasterizer( 248 PolygonMode.fill, Cull.none, FrontFace.ccw 249 ); 250 info.blendInfo = ColorBlendInfo( 251 none!LogicOp, [ 252 ColorBlendAttachment.solid(), 253 ], 254 ); 255 info.dynamicStates = [ DynamicState.viewport, DynamicState.scissor ]; 256 info.layout = layout; 257 info.renderPass = renderPass; 258 info.subpassIndex = 0; 259 260 return info; 261 } 262 263 final PipelineInfo blendInfo(Device device, RenderPass renderPass) 264 { 265 import std.typecons : No, Yes; 266 267 const shaderSpv = [ 268 import("blend.vert.spv"), import("blend.frag.spv"), 269 ]; 270 271 const layoutBindings = [ 272 PipelineLayoutBinding( 273 0, DescriptorType.inputAttachment, 2, ShaderStage.fragment 274 ), 275 ]; 276 277 auto descriptorLayouts = [ 278 retainObj(device.createDescriptorSetLayout(layoutBindings)), 279 ]; 280 auto layout = retainObj(device.createPipelineLayout( descriptorLayouts, [] )); 281 282 PipelineInfo info; 283 info.shaders.vertex = retainObj(device.createShaderModule( 284 cast(immutable(uint)[])shaderSpv[0], "main" 285 )); 286 info.shaders.fragment = retainObj(device.createShaderModule( 287 cast(immutable(uint)[])shaderSpv[1], "main" 288 )); 289 info.inputBindings = [ 290 VertexInputBinding(0, P2T2Vertex.sizeof, No.instanced) 291 ]; 292 info.inputAttribs = [ 293 VertexInputAttrib(0, 0, Format.rg32_sFloat, 0), 294 ]; 295 info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart); 296 info.rasterizer = Rasterizer( 297 PolygonMode.fill, Cull.none, FrontFace.ccw 298 ); 299 info.blendInfo = ColorBlendInfo( 300 none!LogicOp, [ 301 ColorBlendAttachment.solid(), 302 ], 303 ); 304 info.dynamicStates = [ DynamicState.viewport, DynamicState.scissor ]; 305 info.layout = layout; 306 info.renderPass = renderPass; 307 info.subpassIndex = 0; 308 309 return info; 310 } 311 }