1 module gfx.graal.pipeline; 2 3 import gfx.core.rc; 4 import gfx.core.typecons; 5 import gfx.graal.buffer; 6 import gfx.graal.format; 7 import gfx.graal.image; 8 import gfx.graal.renderpass; 9 import gfx.graal.types; 10 11 import std.typecons : Flag; 12 13 interface ShaderModule : IAtomicRefCounted 14 { 15 import gfx.graal.device : Device; 16 17 /// Get the parent device 18 @property Device device(); 19 20 @property string entryPoint(); 21 } 22 23 interface PipelineLayout : IAtomicRefCounted 24 { 25 import gfx.graal.device : Device; 26 27 /// Get the parent device 28 @property Device device(); 29 30 /// Get the descriptor set layouts used to create this pipeline layout 31 @property DescriptorSetLayout[] descriptorLayouts(); 32 33 /// Get the push constant ranges in this layout 34 @property const(PushConstantRange)[] pushConstantRanges(); 35 } 36 37 interface Pipeline : IAtomicRefCounted 38 { 39 import gfx.graal.device : Device; 40 41 /// Get the parent device 42 @property Device device(); 43 } 44 45 interface DescriptorSetLayout : IAtomicRefCounted 46 { 47 import gfx.graal.device : Device; 48 49 /// Get the parent device 50 @property Device device(); 51 } 52 53 interface DescriptorPool : IAtomicRefCounted 54 { 55 import gfx.graal.device : Device; 56 57 /// Get the parent device 58 @property Device device(); 59 60 /// Allocate a descriptor set per descriptor layout passed as argument 61 DescriptorSet[] allocate(DescriptorSetLayout[] layouts); 62 63 /// Reset this pool. 64 /// All descriptors allocated with this pool are invalid after this call 65 void reset(); 66 } 67 68 interface DescriptorSet 69 { 70 @property DescriptorPool pool(); 71 } 72 73 struct PipelineInfo { 74 GraphicsShaderSet shaders; 75 VertexInputBinding[] inputBindings; 76 VertexInputAttrib[] inputAttribs; 77 InputAssembly assembly; 78 Rasterizer rasterizer; 79 /// Viewport configuration of the pipeline. 80 /// For dynamic viewport, leave this array empty 81 ViewportConfig[] viewports; 82 83 // TODO: tesselation, multisample 84 85 DepthInfo depthInfo; 86 StencilInfo stencilInfo; 87 ColorBlendInfo blendInfo; 88 89 DynamicState[] dynamicStates; 90 91 PipelineLayout layout; 92 93 RenderPass renderPass; 94 uint subpassIndex; 95 } 96 97 enum ShaderStage { 98 vertex = 0x01, 99 tessellationControl = 0x02, 100 tessellationEvaluation = 0x04, 101 geometry = 0x08, 102 fragment = 0x10, 103 compute = 0x20, 104 105 allGraphics = 0x1f, 106 all = allGraphics | compute, 107 } 108 109 struct GraphicsShaderSet { 110 ShaderModule vertex; 111 ShaderModule tessControl; 112 ShaderModule tessEval; 113 ShaderModule geometry; 114 ShaderModule fragment; 115 } 116 117 118 /// Describes the binding of a buffer to the pipeline 119 struct VertexInputBinding { 120 uint binding; 121 size_t stride; 122 Flag!"instanced" instanced; 123 } 124 125 /// Describes a vertex attribute 126 struct VertexInputAttrib { 127 uint location; 128 uint binding; 129 Format format; 130 size_t offset; 131 } 132 133 134 enum Primitive { 135 pointList, lineList, lineStrip, 136 triangleList, triangleStrip, triangleFan, 137 lineListAdjacency, lineStripAdjacency, 138 triangleListAdjacency, triangleStripAdjacency, 139 patchList, 140 } 141 142 struct InputAssembly { 143 Primitive primitive; 144 Flag!"primitiveRestart" primitiveRestart; 145 } 146 147 enum FrontFace { 148 ccw, cw, 149 } 150 151 enum Cull { 152 none = 0x00, 153 front = 0x01, 154 back = 0x02, 155 frontAndBack = front | back, 156 } 157 158 enum PolygonMode { 159 fill, line, point, 160 } 161 162 /// Defines how a polygon can be offset (mainly to avoid shadow artifacts). 163 /// Given m as maximum depth slope of the triangle and r as implementation defined 164 /// minimal resolvable difference, the offset of the triangle is defined as follow: 165 /// o = m * slopeFactor + r * constantFactor 166 /// If clamp == 0f, o is used directly as effective offset. 167 /// If clamp > 0f, the effective offset is min(o, clamp) 168 /// If clamp < 0f, the effective offset is max(o, clamp) 169 struct DepthBias 170 { 171 /// Factor multiplied by the minimal resolvable difference of the depth buffer 172 float constantFactor; 173 /// Clamps the effective offset to a particular value 174 float clamp; 175 /// Factor multiplied by the maximum depth slope of the polygon. 176 float slopeFactor; 177 } 178 179 struct Rasterizer { 180 PolygonMode mode; 181 Cull cull; 182 FrontFace front; 183 Flag!"depthClamp" depthClamp; 184 Option!DepthBias depthBias; 185 float lineWidth=1f; 186 } 187 188 struct ViewportConfig { 189 Viewport viewport; 190 Rect scissors; 191 } 192 193 enum CompareOp 194 { 195 never, less, equal, lessOrEqual, greater, notEqual, greaterOrEqual, always, 196 } 197 198 enum StencilOp 199 { 200 keep, 201 zero, 202 replace, 203 incrementAndClamp, 204 decrementAndClamp, 205 invert, 206 incrementAndWrap, 207 decrementAndWrap, 208 } 209 210 struct DepthInfo 211 { 212 Flag!"enabled" enabled; 213 Flag!"write" write; 214 CompareOp compareOp; 215 Flag!"boundsTest" boundsTest; 216 float minBounds; 217 float maxBounds; 218 219 @property static DepthInfo none() { 220 return DepthInfo.init; 221 } 222 } 223 224 struct StencilOpState 225 { 226 StencilOp failOp; 227 StencilOp passOp; 228 StencilOp depthFailOp; 229 CompareOp compareOp; 230 uint compareMask; 231 uint writeMask; 232 uint refMask; 233 } 234 235 struct StencilInfo 236 { 237 Flag!"enabled" enabled; 238 StencilOpState front; 239 StencilOpState back; 240 241 @property static StencilInfo none() { 242 return StencilInfo.init; 243 } 244 } 245 246 247 enum BlendFactor 248 { 249 zero = 0, 250 one = 1, 251 srcColor = 2, 252 oneMinusSrcColor = 3, 253 dstColor = 4, 254 oneMinusDstColor = 5, 255 srcAlpha = 6, 256 oneMinusSrcAlpha = 7, 257 dstAlpha = 8, 258 oneMinusDstAlpha = 9, 259 constantColor = 10, 260 oneMinusConstantColor = 11, 261 constantAlpha = 12, 262 oneMinusConstantAlpha = 13, 263 srcAlphaSaturate = 14, 264 src1Color = 15, 265 oneMinusSrc1Color = 16, 266 src1Alpha = 17, 267 oneMinusSrc1Alpha = 18, 268 } 269 270 enum BlendOp { 271 add, 272 subtract, 273 reverseSubtract, 274 min, 275 max, 276 } 277 278 struct BlendState { 279 Trans!BlendFactor factor; 280 BlendOp op; 281 } 282 283 enum ColorMask { 284 r = 0x01, 285 g = 0x02, 286 b = 0x04, 287 a = 0x08, 288 289 none = 0x00, 290 all = r | g | b | a, 291 rg = r | g, 292 rb = r | b, 293 ra = r | a, 294 gb = g | b, 295 ga = g | a, 296 ba = b | a, 297 rgb = r | g | b, 298 rga = r | g | a, 299 rba = r | b | a, 300 gba = g | b | a, 301 rgba = r | g | b | a, 302 } 303 304 struct ColorBlendAttachment { 305 Flag!"enabled" enabled; 306 BlendState colorBlend; 307 BlendState alphaBlend; 308 ColorMask colorMask; 309 310 static ColorBlendAttachment solid(in ColorMask mask=ColorMask.all) { 311 import std.typecons : No; 312 return ColorBlendAttachment( 313 No.enabled, BlendState.init, BlendState.init, mask 314 ); 315 } 316 317 static ColorBlendAttachment blend(in BlendState blendState, 318 in ColorMask mask=ColorMask.all) { 319 import std.typecons : Yes; 320 return ColorBlendAttachment( 321 Yes.enabled, blendState, blendState, mask 322 ); 323 } 324 325 static ColorBlendAttachment blend(in BlendState color, in BlendState alpha, 326 in ColorMask mask=ColorMask.all) { 327 import std.typecons : Yes; 328 return ColorBlendAttachment( 329 Yes.enabled, color, alpha, mask 330 ); 331 } 332 } 333 334 enum LogicOp { 335 clear, 336 and, 337 andReverse, 338 copy, 339 andInverted, 340 noop, 341 xor, 342 or, 343 nor, 344 equivalent, 345 invert, 346 orReverse, 347 copyInverted, 348 orInverted, 349 nand, 350 set, 351 } 352 353 struct ColorBlendInfo 354 { 355 Option!LogicOp logicOp; 356 ColorBlendAttachment[] attachments; 357 float[4] blendConstants = [ 0f, 0f, 0f, 0f ]; 358 } 359 360 enum DynamicState { 361 viewport, 362 scissor, 363 lineWidth, 364 depthBias, 365 blendConstants, 366 depthBounds, 367 stencilCmpMask, 368 stencilWriteMask, 369 stencilRef, 370 } 371 372 enum DescriptorType { 373 sampler, 374 combinedImageSampler, 375 sampledImage, 376 storageImage, 377 uniformTexelBuffer, 378 storageTexelBuffer, 379 uniformBuffer, 380 storageBuffer, 381 uniformBufferDynamic, 382 storageBufferDynamic, 383 inputAttachment, 384 } 385 386 struct PipelineLayoutBinding { 387 uint binding; 388 DescriptorType descriptorType; 389 uint descriptorCount; 390 ShaderStage stages; 391 } 392 393 struct PushConstantRange { 394 ShaderStage stages; 395 uint offset; 396 uint size; 397 } 398 399 struct DescriptorPoolSize { 400 DescriptorType type; 401 uint count; 402 } 403 404 struct WriteDescriptorSet { 405 DescriptorSet dstSet; 406 uint dstBinding; 407 uint dstArrayElem; 408 DescriptorWrite write; 409 } 410 411 struct CopyDescritporSet { 412 Trans!DescriptorSet set; 413 Trans!uint binding; 414 Trans!uint arrayElem; 415 } 416 417 /// Descriptor for a buffer 418 /// to be used to update the following descriptor types: 419 /// - DescriptorType.uniformBuffer 420 /// - DescriptorType.uniformBufferDynamic 421 /// - DescriptorType.storageBuffer 422 /// - DescriptorType.storageBufferDynamic 423 struct BufferDescriptor 424 { 425 /// descriptor resource 426 Buffer buffer; 427 /// bytes offset from the beginning of the resource 428 size_t offset; 429 /// amount of bytes to use from the resource 430 size_t size; 431 } 432 433 /// Descriptor for a texel buffer 434 /// to be used to update the following descriptor types: 435 /// - DescriptorType.uniformTexelBuffer 436 /// - DescriptorType.storageTexelBuffer 437 struct TexelBufferDescriptor 438 { 439 /// descriptor resource 440 TexelBufferView bufferView; 441 } 442 443 /// Descriptor for images 444 /// to be used to update the following descriptor types: 445 /// - DescriptorType.sampledImage 446 /// - DescriptorType.storageImage 447 /// - DescriptorType.inputAttachment 448 struct ImageDescriptor { 449 /// view to descriptor resource 450 ImageView view; 451 /// layout of the image resource 452 ImageLayout layout; 453 } 454 455 /// Descriptor that combines sampler and image view 456 /// to be used to update the following descriptor types: 457 /// - DescriptorType.combinedImageSampler 458 struct ImageSamplerDescriptor 459 { 460 /// view to image resource 461 ImageView view; 462 /// layout of the image resource 463 ImageLayout layout; 464 /// sampler resource combined with this image 465 Sampler sampler; 466 } 467 468 /// Descriptor for a sampler 469 /// to be used to update the following descriptor types: 470 /// - DescriptorType.sampler 471 struct SamplerDescriptor 472 { 473 /// descriptor resource 474 Sampler sampler; 475 } 476 477 /// Gathering of descriptor or descriptors array to be written to a device 478 struct DescriptorWrite 479 { 480 private this(DescriptorType type, size_t count, Write write) { 481 _type = type; 482 _count = count; 483 _write = write; 484 } 485 private this(DescriptorType type, size_t count, Writes writes) { 486 _type = type; 487 _count = count; 488 _writes = writes; 489 } 490 491 /// the type of the descriptor to be written 492 @property DescriptorType type() const { 493 return _type; 494 } 495 496 /// how many descriptors are to be written 497 @property size_t count() const { 498 return _count; 499 } 500 501 /// make a Descriptor write for a single BufferDescriptor 502 static DescriptorWrite make(in DescriptorType type, BufferDescriptor buffer) 503 in(type == DescriptorType.uniformBuffer 504 || type == DescriptorType.storageBuffer 505 || type == DescriptorType.uniformBufferDynamic 506 || type == DescriptorType.storageBufferDynamic) 507 { 508 Write write; 509 write.buffer = buffer; 510 return DescriptorWrite(type, 1, write); 511 } 512 513 /// make a Descriptor write for a BufferDescriptor array 514 static DescriptorWrite make(in DescriptorType type, BufferDescriptor[] buffers) 515 in(type == DescriptorType.uniformBuffer 516 || type == DescriptorType.storageBuffer 517 || type == DescriptorType.uniformBufferDynamic 518 || type == DescriptorType.storageBufferDynamic) 519 in(buffers.length > 1) 520 { 521 Writes writes; 522 writes.buffers = buffers; 523 return DescriptorWrite(type, buffers.length, writes); 524 } 525 526 /// make a Descriptor write for a single TexelBufferDescriptor 527 static DescriptorWrite make(in DescriptorType type, TexelBufferDescriptor texelBuffer) 528 in(type == DescriptorType.uniformTexelBuffer 529 || type == DescriptorType.storageTexelBuffer) 530 { 531 Write write; 532 write.texelBuffer = texelBuffer; 533 return DescriptorWrite(type, 1, write); 534 } 535 536 /// make a Descriptor write for a TexelBufferDescriptor array 537 static DescriptorWrite make(in DescriptorType type, TexelBufferDescriptor[] texelBuffers) 538 in(type == DescriptorType.uniformTexelBuffer 539 || type == DescriptorType.storageTexelBuffer) 540 in(texelBuffers.length > 1) 541 { 542 Writes writes; 543 writes.texelBuffers = texelBuffers; 544 return DescriptorWrite(type, texelBuffers.length, writes); 545 } 546 547 /// make a Descriptor write for a single ImageDescriptor 548 static DescriptorWrite make(in DescriptorType type, ImageDescriptor image) 549 in(type == DescriptorType.sampledImage 550 || type == DescriptorType.storageImage 551 || type == DescriptorType.inputAttachment) 552 { 553 Write write; 554 write.image = image; 555 return DescriptorWrite(type, 1, write); 556 } 557 558 /// make a Descriptor write for a ImageDescriptor array 559 static DescriptorWrite make(in DescriptorType type, ImageDescriptor[] images) 560 in(type == DescriptorType.sampledImage 561 || type == DescriptorType.storageImage 562 || type == DescriptorType.inputAttachment) 563 in(images.length > 1) 564 { 565 Writes writes; 566 writes.images = images; 567 return DescriptorWrite(type, images.length, writes); 568 } 569 570 /// make a Descriptor write for a single ImageSamplerDescriptor 571 static DescriptorWrite make(in DescriptorType type, ImageSamplerDescriptor imageSampler) 572 in(type == DescriptorType.combinedImageSampler) 573 { 574 Write write; 575 write.imageSampler = imageSampler; 576 return DescriptorWrite(type, 1, write); 577 } 578 579 /// make a Descriptor write for a ImageSamplerDescriptor array 580 static DescriptorWrite make(in DescriptorType type, ImageSamplerDescriptor[] imageSamplers) 581 in(type == DescriptorType.combinedImageSampler) 582 in(imageSamplers.length > 1) 583 { 584 Writes writes; 585 writes.imageSamplers = imageSamplers; 586 return DescriptorWrite(type, imageSamplers.length, writes); 587 } 588 589 /// make a Descriptor write for a single SamplerDescriptor 590 static DescriptorWrite make(in DescriptorType type, SamplerDescriptor sampler) 591 in(type == DescriptorType.sampler) 592 { 593 Write write; 594 write.sampler = sampler; 595 return DescriptorWrite(type, 1, write); 596 } 597 598 /// make a Descriptor write for a SamplerDescriptor array 599 static DescriptorWrite make(in DescriptorType type, SamplerDescriptor[] samplers) 600 in(type == DescriptorType.sampler) 601 in(samplers.length > 1) 602 { 603 Writes writes; 604 writes.samplers = samplers; 605 return DescriptorWrite(type, samplers.length, writes); 606 } 607 608 /// access BufferDescriptor array 609 @property BufferDescriptor[] buffers() return 610 in(type == DescriptorType.uniformBuffer 611 || type == DescriptorType.storageBuffer 612 || type == DescriptorType.uniformBufferDynamic 613 || type == DescriptorType.storageBufferDynamic) 614 { 615 if (_count == 1) { 616 return (&_write.buffer)[0 .. 1]; 617 } 618 else { 619 return _writes.buffers; 620 } 621 } 622 623 /// access TexelBufferDescriptor array 624 @property TexelBufferDescriptor[] texelBuffers() return 625 in(type == DescriptorType.uniformTexelBuffer 626 || type == DescriptorType.storageTexelBuffer) 627 { 628 if (_count == 1) { 629 return (&_write.texelBuffer)[0 .. 1]; 630 } 631 else { 632 return _writes.texelBuffers; 633 } 634 } 635 636 /// access ImageDescriptor array 637 @property ImageDescriptor[] images() return 638 in(type == DescriptorType.sampledImage 639 || type == DescriptorType.storageImage 640 || type == DescriptorType.inputAttachment) 641 { 642 if (_count == 1) { 643 return (&_write.image)[0 .. 1]; 644 } 645 else { 646 return _writes.images; 647 } 648 } 649 650 /// access ImageSamplerDescriptor array 651 @property ImageSamplerDescriptor[] imageSamplers() return 652 in(type == DescriptorType.combinedImageSampler) 653 { 654 if (_count == 1) { 655 return (&_write.imageSampler)[0 .. 1]; 656 } 657 else { 658 return _writes.imageSamplers; 659 } 660 } 661 662 /// access SamplerDescriptor array 663 @property SamplerDescriptor[] samplers() return 664 in(type == DescriptorType.sampler) 665 { 666 if (_count == 1) { 667 return (&_write.sampler)[0 .. 1]; 668 } 669 else { 670 return _writes.samplers; 671 } 672 } 673 674 // union used if count > 1 (heap allocation) 675 private union Writes 676 { 677 BufferDescriptor[] buffers; 678 TexelBufferDescriptor[] texelBuffers; 679 ImageDescriptor[] images; 680 ImageSamplerDescriptor[] imageSamplers; 681 SamplerDescriptor[] samplers; 682 } 683 684 // avoid heap allocation when a single descriptor is specified 685 // (probably over 90% of use cases) 686 private union Write 687 { 688 BufferDescriptor buffer; 689 TexelBufferDescriptor texelBuffer; 690 ImageDescriptor image; 691 ImageSamplerDescriptor imageSampler; 692 SamplerDescriptor sampler; 693 } 694 695 private DescriptorType _type; 696 private size_t _count; 697 private Writes _writes; 698 private Write _write; 699 }