1 module sbylib.graphics.wrapper.renderpass; 2 3 public import erupted; 4 public import sbylib.wrapper.glfw : Window; 5 public import sbylib.wrapper.vulkan; 6 public import sbylib.graphics.wrapper; 7 import std; 8 import sbylib.graphics.util.own; 9 import sbylib.graphics.core.presenter; 10 11 class VRenderPass : RenderPass { 12 13 mixin template ImplOpCall() { 14 private static typeof(this)[Window] instance; 15 16 static opCall(Window window) { 17 if (window !in instance) { 18 instance[window] = new typeof(this)(window); 19 VDevice().pushReleaseCallback({ deinitialize(window); }); 20 } 21 return instance[window]; 22 } 23 24 private static void deinitialize(Window window) { 25 assert(window in instance, "this window is not registered one."); 26 instance[window].destroy(); 27 instance.remove(window); 28 } 29 } 30 31 mixin template Info(RenderPass.CreateInfo info_) { 32 protected override RenderPass.CreateInfo info() { 33 return info_; 34 } 35 } 36 37 protected abstract RenderPass.CreateInfo info(); 38 39 private { 40 Window window; 41 void delegate(CommandBuffer)[] renderList; 42 bool submitted; 43 44 @own { 45 Framebuffer[] framebuffers; 46 VCommandBuffer[] commandBuffers; 47 VFence submitFence; 48 } 49 } 50 mixin ImplReleaseOwn; 51 52 private this(Window window) { 53 super(VDevice(), info); 54 this.window = window; 55 } 56 57 protected void registerFrameBuffers(Framebuffer[] framebuffers) { 58 this.framebuffers = framebuffers; 59 this.commandBuffers = VCommandBuffer.allocate(VCommandBuffer.Type.Graphics, CommandBufferLevel.Primary, cast(uint)framebuffers.length); 60 this.submitFence = VFence.create("standard renderpass submission fence"); 61 Presenter(window).pushPresentFence(submitFence); 62 updateCommandBuffers(); 63 VDevice().pushResource(this); 64 } 65 66 void submitRender() { 67 submitFence.reset(); 68 auto currentImageIndex = Presenter(window).getImageIndex(); 69 70 VQueue(VQueue.Type.Graphics).submitWithFence(commandBuffers[currentImageIndex], submitFence); 71 submitted = true; 72 } 73 74 auto register(void delegate(CommandBuffer) render) { 75 this.renderList ~= render; 76 updateCommandBuffers(); 77 return { unregister(render); }; 78 } 79 80 void unregister(void delegate(CommandBuffer) render) { 81 this.renderList = this.renderList.remove!(r => r == render); 82 updateCommandBuffers(); 83 } 84 85 private void updateCommandBuffers() { 86 if (submitted && submitFence.signaled is false) { 87 Fence.wait([submitFence], true, ulong.max); 88 submitted = false; 89 } 90 enforce(!submitted || submitFence.signaled); 91 92 foreach (cb, framebuffer; zip(commandBuffers, framebuffers)) { 93 with (cb()) { 94 CommandBuffer.RenderPassBeginInfo renderPassBeginInfo = { 95 renderPass: this, 96 framebuffer: framebuffer, 97 renderArea: { 98 extent: VkExtent2D(window.width, window.height) 99 }, 100 clearValues: [{ 101 color: { 102 float32: [0.0f, 0.0f, 0.0f, 1.0f] 103 }, 104 }, { 105 depthStencil: { 106 depth: 1.0f 107 } 108 }] 109 }; 110 cmdBeginRenderPass(renderPassBeginInfo, SubpassContents.Inline); 111 112 foreach (r; this.renderList) { 113 r(commandBuffer); 114 } 115 116 cmdEndRenderPass(); 117 } 118 } 119 } 120 }