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 }