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 }