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 }