1 module triangle;
2 
3 import example;
4 
5 import gfx.core.rc;
6 import gfx.core.typecons;
7 import gfx.graal.buffer;
8 import gfx.graal.cmd;
9 import gfx.graal.device;
10 import gfx.graal.format;
11 import gfx.graal.image;
12 import gfx.graal.memory;
13 import gfx.graal.pipeline;
14 import gfx.graal.presentation;
15 import gfx.graal.queue;
16 import gfx.graal.renderpass;
17 import gfx.graal.types;
18 import gfx.window;
19 import gfx.window.keys;
20 
21 import std.exception;
22 import std.stdio;
23 import std.typecons;
24 
25 class TriangleExample : Example
26 {
27     Rc!RenderPass renderPass;
28     Rc!Pipeline pipeline;
29     FrameData[] perImages;
30     Rc!Buffer vertBuf;
31 
32     struct Vertex {
33         float[4] position;
34         float[4] color;
35     }
36 
37     this(string[] args) {
38         super("Triangle", args);
39     }
40 
41     override void dispose()
42     {
43         if (device) {
44             device.waitIdle();
45         }
46         vertBuf.unload();
47         pipeline.unload();
48         renderPass.unload();
49         super.dispose();
50     }
51 
52     override void prepare()
53     {
54         super.prepare();
55         prepareBuffer();
56         preparePipeline();
57     }
58 
59     void prepareBuffer()
60     {
61         import gfx.math.proj : XYClip, xyClip;
62 
63         const high = ndc.xyClip == XYClip.rightHand ? -0.7f : 0.7f;
64         const low = ndc.xyClip == XYClip.rightHand ?  0.7f : -0.7f;
65 
66         const vertexData = [
67             Vertex([-0.7f,  low, 0f, 1f], [ 0f, 1f, 0f, 1f ]),
68             Vertex([ 0.7f,  low, 0f, 1f], [ 1f, 0f, 0f, 1f ]),
69             Vertex([   0f, high, 0f, 1f], [ 0f, 0f, 1f, 1f ]),
70         ];
71 
72         vertBuf = createStaticBuffer(vertexData, BufferUsage.vertex);
73     }
74 
75     override void prepareRenderPass()
76     {
77         const attachments = [
78             AttachmentDescription(swapchain.format, 1,
79                 AttachmentOps(LoadOp.clear, StoreOp.store),
80                 AttachmentOps(LoadOp.dontCare, StoreOp.dontCare),
81                 trans(ImageLayout.undefined, ImageLayout.presentSrc),
82                 No.mayAlias
83             )
84         ];
85         const subpasses = [
86             SubpassDescription(
87                 [], [ AttachmentRef(0, ImageLayout.colorAttachmentOptimal) ],
88                 none!AttachmentRef, []
89             )
90         ];
91 
92         renderPass = device.createRenderPass(attachments, subpasses, []);
93     }
94 
95     class TriangleFrameData : FrameData
96     {
97         PrimaryCommandBuffer cmdBuf;
98         Rc!Framebuffer framebuffer;
99 
100         this(ImageBase swcColor, CommandBuffer tempBuf)
101         {
102             super(swcColor);
103             cmdBuf = cmdPool.allocatePrimary(1)[0];
104 
105             framebuffer = device.createFramebuffer(this.outer.renderPass.obj, [
106                 swcColor.createView(
107                     ImageType.d2,
108                     ImageSubresourceRange(ImageAspect.color),
109                     Swizzle.identity
110                 )
111             ], size[0], size[1], 1);
112         }
113 
114         override void dispose()
115         {
116             cmdPool.free([ cast(CommandBuffer)cmdBuf ]);
117             framebuffer.unload();
118             super.dispose();
119         }
120     }
121 
122     override FrameData makeFrameData(ImageBase swcColor, CommandBuffer tempBuf)
123     {
124         return new TriangleFrameData(swcColor, tempBuf);
125     }
126 
127     void preparePipeline()
128     {
129         const spv = [
130             import("shader.vert.spv"), import("shader.frag.spv")
131         ];
132         auto vtxShader = device.createShaderModule(
133             cast(immutable(uint)[])spv[0], "main"
134         ).rc;
135         auto fragShader = device.createShaderModule(
136             cast(immutable(uint)[])spv[1], "main"
137         ).rc;
138         auto pl = device.createPipelineLayout([], []).rc;
139 
140         PipelineInfo info;
141         info.shaders.vertex = vtxShader;
142         info.shaders.fragment = fragShader;
143         info.inputBindings = [
144             VertexInputBinding(0, Vertex.sizeof, No.instanced)
145         ];
146         info.inputAttribs = [
147             VertexInputAttrib(0, 0, Format.rgba32_sFloat, 0),
148             VertexInputAttrib(1, 0, Format.rgba32_sFloat, Vertex.color.offsetof),
149         ];
150         info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart);
151         info.rasterizer = Rasterizer(
152             PolygonMode.fill, Cull.back, FrontFace.ccw, No.depthClamp,
153             none!DepthBias, 1f
154         );
155         info.viewports = [
156             ViewportConfig(
157                 Viewport(0, 0, cast(float)surfaceSize[0], cast(float)surfaceSize[1]),
158                 Rect(0, 0, surfaceSize[0], surfaceSize[1])
159             )
160         ];
161         info.blendInfo = ColorBlendInfo(
162             none!LogicOp, [
163                 ColorBlendAttachment(No.enabled,
164                     BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add),
165                     BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add),
166                     ColorMask.all
167                 )
168             ],
169             [ 0f, 0f, 0f, 0f ]
170         );
171         info.layout = pl;
172         info.renderPass = renderPass;
173         info.subpassIndex = 0;
174 
175         auto pls = device.createPipelines( [info] );
176         pipeline = pls[0];
177     }
178 
179 
180     override Submission[] recordCmds(FrameData frameData)
181     {
182         import gfx.graal.types : trans;
183 
184         auto tfd = cast(TriangleFrameData)frameData;
185         auto buf = tfd.cmdBuf;
186 
187         const cv = ClearColorValues(0.6f, 0.6f, 0.6f, hasAlpha ? 0.5f : 1f);
188 
189         buf.begin(CommandBufferUsage.oneTimeSubmit);
190 
191         buf.beginRenderPass(
192             renderPass, tfd.framebuffer,
193             Rect(0, 0, surfaceSize[0], surfaceSize[1]), [ ClearValues(cv) ]
194         );
195 
196         buf.bindPipeline(pipeline);
197         buf.bindVertexBuffers(0, [ VertexBinding(vertBuf, 0) ]);
198         buf.draw(3, 1, 0, 0);
199 
200         buf.endRenderPass();
201 
202         buf.end();
203 
204         return simpleSubmission([ buf ]);
205     }
206 
207 }
208 
209 int main(string[] args)
210 {
211     try {
212 
213         auto example = new TriangleExample(args);
214         example.prepare();
215         scope(exit) example.dispose();
216 
217         example.window.onKeyOn = (KeyEvent ev)
218         {
219             if (ev.sym == KeySym.escape) {
220                 example.window.closeFlag = true;
221             }
222         };
223 
224         while (!example.window.closeFlag) {
225             example.display.pollAndDispatch();
226             example.render();
227             example.frameTick();
228         }
229 
230         return 0;
231     }
232     catch(Exception ex) {
233         stderr.writeln("error occured: ", ex.msg);
234         return 1;
235     }
236 }