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 }