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 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(string[] args) { 41 super("Triangle", args); 42 } 43 44 override void dispose() { 45 if (device) { 46 device.waitIdle(); 47 } 48 vertBuf.unload(); 49 pipeline.unload(); 50 renderPass.unload(); 51 releaseArr(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 69 vertBuf = createStaticBuffer(vertexData, BufferUsage.vertex); 70 } 71 72 void prepareRenderPass() { 73 const attachments = [ 74 AttachmentDescription(swapchain.format, 1, 75 AttachmentOps(LoadOp.clear, StoreOp.store), 76 AttachmentOps(LoadOp.dontCare, StoreOp.dontCare), 77 trans(ImageLayout.presentSrc, ImageLayout.presentSrc), 78 No.mayAlias 79 ) 80 ]; 81 const subpasses = [ 82 SubpassDescription( 83 [], [ AttachmentRef(0, ImageLayout.colorAttachmentOptimal) ], 84 none!AttachmentRef, [] 85 ) 86 ]; 87 88 renderPass = device.createRenderPass(attachments, subpasses, []); 89 90 framebuffers = new Framebuffer[scImages.length]; 91 foreach (i; 0 .. scImages.length) { 92 framebuffers[i] = device.createFramebuffer(renderPass, [ 93 scImages[i].createView( 94 ImageType.d2, 95 ImageSubresourceRange(ImageAspect.color), 96 Swizzle.identity 97 ) 98 ], surfaceSize[0], surfaceSize[1], 1); 99 } 100 retainArr(framebuffers); 101 } 102 103 void preparePipeline() 104 { 105 auto vtxShader = device.createShaderModule( 106 cast(immutable(uint)[])import("shader.vert.spv"), "main" 107 ).rc; 108 auto fragShader = device.createShaderModule( 109 cast(immutable(uint)[])import("shader.frag.spv"), "main" 110 ).rc; 111 112 PipelineInfo info; 113 info.shaders.vertex = vtxShader; 114 info.shaders.fragment = fragShader; 115 info.inputBindings = [ 116 VertexInputBinding(0, Vertex.sizeof, No.instanced) 117 ]; 118 info.inputAttribs = [ 119 VertexInputAttrib(0, 0, Format.rgba32_sFloat, 0), 120 VertexInputAttrib(1, 0, Format.rgba32_sFloat, Vertex.color.offsetof), 121 ]; 122 info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart); 123 info.rasterizer = Rasterizer( 124 PolygonMode.fill, Cull.back, FrontFace.ccw, No.depthClamp, 125 none!DepthBias, 1f 126 ); 127 info.viewports = [ 128 ViewportConfig( 129 Viewport(0, 0, cast(float)surfaceSize[0], cast(float)surfaceSize[1]), 130 Rect(0, 0, surfaceSize[0], surfaceSize[1]) 131 ) 132 ]; 133 info.blendInfo = ColorBlendInfo( 134 none!LogicOp, [ 135 ColorBlendAttachment(No.enabled, 136 BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add), 137 BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add), 138 ColorMask.all 139 ) 140 ], 141 [ 0f, 0f, 0f, 0f ] 142 ); 143 info.layout = device.createPipelineLayout([], []); 144 info.renderPass = renderPass; 145 info.subpassIndex = 0; 146 147 auto pls = device.createPipelines( [info] ); 148 pipeline = pls[0]; 149 } 150 151 152 override void recordCmds(size_t cmdBufInd, size_t imgInd) { 153 import gfx.core.typecons : trans; 154 155 if (!perImages.length) { 156 perImages = new PerImage[scImages.length]; 157 } 158 159 const cv = ClearColorValues(0.6f, 0.6f, 0.6f, hasAlpha ? 0.5f : 1f); 160 auto subrange = ImageSubresourceRange(ImageAspect.color, 0, 1, 0, 1); 161 162 auto buf = cmdBufs[cmdBufInd]; 163 164 //buf.reset(); 165 buf.begin(No.persistent); 166 167 if (perImages[imgInd].undefinedLayout) { 168 buf.pipelineBarrier( 169 trans(PipelineStage.colorAttachmentOutput, PipelineStage.colorAttachmentOutput), [], 170 [ ImageMemoryBarrier( 171 trans(Access.none, Access.colorAttachmentWrite), 172 trans(ImageLayout.undefined, ImageLayout.presentSrc), 173 trans(graphicsQueueIndex, graphicsQueueIndex), 174 scImages[imgInd], subrange 175 ) ] 176 ); 177 perImages[imgInd].undefinedLayout = false; 178 } 179 180 buf.beginRenderPass( 181 renderPass, framebuffers[imgInd], 182 Rect(0, 0, surfaceSize[0], surfaceSize[1]), [ ClearValues(cv) ] 183 ); 184 185 buf.bindPipeline(pipeline); 186 buf.bindVertexBuffers(0, [ VertexBinding(vertBuf, 0) ]); 187 buf.draw(3, 1, 0, 0); 188 189 buf.endRenderPass(); 190 191 buf.end(); 192 } 193 194 } 195 196 int main(string[] args) { 197 198 try { 199 auto example = new TriangleExample(args); 200 example.prepare(); 201 scope(exit) example.dispose(); 202 203 example.window.onMouseOn = (uint, uint) { 204 example.window.closeFlag = true; 205 }; 206 207 import std.datetime.stopwatch : StopWatch; 208 209 uint frameCount; 210 ulong lastUs; 211 StopWatch sw; 212 sw.start(); 213 214 enum reportFreq = 100; 215 216 while (!example.window.closeFlag) { 217 example.display.pollAndDispatch(); 218 example.render(); 219 ++ frameCount; 220 if ((frameCount % reportFreq) == 0) { 221 const us = sw.peek().total!"usecs"; 222 writeln("FPS: ", 1000_000.0 * reportFreq / (us - lastUs)); 223 lastUs = us; 224 } 225 } 226 227 return 0; 228 } 229 catch(Exception ex) { 230 stderr.writeln("error occured: ", ex.msg); 231 return 1; 232 } 233 }