1 /// command buffer module
2 module gfx.graal.cmd;
3 
4 import gfx.core.rc;
5 import gfx.core.typecons;
6 import gfx.graal.buffer;
7 import gfx.graal.image;
8 import gfx.graal.renderpass;
9 import gfx.graal.pipeline;
10 import gfx.graal.types;
11 
12 import std.typecons : Flag, No;
13 
14 interface CommandPool : IAtomicRefCounted {
15     void reset();
16 
17     PrimaryCommandBuffer[] allocatePrimary(in size_t count);
18     SecondaryCommandBuffer[] allocateSecondary(in size_t count);
19 
20     void free(CommandBuffer[] buffers)
21     in {
22         import std.algorithm : all;
23 
24         assert(buffers.all!(b => b.pool is this));
25     }
26 }
27 
28 enum Access {
29     none = 0x00000000,
30     indirectCommandRead = 0x00000001,
31     indexRead = 0x00000002,
32     vertexAttributeRead = 0x00000004,
33     uniformRead = 0x00000008,
34     inputAttachmentRead = 0x00000010,
35     shaderRead = 0x00000020,
36     shaderWrite = 0x00000040,
37     colorAttachmentRead = 0x00000080,
38     colorAttachmentWrite = 0x00000100,
39     depthStencilAttachmentRead = 0x00000200,
40     depthStencilAttachmentWrite = 0x00000400,
41     transferRead = 0x00000800,
42     transferWrite = 0x00001000,
43     hostRead = 0x00002000,
44     hostWrite = 0x00004000,
45     memoryRead = 0x00008000,
46     memoryWrite = 0x00010000,
47 }
48 
49 enum queueFamilyIgnored = 0xffffffff;
50 
51 struct ImageMemoryBarrier {
52     Trans!Access accessMaskTrans;
53     Trans!ImageLayout layoutTrans;
54     Trans!uint queueFamIndexTrans;
55     ImageBase image;
56     ImageSubresourceRange range;
57 }
58 
59 struct BufferMemoryBarrier {
60     Trans!Access accessMaskTrans;
61     Trans!uint queueFamIndexTrans;
62     Buffer buffer;
63     size_t offset;
64     size_t size;
65 }
66 
67 enum PipelineStage {
68     topOfPipe = 0x00000001,
69     drawIndirect = 0x00000002,
70     vertexInput = 0x00000004,
71     vertexShader = 0x00000008,
72     tessellationControlShader = 0x00000010,
73     tessellationEvalShader = 0x00000020,
74     geometryShader = 0x00000040,
75     fragmentShader = 0x00000080,
76     earlyFragmentTests = 0x00000100,
77     lateFragmentTests = 0x00000200,
78     colorAttachmentOutput = 0x00000400,
79     computeShader = 0x00000800,
80     transfer = 0x00001000,
81     bottomOfPipe = 0x00002000,
82     host = 0x00004000,
83     allGraphics = 0x00008000,
84     allCommands = 0x00010000,
85 }
86 
87 enum PipelineBindPoint {
88     graphics,
89     compute
90 }
91 
92 /// Values to be given to a clear image color command
93 /// The type should be f32, unless the image format has numeric format of sInt or uInt.
94 struct ClearColorValues {
95     enum Type {
96         f32,
97         i32,
98         u32
99     }
100 
101     union Values {
102         float[4] f32;
103         int[4] i32;
104         uint[4] u32;
105     }
106 
107     Type type;
108     Values values;
109 
110     this(float r, float g, float b, float a) {
111         type = Type.f32;
112         values.f32 = [r, g, b, a];
113     }
114 
115     this(int r, int g, int b, int a) {
116         type = Type.i32;
117         values.i32 = [r, g, b, a];
118     }
119 
120     this(uint r, uint g, uint b, uint a) {
121         type = Type.u32;
122         values.u32 = [r, g, b, a];
123     }
124 }
125 
126 struct ClearDepthStencilValues {
127     float depth;
128     uint stencil;
129 }
130 
131 struct ClearValues {
132     enum Type {
133         undefined,
134         color,
135         depthStencil
136     }
137 
138     union Values {
139         ClearColorValues color;
140         ClearDepthStencilValues depthStencil;
141     }
142 
143     Type type;
144     Values values;
145 
146     this(ClearColorValues color) {
147         type = Type.color;
148         values.color = color;
149     }
150 
151     this(ClearDepthStencilValues depthStencil) {
152         type = Type.depthStencil;
153         values.depthStencil = depthStencil;
154     }
155 
156     static ClearValues color(in float r, in float g, in float b, in float a) {
157         return ClearValues(ClearColorValues(r, g, b, a));
158     }
159 
160     static ClearValues color(in int r, in int g, in int b, in int a) {
161         return ClearValues(ClearColorValues(r, g, b, a));
162     }
163 
164     static ClearValues color(in uint r, in uint g, in uint b, in uint a) {
165         return ClearValues(ClearColorValues(r, g, b, a));
166     }
167 
168     static ClearValues depthStencil(in float depth, in uint stencil) {
169         return ClearValues(ClearDepthStencilValues(depth, stencil));
170     }
171 }
172 
173 struct VertexBinding {
174     Buffer buffer;
175     size_t offset;
176 }
177 
178 struct CopyRegion {
179     Trans!size_t offset;
180     size_t size;
181 }
182 
183 struct ImageCopyRegion {
184     Trans!ImageSubresourceRange isr;
185     Trans!(float[3]) offset;
186 }
187 
188 struct BufferImageCopy {
189     ulong bufferOffset;
190     uint bufferWidth;
191     uint bufferHeight;
192     ImageSubresourceLayer imageLayers;
193     int[3] offset;
194     uint[3] extent;
195 }
196 
197 enum StencilFace {
198     front = 1,
199     back = 2,
200     frontAndBack = 3,
201 }
202 
203 enum wholeSize = uint.max;
204 
205 enum CommandBufferUsage {
206     none = 0,
207     oneTimeSubmit = 0x0001,
208     simultaneousUse = 0x0004,
209 }
210 
211 enum CommandBufferLevel {
212     primary,
213     secondary,
214 }
215 
216 /// Base interface for a command buffer
217 ///
218 /// CommandBuffer are allocated and owned by a command pool.
219 /// A command buffer can be in three defined states:
220 /// 1. invalid - that is the state after it as been created or reset
221 /// 2. recoding - that is the state between begin() and end() calls()
222 /// 3. pending - that is the state when recording is done and commands
223 ///     are ready for execution.
224 ///
225 /// A command buffer in pending state can only go back to the initial
226 /// state by a call to reset(). This call must not occur before all
227 /// submitted executions are finished in the device queues.
228 interface CommandBuffer {
229     @property CommandPool pool();
230 
231     @property CommandBufferLevel level() const;
232 
233     void reset();
234 
235     /// Begin recording and switches the buffer state from "invalid" to "recording"
236     /// SecondaryCommandBuffer can alternatively call beginWithinRenderPass
237     void begin(in CommandBufferUsage usage);
238     void end();
239 
240     void pipelineBarrier(Trans!PipelineStage stageTrans,
241             BufferMemoryBarrier[] bufMbs, ImageMemoryBarrier[] imgMbs);
242 
243     void clearColorImage(ImageBase image, ImageLayout layout,
244             in ClearColorValues clearValues, ImageSubresourceRange[] ranges);
245 
246     void clearDepthStencilImage(ImageBase image, ImageLayout layout,
247             in ClearDepthStencilValues clearValues, ImageSubresourceRange[] ranges);
248 
249     /// Fills buffer from offset to offset+size with value
250     /// Params:
251     ///     dst     = the buffer to fill.
252     ///     offset  = Byte offset from where to fill the buffer.
253     ///               Must be a multiple of 4.
254     ///     size    = Number of bytes to fill. Must be a multiple of 4 or
255     ///               wholeSize to fill until the end of the buffer.
256     ///     value   = Value to copy into the buffer, in host endianess.
257     /// Can only be used outside of a render pass.
258     void fillBuffer(Buffer dst, in size_t offset, in size_t size, uint value)
259     in {
260         assert(offset % 4 == 0);
261         assert(size == wholeSize || size % 4 == 0);
262     }
263     /// Update buffer with the data passed as argument
264     /// Params:
265     ///     dst     = the buffer to update.
266     ///     offset  = Byte offset from where to update the buffer.
267     ///               Must be a multiple of 4.
268     ///     data    = The data to copy into the buffer.
269     /// The data is duplicated into the command buffer, so it is legal to pass a slice
270     /// to local on-stack data, or to let GC collect the data right after the call.
271     /// Can only be used outside of a render pass.
272     void updateBuffer(Buffer dst, in size_t offset, in uint[] data);
273     void copyBuffer(Trans!Buffer buffers, in CopyRegion[] regions);
274     void copyBufferToImage(Buffer srcBuffer, ImageBase dstImage,
275             in ImageLayout dstLayout, in BufferImageCopy[] regions);
276 
277     void setViewport(in uint firstViewport, in Viewport[] viewports);
278     void setScissor(in uint firstScissor, in Rect[] scissors);
279     void setDepthBounds(in float minDepth, in float maxDepth);
280     void setLineWidth(in float lineWidth);
281     void setDepthBias(in float constFactor, in float clamp, in float slopeFactor);
282     void setStencilCompareMask(in StencilFace faceMask, in uint compareMask);
283     void setStencilWriteMask(in StencilFace faceMask, in uint writeMask);
284     void setStencilReference(in StencilFace faceMask, in uint reference);
285     void setBlendConstants(in float[4] blendConstants);
286 
287     void bindPipeline(Pipeline pipeline);
288     void bindVertexBuffers(uint firstBinding, VertexBinding[] bindings);
289     void bindIndexBuffer(Buffer indexBuf, size_t offset, IndexType type);
290 
291     void bindDescriptorSets(PipelineBindPoint bindPoint, PipelineLayout layout,
292             uint firstSet, DescriptorSet[] sets, in size_t[] dynamicOffsets);
293 
294     void pushConstants(PipelineLayout layout, ShaderStage stages, size_t offset,
295             size_t size, const(void)* data);
296 
297     void draw(uint vertexCount, uint instanceCount, uint firstVertex, uint firstInstance);
298     void drawIndexed(uint indexCount, uint instanceCount, uint firstVertex,
299             int vertexOffset, uint firstInstance);
300 }
301 
302 /// Interface to a primary command buffer
303 ///
304 /// A primary command buffer can be submitted directly to a queue
305 /// and also execute commands that are recorded in a secondary command buffer.
306 ///
307 /// Primary command buffers are doing most of their work when tied to a render pass.
308 /// As they are not thread safe, it means that recording commands to the same framebuffer
309 /// cannot be parallelized with PrimaryCommandBuffer.
310 /// If this is needed, SecondaryCommandBuffer (from other CommandPool) can be filled in parallel,
311 /// and later executed on a PrimaryCommandBuffer
312 interface PrimaryCommandBuffer : CommandBuffer {
313 
314     /// Place the command buffer into a render pass context
315     void beginRenderPass(RenderPass rp, Framebuffer fb, in Rect area, in ClearValues[] clearValues);
316     void nextSubpass();
317     void endRenderPass();
318 
319     /// Execute secondary buffers into this primary buffer
320     void execute(SecondaryCommandBuffer[] buffers);
321 }
322 
323 /// Interface to a secondary command buffer
324 ///
325 /// Main interest of secondary command buffer is that they are not tied to
326 /// a render pass and as such can be filled in parallel on different threads.
327 interface SecondaryCommandBuffer : CommandBuffer {
328 
329     /// Switches the buffer to the "recording" state, acknowledging that the buffer
330     /// will be executed within a render pass compatible with rp
331     void beginWithinRenderPass(in CommandBufferUsage usage, RenderPass rp,
332             Framebuffer fb, uint subpass = 0);
333 
334 }