1 module triangle;
2 
3 import example;
4 
5 import gfx.core.rc;
6 import gfx.core.typecons;
7 import gfx.core.types;
8 import gfx.graal.buffer;
9 import gfx.graal.cmd;
10 import gfx.graal.device;
11 import gfx.graal.format;
12 import gfx.graal.image;
13 import gfx.graal.memory;
14 import gfx.graal.pipeline;
15 import gfx.graal.presentation;
16 import gfx.graal.queue;
17 import gfx.graal.renderpass;
18 
19 import std.exception;
20 import std.stdio;
21 import std.typecons;
22 
23 class TriangleExample : Example
24 {
25     Rc!RenderPass renderPass;
26     Framebuffer[] framebuffers;
27     Rc!Pipeline pipeline;
28     PerImage[] perImages;
29     Rc!Buffer vertBuf;
30 
31     struct PerImage {
32         bool undefinedLayout=true;
33     }
34 
35     struct Vertex {
36         float[4] position;
37         float[4] color;
38     }
39 
40     this() {
41         super("Triangle");
42     }
43 
44     override void dispose() {
45         if (device) {
46             device.waitIdle();
47         }
48         vertBuf.unload();
49         pipeline.unload();
50         renderPass.unload();
51         releaseArray(framebuffers);
52         super.dispose();
53     }
54 
55     override void prepare() {
56         super.prepare();
57         prepareBuffer();
58         prepareRenderPass();
59         preparePipeline();
60     }
61 
62     void prepareBuffer() {
63         const vertexData = [
64             Vertex([-0.7f,  0.7f, 0f, 1f], [ 0f, 1f, 0f, 1f ]),
65             Vertex([ 0.7f,  0.7f, 0f, 1f], [ 1f, 0f, 0f, 1f ]),
66             Vertex([   0f, -0.7f, 0f, 1f], [ 0f, 0f, 1f, 1f ]),
67         ];
68         const dataSize = vertexData.length * Vertex.sizeof;
69 
70         vertBuf = device.createBuffer( BufferUsage.vertex, dataSize );
71 
72         const mr = vertBuf.memoryRequirements;
73         const props = mr.props | MemProps.hostVisible;
74         const devMemProps = physicalDevice.memoryProperties;
75         uint memTypeInd = uint.max;
76         foreach (uint i, mt; devMemProps.types) {
77             if ((mt.props & props) == props) {
78                 memTypeInd = i;
79                 break;
80             }
81         }
82         enforce(memTypeInd != uint.max, "Could not find a memory type");
83 
84         auto mem = device.allocateMemory(memTypeInd, mr.size).rc;
85         {
86             auto mm = mapMemory!Vertex(mem, 0, vertexData.length);
87             mm[] = vertexData;
88             MappedMemorySet mms;
89             mm.addToSet(mms);
90             device.flushMappedMemory(mms);
91         }
92 
93         vertBuf.bindMemory(mem, 0);
94     }
95 
96     void prepareRenderPass() {
97         const attachments = [
98             AttachmentDescription(swapchain.format, 1,
99                 AttachmentOps(LoadOp.clear, StoreOp.store),
100                 AttachmentOps(LoadOp.dontCare, StoreOp.dontCare),
101                 trans(ImageLayout.presentSrc, ImageLayout.presentSrc),
102                 No.mayAlias
103             )
104         ];
105         const subpasses = [
106             SubpassDescription(
107                 [], [ AttachmentRef(0, ImageLayout.colorAttachmentOptimal) ],
108                 none!AttachmentRef, []
109             )
110         ];
111 
112         renderPass = device.createRenderPass(attachments, subpasses, []);
113 
114         framebuffers = new Framebuffer[scImages.length];
115         foreach (i; 0 .. scImages.length) {
116             framebuffers[i] = device.createFramebuffer(renderPass, [
117                 scImages[i].createView(
118                     ImageType.d2,
119                     ImageSubresourceRange(ImageAspect.color, 0, 1, 0, 1),
120                     Swizzle.init
121                 )
122             ], surfaceSize[0], surfaceSize[1], 1);
123         }
124     }
125 
126     void preparePipeline()
127     {
128         auto vtxShader = device.createShaderModule(
129             ShaderLanguage.spirV, import("shader.vert.spv"), "main"
130         ).rc;
131         auto fragShader = device.createShaderModule(
132             ShaderLanguage.spirV, import("shader.frag.spv"), "main"
133         ).rc;
134 
135         PipelineInfo info;
136         info.shaders.vertex = vtxShader;
137         info.shaders.fragment = fragShader;
138         info.inputBindings = [
139             VertexInputBinding(0, Vertex.sizeof, No.instanced)
140         ];
141         info.inputAttribs = [
142             VertexInputAttrib(0, 0, Format.rgba32_sFloat, 0),
143             VertexInputAttrib(1, 0, Format.rgba32_sFloat, Vertex.color.offsetof),
144         ];
145         info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart);
146         info.rasterizer = Rasterizer(
147             PolygonMode.fill, Cull.back, FrontFace.ccw, No.depthClamp,
148             none!DepthBias, 1f
149         );
150         info.viewports = [
151             ViewportConfig(
152                 Viewport(0, 0, cast(float)surfaceSize[0], cast(float)surfaceSize[1], -1, 1),
153                 Rect(0, 0, surfaceSize[0], surfaceSize[1])
154             )
155         ];
156         info.blendInfo = ColorBlendInfo(
157             none!LogicOp, [
158                 ColorBlendAttachment(No.enabled,
159                     BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add),
160                     BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add),
161                     ColorMask.all
162                 )
163             ],
164             [ 0f, 0f, 0f, 0f ]
165         );
166         info.layout = device.createPipelineLayout();
167         info.renderPass = renderPass;
168         info.subpassIndex = 0;
169 
170         auto pls = device.createPipelines( [info] );
171         pipeline = pls[0];
172     }
173 
174 
175     override void recordCmds(size_t cmdBufInd, size_t imgInd) {
176         import gfx.core.typecons : trans;
177 
178         if (!perImages.length) {
179             perImages = new PerImage[scImages.length];
180         }
181 
182         const cv = ClearColorValues(0.6f, 0.6f, 0.6f, hasAlpha ? 0.5f : 1f);
183         auto subrange = ImageSubresourceRange(ImageAspect.color, 0, 1, 0, 1);
184 
185         auto buf = cmdBufs[cmdBufInd];
186 
187         //buf.reset();
188         buf.begin(No.persistent);
189 
190         if (perImages[imgInd].undefinedLayout) {
191             buf.pipelineBarrier(
192                 trans(PipelineStage.colorAttachment, PipelineStage.colorAttachment), [],
193                 [ ImageMemoryBarrier(
194                     trans(Access.none, Access.colorAttachmentWrite),
195                     trans(ImageLayout.undefined, ImageLayout.presentSrc),
196                     trans(graphicsQueueIndex, graphicsQueueIndex),
197                     scImages[imgInd], subrange
198                 ) ]
199             );
200             perImages[imgInd].undefinedLayout = false;
201         }
202 
203         buf.beginRenderPass(
204             renderPass, framebuffers[imgInd],
205             Rect(0, 0, surfaceSize[0], surfaceSize[1]), [ ClearValues(cv) ]
206         );
207 
208         buf.bindPipeline(pipeline);
209         buf.bindVertexBuffers(0, [ VertexBinding(vertBuf, 0) ]);
210         buf.draw(3, 1, 0, 0);
211 
212         buf.endRenderPass();
213 
214         buf.end();
215     }
216 
217 }
218 
219 int main() {
220 
221     try {
222         auto example = new TriangleExample();
223         example.prepare();
224         scope(exit) example.dispose();
225 
226         bool exitFlag;
227         example.window.mouseOn = (uint, uint) {
228             exitFlag = true;
229         };
230 
231         import std.datetime.stopwatch : StopWatch;
232 
233         size_t frameCount;
234         size_t lastUs;
235         StopWatch sw;
236         sw.start();
237 
238         enum reportFreq = 100;
239 
240         while (!exitFlag) {
241             example.window.pollAndDispatch();
242             example.render();
243             ++ frameCount;
244             if ((frameCount % reportFreq) == 0) {
245                 const us = sw.peek().total!"usecs";
246                 writeln("FPS: ", 1000_000.0 * reportFreq / (us - lastUs));
247                 lastUs = us;
248             }
249         }
250 
251         return 0;
252     }
253     catch(Exception ex) {
254         stderr.writeln("error occured: ", ex.msg);
255         return 1;
256     }
257 }