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 }