1 module depth; 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 gfx.math; 22 23 import std.exception; 24 import std.stdio; 25 import std.typecons; 26 import std.math; 27 28 class DepthExample : Example 29 { 30 Rc!RenderPass renderPass; 31 Rc!Pipeline pipeline; 32 Rc!PipelineLayout layout; 33 size_t cubeLen; 34 enum cubeCount = 3; 35 const(ushort)[] indices; 36 Rc!Buffer vertBuf; 37 Rc!Buffer indBuf; 38 Rc!Buffer matBuf; 39 Rc!Buffer ligBuf; 40 Rc!DescriptorPool descPool; 41 Rc!DescriptorSetLayout setLayout; 42 DescriptorSet set; 43 44 struct Vertex { 45 FVec3 position; 46 FVec3 normal; 47 FVec4 color; 48 } 49 50 struct Matrices { 51 FMat4 mvp; 52 FMat4 normal; 53 } 54 55 enum maxLights = 5; 56 57 struct Light { 58 FVec4 direction; 59 FVec4 color; 60 } 61 62 struct Lights { 63 Light[maxLights] lights; 64 uint num; 65 } 66 67 this(string[] args) { 68 super("Depth", args); 69 } 70 71 override void dispose() { 72 if (device) { 73 device.waitIdle(); 74 } 75 vertBuf.unload(); 76 indBuf.unload(); 77 matBuf.unload(); 78 ligBuf.unload(); 79 setLayout.unload(); 80 descPool.unload(); 81 layout.unload(); 82 pipeline.unload(); 83 renderPass.unload(); 84 super.dispose(); 85 } 86 87 override void prepare() { 88 super.prepare(); 89 prepareBuffers(); 90 preparePipeline(); 91 prepareDescriptorSet(); 92 } 93 94 void prepareBuffers() { 95 96 import gfx.genmesh.cube : genCube; 97 import gfx.genmesh.algorithm : indexCollectMesh, triangulate, vertices; 98 import gfx.genmesh.poly : quad; 99 import std.algorithm : map; 100 101 const cube = genCube() 102 .map!(f => quad( 103 Vertex( fvec(f[0].p), fvec(f[0].n) ), 104 Vertex( fvec(f[1].p), fvec(f[1].n) ), 105 Vertex( fvec(f[2].p), fvec(f[2].n) ), 106 Vertex( fvec(f[3].p), fvec(f[3].n) ), 107 )) 108 .triangulate() 109 .vertices() 110 .indexCollectMesh(); 111 112 cubeLen = cube.vertices.length; 113 114 const red = fvec( 1f, 0f, 0f, 1f ); 115 const green = fvec( 0f, 1f, 0f, 1f ); 116 const blue = fvec( 0f, 0f, 1f, 1f ); 117 const colors = [ red, green, blue ]; 118 119 Vertex[] verts; 120 foreach (c; 0 .. cubeCount) { 121 verts ~= cube.vertices; 122 const color = colors[c % 3]; 123 foreach (v; 0 .. cubeLen) { 124 verts[$ - cubeLen + v].color = color; 125 } 126 } 127 128 indices = cube.indices; 129 vertBuf = createStaticBuffer(verts, BufferUsage.vertex); 130 indBuf = createStaticBuffer(indices, BufferUsage.index); 131 132 const lights = Lights( [ 133 Light(normalize(fvec(1.0, 1.0, -1.0, 0.0)), fvec(0.8, 0.5, 0.2, 1.0)), 134 Light(normalize(fvec(-1.0, 1.0, -1.0, 0.0)), fvec(0.2, 0.5, 0.8, 1.0)), 135 Light.init, Light.init, Light.init 136 ], 2); 137 138 matBuf = createDynamicBuffer(cubeCount * Matrices.sizeof, BufferUsage.uniform); 139 ligBuf = createStaticBuffer(lights, BufferUsage.uniform); 140 } 141 142 override void prepareRenderPass() { 143 const attachments = [ 144 AttachmentDescription(swapchain.format, 1, 145 AttachmentOps(LoadOp.clear, StoreOp.store), 146 AttachmentOps(LoadOp.dontCare, StoreOp.dontCare), 147 trans(ImageLayout.undefined, ImageLayout.presentSrc), 148 No.mayAlias 149 ), 150 AttachmentDescription(findDepthFormat(), 1, 151 AttachmentOps(LoadOp.clear, StoreOp.dontCare), 152 AttachmentOps(LoadOp.dontCare, StoreOp.dontCare), 153 trans(ImageLayout.undefined, ImageLayout.depthStencilAttachmentOptimal), 154 No.mayAlias 155 ) 156 ]; 157 const subpasses = [ 158 SubpassDescription( 159 [], [ AttachmentRef(0, ImageLayout.colorAttachmentOptimal) ], 160 some(AttachmentRef(1, ImageLayout.depthStencilAttachmentOptimal)), 161 [] 162 ) 163 ]; 164 165 renderPass = device.createRenderPass(attachments, subpasses, []); 166 } 167 168 class DepthFrameData : FrameData 169 { 170 PrimaryCommandBuffer cmdBuf; 171 Rc!Image depth; 172 Rc!Framebuffer framebuffer; 173 174 this(ImageBase swcColor, CommandBuffer tempBuf) 175 { 176 super(swcColor); 177 cmdBuf = cmdPool.allocatePrimary(1)[0]; 178 depth = this.outer.createDepthImage(size[0], size[1]); 179 180 auto colorView = swcColor.createView( 181 ImageType.d2, ImageSubresourceRange(ImageAspect.color), Swizzle.identity 182 ).rc; 183 auto depthView = depth.createView( 184 ImageType.d2, ImageSubresourceRange(ImageAspect.depth), Swizzle.identity 185 ).rc; 186 187 this.framebuffer = this.outer.device.createFramebuffer(this.outer.renderPass, [ 188 colorView.obj, depthView.obj 189 ], size[0], size[1], 1); 190 } 191 192 override void dispose() 193 { 194 framebuffer.unload(); 195 depth.unload(); 196 cmdPool.free([ cast(CommandBuffer)cmdBuf ]); 197 super.dispose(); 198 } 199 } 200 201 override FrameData makeFrameData(ImageBase swcColor, CommandBuffer tempBuf) 202 { 203 return new DepthFrameData(swcColor, tempBuf); 204 } 205 206 void preparePipeline() 207 { 208 const spv = [ 209 import("shader.vert.spv"), import("shader.frag.spv") 210 ]; 211 Rc!ShaderModule vtxShader; 212 Rc!ShaderModule fragShader; 213 214 vtxShader = device.createShaderModule( 215 cast(immutable(uint)[])spv[0], "main" 216 ); 217 fragShader = device.createShaderModule( 218 cast(immutable(uint)[])spv[1], "main" 219 ); 220 221 const layoutBindings = [ 222 PipelineLayoutBinding(0, DescriptorType.uniformBufferDynamic, 1, ShaderStage.vertex), 223 PipelineLayoutBinding(1, DescriptorType.uniformBuffer, 1, ShaderStage.fragment), 224 ]; 225 226 setLayout = device.createDescriptorSetLayout(layoutBindings); 227 layout = device.createPipelineLayout([setLayout.obj], []); 228 229 PipelineInfo info; 230 info.shaders.vertex = vtxShader; 231 info.shaders.fragment = fragShader; 232 info.inputBindings = [ 233 VertexInputBinding(0, Vertex.sizeof, No.instanced) 234 ]; 235 info.inputAttribs = [ 236 VertexInputAttrib(0, 0, Format.rgb32_sFloat, 0), 237 VertexInputAttrib(1, 0, Format.rgb32_sFloat, Vertex.normal.offsetof), 238 VertexInputAttrib(2, 0, Format.rgba32_sFloat, Vertex.color.offsetof), 239 ]; 240 info.assembly = InputAssembly(Primitive.triangleList, No.primitiveRestart); 241 info.rasterizer = Rasterizer( 242 PolygonMode.fill, Cull.back, FrontFace.ccw, No.depthClamp, 243 none!DepthBias, 1f 244 ); 245 // info.viewports = [ 246 // ViewportConfig( 247 // Viewport(0, 0, cast(float)surfaceSize[0], cast(float)surfaceSize[1]), 248 // Rect(0, 0, surfaceSize[0], surfaceSize[1]) 249 // ) 250 // ]; 251 info.depthInfo = DepthInfo( 252 Yes.enabled, Yes.write, CompareOp.less, No.boundsTest, 0f, 1f 253 ); 254 info.blendInfo = ColorBlendInfo( 255 none!LogicOp, [ 256 ColorBlendAttachment(No.enabled, 257 BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add), 258 BlendState(trans(BlendFactor.one, BlendFactor.zero), BlendOp.add), 259 ColorMask.all 260 ) 261 ], 262 [ 0f, 0f, 0f, 0f ] 263 ); 264 info.dynamicStates = [ DynamicState.viewport, DynamicState.scissor ]; 265 info.layout = layout; 266 info.renderPass = renderPass; 267 info.subpassIndex = 0; 268 269 auto pls = device.createPipelines( [info] ); 270 pipeline = pls[0]; 271 } 272 273 void prepareDescriptorSet() { 274 const poolSizes = [ 275 DescriptorPoolSize(DescriptorType.uniformBufferDynamic, 1), 276 DescriptorPoolSize(DescriptorType.uniformBuffer, 1), 277 ]; 278 descPool = device.createDescriptorPool(1, poolSizes); 279 set = descPool.allocate([ setLayout.obj ])[0]; 280 281 auto writes = [ 282 WriteDescriptorSet(set, 0, 0, DescriptorWrite.make( 283 DescriptorType.uniformBufferDynamic, 284 matBuf.descriptor(0, Matrices.sizeof), 285 )), 286 287 WriteDescriptorSet(set, 1, 0, DescriptorWrite.make( 288 DescriptorType.uniformBuffer, 289 ligBuf.descriptor(0, Lights.sizeof), 290 )), 291 ]; 292 device.updateDescriptorSets(writes, []); 293 } 294 295 void updateMatrices(in Matrices[] mat) { 296 auto mm = matBuf.boundMemory.map(); 297 auto v = mm.view!(Matrices[])(0, mat.length); 298 v[] = mat; 299 MappedMemorySet mms; 300 mm.addToSet(mms); 301 device.flushMappedMemory(mms); 302 } 303 304 override Submission[] recordCmds(FrameData frameData) 305 { 306 307 auto dfd = cast(DepthFrameData)frameData; 308 309 const ccv = ClearColorValues(0.6f, 0.6f, 0.6f, hasAlpha ? 0.5f : 1f); 310 const dcv = ClearDepthStencilValues(1f, 0); 311 312 PrimaryCommandBuffer buf = dfd.cmdBuf; 313 314 buf.begin(CommandBufferUsage.oneTimeSubmit); 315 316 buf.setViewport(0, [ Viewport(0f, 0f, cast(float)surfaceSize[0], cast(float)surfaceSize[1]) ]); 317 buf.setScissor(0, [ Rect(0, 0, surfaceSize[0], surfaceSize[1]) ]); 318 319 buf.beginRenderPass( 320 renderPass, dfd.framebuffer, 321 Rect(0, 0, surfaceSize[0], surfaceSize[1]), 322 [ ClearValues(ccv), ClearValues(dcv) ] 323 ); 324 325 buf.bindPipeline(pipeline); 326 buf.bindIndexBuffer(indBuf, 0, IndexType.u16); 327 foreach(c; 0 .. cubeCount) { 328 buf.bindVertexBuffers(0, [ VertexBinding(vertBuf, Vertex.sizeof*c*cubeLen) ]); 329 buf.bindDescriptorSets(PipelineBindPoint.graphics, layout, 0, [ set ], [c * Matrices.sizeof]); 330 buf.drawIndexed(cast(uint)indices.length, 1, 0, 0, 0); 331 } 332 333 buf.endRenderPass(); 334 335 buf.end(); 336 337 return simpleSubmission([ buf ]); 338 } 339 340 } 341 342 int main(string[] args) { 343 344 try { 345 auto example = new DepthExample(args); 346 example.prepare(); 347 scope(exit) example.dispose(); 348 349 example.window.onKeyOn = (KeyEvent ev) 350 { 351 if (ev.sym == KeySym.escape) { 352 example.window.closeFlag = true; 353 } 354 }; 355 356 // 6 RPM at 60 FPS 357 const puls = 6 * 2*PI / 3600f; 358 auto angle = 0f; 359 const view = lookAt(fvec(0, -7, 2), fvec(0, 0, 0), fvec(0, 0, 1)); 360 const proj = perspective!float(example.ndc, 45, 4f/3f, 1f, 10f); 361 const viewProj = proj*view; 362 363 DepthExample.Matrices[3] matrices; 364 365 while (!example.window.closeFlag) { 366 367 import gfx.math.inverse : affineInverse; 368 369 foreach (m; 0 .. 3) { 370 const posAngle = cast(float)(m * 2f * PI / 3f); 371 const model = rotation(posAngle + angle, fvec(0, 0, 1)) 372 * translation(2f, 0f, 0f) 373 * rotation(-angle, fvec(0, 0, 1)); 374 const mvp = viewProj*model; 375 matrices[m] = DepthExample.Matrices( 376 mvp.transpose(), 377 model.affineInverse(), // need the transpose of model inverse 378 ); 379 } 380 angle += puls; 381 example.updateMatrices(matrices); 382 383 example.render(); 384 example.frameTick(); 385 386 example.display.pollAndDispatch(); 387 } 388 389 return 0; 390 } 391 catch(Exception ex) { 392 stderr.writeln("error occured: ", ex.msg); 393 return 1; 394 } 395 }