From e429cee207bb7d2012a2f00118fee237b19a49f1 Mon Sep 17 00:00:00 2001 From: matthew Date: Thu, 24 Jul 2025 07:58:12 +1000 Subject: [PATCH] some work on camera (wip) --- assets/shaders/pbr.vert.spv | Bin 4256 -> 4420 bytes src/gears/game.d | 170 ++++++++++++++++++++++++++++++ src/gears/main.d | 33 ++---- src/gears/platform.d | 201 +++++++++++++++++++++++++++++++++++- src/gears/renderer.d | 130 ++++------------------- src/gears/vulkan.d | 65 +++++++----- src/shaders/pbr.vert.glsl | 2 +- src/shared/util.d | 108 +++++++++++++++++++ 8 files changed, 538 insertions(+), 171 deletions(-) create mode 100644 src/gears/game.d diff --git a/assets/shaders/pbr.vert.spv b/assets/shaders/pbr.vert.spv index 93f724db89b460d0d0b33ba1b55d1d2a46924099..9a311d6984c8e5ca5c6f4ab0c699b45b850f595f 100644 GIT binary patch literal 4420 zcmZve+jbOH5QaOM$%Hc^=TjU&5#=DtK@=fCfC(BP8VCUoP0vgxY3%79dS-%n#VhD* zc#B@>g)iXycv#D|{J-v9lQxUZs#MiqwX15^?%G3T^vJkZ8}T-Jo4sdVv9@`m-iSo_ z&pQhKi{rmK{+swlua^5YX69y2_4@5oXV0A`!WOTR2O`E+PmWquQ74EJ%93-|maO$JG{m}VXS=^%)s z#VE{V-+;Yw_ikh6hTrOT{a*ih9QtvTgnm29!d5?835Rie(9fdpRF06Ew@Z8}_GiOvKFs=Ij@KNH54N-y^`kTqI-dK}qa2Tt{#^9Es_}+4 z&MDhe9Cfcpy?&6i!l8{0V;jWr&^D&t&{r1q91w5BX)}oL7rp5byTI{TiNa@ggqnJZ zKlOC8^a;I56SK0fn%k)<3ww%R$?vZroqik@pGp&|>?@7@$8$`g*Gb!9yc$Zj!k=8~ zpdYn~QOUoB*(u~|{!K)Q-%S+^+gbUx(pd7CcTV!{pdV&Y5KGMCfw6*4GYXUb5Fz=Y&%`Gk-k`p55vMOAH0rKwS9~O?iIt)Icr5IF8p) z3}%q~ot8f`Yh%HN7~cdK-2B)B#y4OXG8lJHZ04hgUCe@1WhwlzvAE0EM8q)c2nMZb zMY0(y@1u^j`@q%qM zyw~Jr(HCZ*$WzQFcsT}kJCF6o_TX0+aYnF;2<&tTqyJ#M0p`a!!1%@ut2ykG62|%P zyHdiKC$Q@!jQIhZ7I8-6mV1j%Z#gGtCdbPig?zarPnP6sCHY24zB!bu`EOo15A#SK z`b8e*!SdWM$@3-oK}mjCk{=D_YChBCsfaiqzq90Fp*O|3(^020+pBk6%r?5!#SG(1 z?`@vxAB%YWZj-O@FZ6Og<{P`^LoeG0(pU2pbB<2^+qH{*hoqq+?~=s**G0RPpL<8= z+u5VP+&LI}U4OZ6?BExj&i_lmj!TCZ@5YNs(>DoYolqoVZ5H7JZe+e&gn8bJ-_3Wc z^8q(svoRBfSv<3CE7|bDj*Yrs7f}PTiGlA<)xKT4E@Dv+x<1wXE)GcFDVg(uO-SOM zw0>cO=+SO*`iq?&q3>}RdG<=Ki$+A`LEk50aR>Xw$;16jxc88{A#CJ0D2|1w-GUPj{g}hp|BjQ{kA6~|*qk4Kblx{G?C*=y z1MKK$oQyu9TRT_M!KmX^L>~?+(s^->>r797CYM|XCsgGW=b-# z@#j5bFaA3uHN@@yrzNxYD&lQ%_KX0Omg&@aM>u}Oz3Y6ys1u!cie+`&lT4rRU%;Tn z{(Y+BOL6e80JYGGgU&m|+OOTdxaABakK}mai{5k?IjMh1q%}z_?uj?cYKWc8cZMCk z%@fKXwj=K0E5i`WxT+)8N^}`}?^Eo0JALiA3 z-jodfqvEjVEfM>`*~jd>D>^1B?>p{r+jl}bd%=lK-S3H*s~;2x{j>-_aAI?RABcEg zh|Rgs@x#t6d@Lfjor~}MqQmEu2c6$#u&cT;=H;@8nF6(!Qug!B+ z7`WxRCK-%8%pJe)&%|T}#vyE$GJSd0X^Y1U@R-B%=R(%h=e5Unt^EOkb3Y&#a5HEO}`SZPFLZ w-bgee;#(sQd-1n>#{RdmTaV$E=Ud6-#rKIgx}7DF%vrGUj-damOczA|0VQgD#Q*>R literal 4256 zcmZve+jbOH5QaOM1K}hh=Tn>z6a)lRKoo(&1SVjBXdvQ=wlmXV8hX0NnH~_Ycm&_W zTlGROd;#Cb!&<9MX{(Ss_1W0{C5SfdQ)C&(Z6>8uAijID2dk6LC^nY6vWY5 z6b@wHguQj=PHXX+-|qMQVfHKz{WwZOzY`6@b{0KR5*Nq$MM*mzb;=Gkd6es~c{N4$ zyk~wd$Oh535{1;g-Qo{pe<>WSgo7;1@w&tD!IloAEJ_oh8*+bol;cs7El1yR}6i`j7Lv$ziK`^=_qrts`(tD<3OCY{919k z8pQXCc~J(QDLCs%6h5``=`A?5_Xp`C<|R$c%D!rD=Psxs#joTu+mcSMHSy(c&~Zt$3Z*nrm-CIy)^Z`UW($_b1tSO8%OY~w9}&~RPVl=>!k7)P4@wyG0M;yFQx2OiVcdEA7DSwp`#vLLnSNL@=j6=X z<>JiM@tvn8YR1MQx1HB8aQjOIR!M%lB%dqEoZtN48_U)FJ5sKH zPB!W%AF;2GeJlByEyj%!ezPPmmgHMwxth--c`73M#J7t)Ec6v|?n=?OVlLP3PBEA0 zR#)5kE@&?@%lc}1xvz%J7Opx=v5$D=edsUl17lxP#Pc8)b%H$?QGX~tBVw7pe!faR z+w5V#&9l{le^)m4lgsq={ndQFu@eLPWAU<`Szqr@G3V$N(GKlm-;6YLd29j4#qkDk2uRAMS4w~J;ZuloO=OAZuFxLo0fh|GCeGMRrTJG%$)$oADwSB zn4Rr}!d)M@_bB~u&z?}}r`f2XAP#qHT#l+4qPGZuB{aSsg9u^cnw;oUJLoUv=De_#KC%69=7l8tZ^|eTWCojGa9S(*sde>p}Jd%v>gs8lTWoLZk4EPcQ{jtN)x!bXb7^d^v1pU0uK%A-rt6ZytfmFY)CArVSxq-2W3zoXC4-TR*;^FNiNM*@6u%_`M`!*%7BPD( z+QZx}i|_%*hZ*=(#Ejk76Q}3*Mfibp*S3i0Klcb5`|$fr#4|DdbIJHDxj0`+W>(9z zMYoK-Ux~QS+zaBc7k_)s*#A;?>oMH&_>#$s?*nmkJIktM&VnrvNB>8eE{OgGdGK)M diff --git a/src/gears/game.d b/src/gears/game.d new file mode 100644 index 0000000..6b25cd1 --- /dev/null +++ b/src/gears/game.d @@ -0,0 +1,170 @@ +import aliases; +import includes; +import renderer : Destroy; +import renderer; +import util; +import platform; +import dplug.math; + +struct Camera +{ + f32 speed = 3.0; + Vec3 pos = Vec3(0.0, 0.0, 3.0); + Vec3 front = Vec3(0.0, 0.0, -1.0); + Vec3 up = Vec3(0.0, 1.0, 0.0); +} + +struct Game +{ + Renderer rd; + + PlatformWindow* window; + + Pipeline pbr_pipeline; + Pipeline triangle_pipeline; + Pipeline compute_pipeline; + Pipeline ui_pipeline; + + GlobalUniforms globals; + + f32 delta; + Timer timer; + + Camera camera; + + Model model; +} + +Game +InitGame(PlatformWindow* window) +{ + Game g = { + rd: InitRenderer(window), + window: window, + timer: CreateTimer(), + }; + + GfxPipelineInfo triangle_info = { + vertex_shader: "shaders/triangle.vert.spv", + frag_shader: "shaders/triangle.frag.spv", + }; + + GfxPipelineInfo ui_info = { + vertex_shader: "shaders/gui.vert.spv", + frag_shader: "shaders/gui.frag.spv", + input_rate: IR.Instance, + input_rate_stride: UIVertex.sizeof, + vertex_attributes: [ + { binding: 0, location: 0, format: FMT.RG_F32, offset: 0 }, + { binding: 0, location: 1, format: FMT.RG_F32, offset: UIVertex.p1.offsetof }, + { binding: 0, location: 2, format: FMT.RGBA_F32, offset: UIVertex.col.offsetof }, + { binding: 0, location: 3, format: FMT.UINT, offset: UIVertex.texture.offsetof }, + ], + }; + + GfxPipelineInfo pbr_info = { + vertex_shader: "shaders/pbr.vert.spv", + frag_shader: "shaders/pbr.frag.spv", + input_rate_stride: Vertex.sizeof, + vertex_attributes: [ + { binding: 0, location: 0, format: FMT.RGBA_F32, offset: 0 }, + { binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.n.offsetof }, + { binding: 0, location: 2, format: FMT.RG_F32, offset: Vertex.uv.offsetof }, + { binding: 0, location: 3, format: FMT.RGBA_UNORM, offset: Vertex.col.offsetof }, + ], + }; + + CompPipelineInfo gradient_info = { + shader: "shaders/gradient.comp.spv", + }; + + g.pbr_pipeline = BuildGfxPipeline(&g.rd, &pbr_info); + g.triangle_pipeline = BuildGfxPipeline(&g.rd, &triangle_info); + g.ui_pipeline = BuildGfxPipeline(&g.rd, &ui_info); + g.compute_pipeline = BuildCompPipeline(&g.rd, &gradient_info); + + g.model = LoadModel(&g.rd, "models/yoda.m3d"); + + return g; +} + +void +Update(Game* g, Camera* cam) +{ + f32 speed = cam.speed * g.delta; + + foreach(i; 0 .. g.window.input_count) + { + switch(g.window.inputs[i].key) + { + case KBI.W: + { + cam.pos += speed * cam.front; + } break; + case KBI.A: + { + cam.pos -= speed * cam.front; + } break; + case KBI.S: + { + cam.pos -= cross(cam.front, cam.up).normalized() * speed; + } break; + case KBI.D: + { + cam.pos += cross(cam.front, cam.up).normalized() * speed; + } break; + default: break; + } + } +} + +void +Cycle(Game* g) +{ + g.delta = DeltaTime(&g.timer); + + Update(g, &g.camera); + + g.globals.projection_matrix = Mat4.identity; + g.globals.view_matrix = Mat4.lookAt(g.camera.pos, g.camera.pos + g.camera.front, g.camera.up); + + BeginFrame(&g.rd); + + Bind(&g.rd, &g.compute_pipeline); + + SetUniform(&g.rd, &g.globals); + + DrawRect(&g.rd, 150.0, 300.0, 500.0, 700.0, Vec4(0.0, 0.0, 1.0, 1.0)); + + PrepComputeDrawImage(&g.rd); + + Dispatch(&g.rd); + + BeginRender(&g.rd); + + Bind(&g.rd, &g.ui_pipeline); + + BindUIBuffers(&g.rd); + + DrawUI(&g.rd); + + Bind(&g.rd, &g.triangle_pipeline); + + Draw(&g.rd, 3, 1); + + Bind(&g.rd, &g.pbr_pipeline); + + DrawModel(&g.rd, &g.model); + + FinishFrame(&g.rd); +} + +void +Destroy(Game* g) +{ + Destroy(&g.rd, &g.pbr_pipeline); + Destroy(&g.rd, &g.triangle_pipeline); + Destroy(&g.rd, &g.ui_pipeline); + Destroy(&g.rd, &g.compute_pipeline); + Destroy(&g.rd); +} diff --git a/src/gears/main.d b/src/gears/main.d index b8ddc6a..3cf45e6 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -2,43 +2,24 @@ public import includes; import std.stdio; import aliases; import core.memory; -import p = platform; -import r = renderer; +import platform; +import game; import util; import core.simd; void main() { - p.Window window = p.CreateWindow("Video Game", 1920, 1080); + PlatformWindow window = CreateWindow("Video Game", 1920, 1080); - r.Renderer rd = r.Init(&window); - scope(exit) r.Destroy(&rd); - - u64 os_freq = OSTimeFreq(); - u64 cpu_start = RDTSC(); - u64 os_start = OSTime(); - u64 os_end = 0; - u64 os_elapsed = 0; - - while (os_elapsed < os_freq) - { - os_end = OSTime(); - os_elapsed = os_end - os_start; - } - - u64 cpu_end = RDTSC(); - u64 cpu_elapsed = cpu_end - cpu_start; - - writefln(" OS Timer: %s -> %s = %s elapsed", os_start, os_end, os_elapsed); - writefln("OS Seconds: %.4f", cast(f64)(os_elapsed)/cast(f64)(os_freq)); - writefln(" CPU Timer: %s -> %s = %s elapsed", cpu_start, cpu_end, cpu_elapsed); + Game g = InitGame(&window); + scope(exit) Destroy(&g); while (true) { - p.HandleEvents(&window); + HandleEvents(&window); if (window.close) break; - r.Cycle(&rd); + Cycle(&g); } } diff --git a/src/gears/platform.d b/src/gears/platform.d index b3973cf..bcc37e2 100644 --- a/src/gears/platform.d +++ b/src/gears/platform.d @@ -3,11 +3,40 @@ import includes; import std.stdio; import core.memory; +enum KeyboardInput +{ + None, + A, B, C, D, E, F, G, H, I, J, K, L, M, + N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, + Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, + NumLock, NumSlash, NumStar, NumMinus, NumPlus, NumEnter, NumPeriod, + Insert, Delete, Home, End, PageUp, PageDown, + PrintScreen, ScrollLock, Pause, + Comma, Period, BackSlash, Backspace, ForwardSlash, Minus, Plus, + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + Up, Down, Left, Right, + LeftCtrl, LeftAlt, LeftShift, LeftSuper, + Tab, CapsLock, + RightCtrl, RightAlt, RightSuper, RightShift, + Enter, Space, + Tilde, Esc, + Semicolon, Quote, LeftBrace, RightBrace, +}; + +alias KBI = KeyboardInput; + version(linux) { import core.sys.posix.dlfcn; -struct Window +struct InputEvent +{ + KeyboardInput key; + bool pressed; +} + +struct PlatformWindow { Display *display; xcb_connection_t *conn; @@ -17,6 +46,8 @@ struct Window u16 w; u16 h; bool close; + InputEvent[10] inputs; + u32 input_count; }; struct Library @@ -29,15 +60,15 @@ struct Function void* ptr; }; -void CheckErr(Window *window, xcb_void_cookie_t *cookie, xcb_generic_error_t *err, string msg) +void CheckErr(PlatformWindow *window, xcb_void_cookie_t *cookie, xcb_generic_error_t *err, string msg) { assert(err == null, msg); pureFree(err); }; -Window CreateWindow(string name, u16 width, u16 height) +PlatformWindow CreateWindow(string name, u16 width, u16 height) { - Window window = { + PlatformWindow window = { w: width, h: height, }; @@ -147,7 +178,7 @@ Window CreateWindow(string name, u16 width, u16 height) }; void -HandleEvents(Window* window) +HandleEvents(PlatformWindow* window) { xcb_generic_event_t* e; @@ -172,6 +203,29 @@ HandleEvents(Window* window) window.close = true; } } break; + case XCB_KEY_RELEASE: + case XCB_KEY_PRESS: + { + // TODO: definitely definitely need to rework this whole thing + if (window.input_count == window.inputs.length) + { + continue; + } + + xcb_key_press_event_t* keyboard_event = cast(xcb_key_press_event_t*)e; + + bool pressed = e.response_type == XCB_KEY_PRESS; + xcb_keycode_t code = keyboard_event.detail; + KeySym key_sym = XkbKeycodeToKeysym(window.display, cast(KeyCode)code, 0, 0); + KBI input = ConvertInput(key_sym); + + if (input != KBI.None) + { + window.inputs[window.input_count].key = input; + window.inputs[window.input_count].pressed = pressed; + window.input_count += 1; + } + } break; default: break; } @@ -202,6 +256,143 @@ Function LoadFunction(Library lib, string name) return fn; }; +KeyboardInput +ConvertInput(u64 x_key) +{ + switch (x_key) + { + case XK_BackSpace: return KBI.Backspace; + case XK_Return: return KBI.Enter; + case XK_Tab: return KBI.Tab; + case XK_Pause: return KBI.Pause; + case XK_Caps_Lock: return KBI.CapsLock; + case XK_Escape: return KBI.Esc; + case XK_space: return KBI.Space; + case XK_Prior: return KBI.PageUp; + case XK_Next: return KBI.PageDown; + case XK_End: return KBI.End; + case XK_Home: return KBI.Home; + case XK_Left: return KBI.Left; + case XK_Up: return KBI.Up; + case XK_Right: return KBI.Right; + case XK_Down: return KBI.Down; + case XK_Print: return KBI.PrintScreen; + case XK_Insert: return KBI.Insert; + case XK_Delete: return KBI.Delete; + case XK_Meta_L: + case XK_Super_L: return KBI.LeftSuper; + case XK_Meta_R: + case XK_Super_R: return KBI.RightSuper; + case XK_KP_0: return KBI.Num0; + case XK_KP_1: return KBI.Num1; + case XK_KP_2: return KBI.Num2; + case XK_KP_3: return KBI.Num3; + case XK_KP_4: return KBI.Num4; + case XK_KP_5: return KBI.Num5; + case XK_KP_6: return KBI.Num6; + case XK_KP_7: return KBI.Num7; + case XK_KP_8: return KBI.Num8; + case XK_KP_9: return KBI.Num9; + case XK_multiply: return KBI.NumStar; + case XK_KP_Subtract: return KBI.NumMinus; + case XK_KP_Decimal: return KBI.NumPeriod; + case XK_KP_Divide: return KBI.NumSlash; + case XK_KP_Add: return KBI.NumPlus; + case XK_F1: return KBI.F1; + case XK_F2: return KBI.F2; + case XK_F3: return KBI.F3; + case XK_F4: return KBI.F4; + case XK_F5: return KBI.F5; + case XK_F6: return KBI.F6; + case XK_F7: return KBI.F7; + case XK_F8: return KBI.F8; + case XK_F9: return KBI.F9; + case XK_F10: return KBI.F10; + case XK_F11: return KBI.F11; + case XK_F12: return KBI.F12; + case XK_Num_Lock: return KBI.NumLock; + case XK_Scroll_Lock: return KBI.ScrollLock; + case XK_Shift_L: return KBI.LeftShift; + case XK_Shift_R: return KBI.RightShift; + case XK_Control_L: return KBI.LeftCtrl; + case XK_Control_R: return KBI.RightCtrl; + case XK_Alt_L: return KBI.LeftAlt; + case XK_Alt_R: return KBI.RightAlt; + case XK_semicolon: return KBI.Semicolon; + case XK_bracketleft: return KBI.LeftBrace; + case XK_bracketright: return KBI.RightBrace; + case XK_plus: return KBI.Plus; + case XK_comma: return KBI.Comma; + case XK_minus: return KBI.Minus; + case XK_backslash: return KBI.BackSlash; + case XK_slash: return KBI.ForwardSlash; + case XK_grave: return KBI.Tilde; + case XK_0: return KBI.Zero; + case XK_1: return KBI.One; + case XK_2: return KBI.Two; + case XK_3: return KBI.Three; + case XK_4: return KBI.Four; + case XK_5: return KBI.Five; + case XK_6: return KBI.Six; + case XK_7: return KBI.Seven; + case XK_8: return KBI.Eight; + case XK_9: return KBI.Nine; + case XK_a: + case XK_A: return KBI.A; + case XK_b: + case XK_B: return KBI.B; + case XK_c: + case XK_C: return KBI.C; + case XK_d: + case XK_D: return KBI.D; + case XK_e: + case XK_E: return KBI.E; + case XK_f: + case XK_F: return KBI.F; + case XK_g: + case XK_G: return KBI.G; + case XK_h: + case XK_H: return KBI.H; + case XK_i: + case XK_I: return KBI.I; + case XK_j: + case XK_J: return KBI.J; + case XK_k: + case XK_K: return KBI.K; + case XK_l: + case XK_L: return KBI.L; + case XK_m: + case XK_M: return KBI.M; + case XK_n: + case XK_N: return KBI.N; + case XK_o: + case XK_O: return KBI.O; + case XK_p: + case XK_P: return KBI.P; + case XK_q: + case XK_Q: return KBI.Q; + case XK_r: + case XK_R: return KBI.R; + case XK_s: + case XK_S: return KBI.S; + case XK_t: + case XK_T: return KBI.T; + case XK_u: + case XK_U: return KBI.U; + case XK_v: + case XK_V: return KBI.V; + case XK_w: + case XK_W: return KBI.W; + case XK_x: + case XK_X: return KBI.X; + case XK_y: + case XK_Y: return KBI.Y; + case XK_z: + case XK_Z: return KBI.Z; + default: return KBI.None; + } +} + } version(Windows) diff --git a/src/gears/renderer.d b/src/gears/renderer.d index bf5a8de..b95a505 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -8,7 +8,7 @@ import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRend import assets; import std.math.traits : isNaN; import u = util : Logf; -import p = platform; +import platform; alias Shader = VkShaderModule; alias Pipeline = PipelineHandle; @@ -51,8 +51,8 @@ alias BT = BufferType; struct GlobalUniforms { - Mat4 view_matrix; - Mat4 projection_matrix; + Mat4 view_matrix = Mat4.identity; + Mat4 projection_matrix = Mat4.identity; Vec2 res; } @@ -106,30 +106,13 @@ struct Renderer Arena temp_arena; Vulkan vk; - p.Window* window; + PlatformWindow* window; - GlobalUniforms globals; UIVertex[] ui_vertex_buf; u32[] ui_index_buf; u32 ui_count; - Pipeline pbr_pipeline; - Pipeline triangle_pipeline; - Pipeline compute_pipeline; - Pipeline ui_pipeline; - PushConst push_const; - - Vec3 camera_pos = Vec3(0.0); - - Model model; -} - -struct Camera -{ - Vec3 pos = Vec3(0.0, 0.0, 3.0); - Vec3 front = Vec3(0.0, 0.0, -1.0); - Vec3 up = Vec3(0.0, 1.0, 0.0); } extern(C) struct Material @@ -182,7 +165,7 @@ struct Model } Renderer -Init(p.Window* window) +InitRenderer(PlatformWindow* window) { u.Result!(Vulkan) vk_result = Init(window, u.MB(24), u.MB(32)); assert(vk_result.ok, "Init failure: Unable to initialize Vulkan"); @@ -196,95 +179,15 @@ Init(p.Window* window) ui_index_buf: GetUIIndexBuffer(&vk_result.value), }; - GfxPipelineInfo triangle_info = { - vertex_shader: "shaders/triangle.vert.spv", - frag_shader: "shaders/triangle.frag.spv", - }; - - GfxPipelineInfo ui_info = { - vertex_shader: "shaders/gui.vert.spv", - frag_shader: "shaders/gui.frag.spv", - input_rate: IR.Instance, - input_rate_stride: UIVertex.sizeof, - vertex_attributes: [ - { binding: 0, location: 0, format: FMT.RG_F32, offset: 0 }, - { binding: 0, location: 1, format: FMT.RG_F32, offset: UIVertex.p1.offsetof }, - { binding: 0, location: 2, format: FMT.RGBA_F32, offset: UIVertex.col.offsetof }, - { binding: 0, location: 3, format: FMT.UINT, offset: UIVertex.texture.offsetof }, - ], - }; - - GfxPipelineInfo pbr_info = { - vertex_shader: "shaders/pbr.vert.spv", - frag_shader: "shaders/pbr.frag.spv", - input_rate_stride: Vertex.sizeof, - vertex_attributes: [ - { binding: 0, location: 0, format: FMT.RGBA_F32, offset: 0 }, - { binding: 0, location: 1, format: FMT.RGBA_F32, offset: Vertex.n.offsetof }, - { binding: 0, location: 2, format: FMT.RG_F32, offset: Vertex.uv.offsetof }, - { binding: 0, location: 3, format: FMT.RGBA_UNORM, offset: Vertex.col.offsetof }, - ], - }; - - CompPipelineInfo gradient_info = { - shader: "shaders/gradient.comp.spv", - }; - - rd.pbr_pipeline = BuildGfxPipeline(&rd, &pbr_info); - rd.triangle_pipeline = BuildGfxPipeline(&rd, &triangle_info); - rd.ui_pipeline = BuildGfxPipeline(&rd, &ui_info); - rd.compute_pipeline = BuildCompPipeline(&rd, &gradient_info); - - rd.model = LoadModel(&rd, "models/yoda.m3d"); - - ReadModel(&rd, "models/yoda.m3d"); - return rd; } -void -Cycle(Renderer* rd) -{ - rd.ui_count = 0; - - rd.globals.view_matrix = Mat4(1.0); - - BeginFrame(rd); - - Bind(rd, &rd.compute_pipeline); - - SetUniform(rd, &rd.globals); - - //DrawRect(rd, 150.0, 300.0, 500.0, 700.0, Vec4(0.0, 0.0, 1.0, 1.0)); - - PrepComputeDrawImage(rd); - - Dispatch(rd); - - BeginRender(rd); - - Bind(rd, &rd.ui_pipeline); - - BindUIBuffers(rd); - - DrawIndexed(rd, 6, rd.ui_count, 0); - - Bind(rd, &rd.triangle_pipeline); - - //Draw(rd, 3, 1); - - Bind(rd, &rd.pbr_pipeline); - - DrawModel(rd, &rd.model); - - FinishFrame(rd); -} - pragma(inline): void DrawModel(Renderer* rd, Model* model) { BindBuffers(&rd.vk, &model.index_buffer, &model.vertex_buffer); + rd.push_const.model_matrix = Mat4.identity; foreach(i, part; model.parts) { rd.push_const.mat_id = part.mat; @@ -308,9 +211,16 @@ CopyVertex(Vec4* dst, m3dv_t* src) pragma(inline): void BeginFrame(Renderer* rd) { + rd.ui_count = 0; BeginFrame(&rd.vk); } +pragma(inline): void +DrawUI(Renderer* rd) +{ + DrawIndexed(rd, 6, rd.ui_count, 0); +} + pragma(inline): void FinishFrame(Renderer* rd) { @@ -410,7 +320,6 @@ ReadModel(Renderer* rd, string name) foreach(i; 0 .. m3d.numtexture) { const(char)[] tex_name = m3d.texture[i].name[0 .. strlen(m3d.texture[i].name)]; - Logf("texture name: %r", tex_name); } if (m3d.numtexture == 0) @@ -421,7 +330,6 @@ ReadModel(Renderer* rd, string name) foreach(i; 0 .. m3d.nummaterial) { const(char)[] mat_name = m3d.material[i].name[0 .. strlen(m3d.material[i].name)]; - Logf("material name: %r", mat_name); } } @@ -445,8 +353,6 @@ LoadModel(Renderer* rd, string name) u32 w = m3d.texture[i].w; u32 h = m3d.texture[i].h; u32 ch = m3d.texture[i].f; u8[] tex_data = m3d.texture[i].d[0 .. w * h * ch]; - Logf("w: %s h: %s ch: %s", w, h, ch); - const(char)[] tex_name = m3d.texture[i].name[0 .. strlen(m3d.texture[i].name)]; CreateImageView(&rd.vk, &model.textures[i], w, h, ch, tex_data); @@ -483,7 +389,7 @@ LoadModel(Renderer* rd, string name) mats[i].specular_texture = tex_lookup[m3d.material[i].prop[j].value.textureid]; mats[i].specular_has_texture = true; } break; - default: Logf("Unimplemented: %s", m3d.material[i].prop[j].type); break; + default: break; } } @@ -588,9 +494,11 @@ LoadModel(Renderer* rd, string name) void Destroy(Renderer* rd) { - Destroy(&rd.vk, rd.triangle_pipeline); - Destroy(&rd.vk, rd.compute_pipeline); Destroy(&rd.vk); } - +void +Destroy(Renderer* rd, Pipeline* pipeline) +{ + Destroy(&rd.vk, pipeline); +} diff --git a/src/gears/vulkan.d b/src/gears/vulkan.d index e241f41..871ffe1 100644 --- a/src/gears/vulkan.d +++ b/src/gears/vulkan.d @@ -7,7 +7,7 @@ import core.stdc.string : strcmp, memcpy; import std.format : sformat; import u = util : HashTable, Result, Logf, Log, MB, Delete; import alloc; -import p = platform; +import platform; import ap = assets; import renderer; import std.math.rounding : Ceil = ceil; @@ -140,7 +140,7 @@ struct Vulkan u.SLList!(SI) cleanup_list; - p.Window* window; + PlatformWindow* window; VkDebugUtilsMessengerEXT dbg_msg; VkInstance instance; @@ -226,7 +226,7 @@ struct QueueInfo }; u.Result!(Vulkan) -Init(p.Window* window, u64 permanent_mem, u64 frame_mem) +Init(PlatformWindow* window, u64 permanent_mem, u64 frame_mem) { bool success = true; @@ -716,8 +716,6 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data) { CreateImageView(vk, view, w, h); - Logf("w: %s h: %s ch: %s", w, h, ch); - if (ch == 4) { assert(Transfer(vk, view, data, w, h), "CreateImageView failure: Image Transfer error"); @@ -1457,6 +1455,7 @@ SetUniform(Vulkan* vk, GlobalUniforms* globals) { globals.res.x = vk.swapchain_extent.width; globals.res.y = vk.swapchain_extent.height; + globals.projection_matrix = Mat4.perspective(1.57, cast(f32)(globals.res.y) / cast(f32)(globals.res.y), 0.1, 100.0); vk.global_buf.data[0] = *globals; @@ -1484,7 +1483,7 @@ Destroy(Vulkan* vk, Shader shader) } void -Destroy(Vulkan* vk, Pipeline pipeline) +Destroy(Vulkan* vk, Pipeline* pipeline) { vkDestroyPipeline(vk.device, pipeline.handle, null); } @@ -1731,36 +1730,43 @@ InitDescriptors(Vulkan* vk) sampler: vk.nearest_sampler, }; - VkDescriptorImageInfo draw_image_info = { - imageView: vk.draw_image.view, - imageLayout: VK_IMAGE_LAYOUT_GENERAL, + VkWriteDescriptorSet write = { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 3, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, + pImageInfo: &sampler_info, }; - VkWriteDescriptorSet[] writes = [ - { - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: vk.desc_sets[DT.Shared], - dstBinding: 3, - descriptorCount: 1, - descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, - pImageInfo: &sampler_info, - }, - { - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: vk.desc_sets[DT.Shared], - dstBinding: 2, - descriptorCount: 1, - descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - pImageInfo: &draw_image_info, - }, - ]; + vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); - vkUpdateDescriptorSets(vk.device, cast(u32)writes.length, writes.ptr, 0, null); + WriteDrawImageDesc(vk); } return success; } +void +WriteDrawImageDesc(Vulkan* vk) +{ + VkDescriptorImageInfo draw_image_info = { + imageView: vk.draw_image.view, + imageLayout: VK_IMAGE_LAYOUT_GENERAL, + }; + + VkWriteDescriptorSet write = { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 2, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + pImageInfo: &draw_image_info, + }; + + vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); +} + void WriteConvDescriptor(Vulkan* vk, Buffer* buf) { @@ -2258,8 +2264,11 @@ RecreateSwapchain(Vulkan* vk) vkDeviceWaitIdle(vk.device); Destroy(vk.swapchain, vk.present_images, vk.device); + Destroy(&vk.draw_image, &vk.depth_image, vk.device, vk.vma); CreateSwapchain(vk); + CreateDrawImages(vk); + WriteDrawImageDesc(vk); } bool diff --git a/src/shaders/pbr.vert.glsl b/src/shaders/pbr.vert.glsl index 41c2a9c..d21d22b 100644 --- a/src/shaders/pbr.vert.glsl +++ b/src/shaders/pbr.vert.glsl @@ -22,7 +22,7 @@ mat4 y_matrix = mat4( void main() { - gl_Position = in_pos * y_matrix; + gl_Position = G.projection_matrix * G.view_matrix * PC.model_matrix * in_pos; vec4 col = Materials[nonuniformEXT(PC.mat_id)].diffuse; diff --git a/src/shared/util.d b/src/shared/util.d index 7f5ae8a..c622068 100644 --- a/src/shared/util.d +++ b/src/shared/util.d @@ -411,3 +411,111 @@ OSTime() return time; } + +// TODO: probably needs improvement/testing +struct IntervalTimer +{ + u64 cpu_freq; + u64 interval; + u64 prev; +} + +IntervalTimer +CreateTimer(u64 fps) +{ + IntervalTimer timer; + + u64 ms_to_wait = 50; + + u64 os_freq = OSTimeFreq(); + u64 cpu_start = RDTSC(); + u64 os_start = OSTime(); + u64 os_end = 0; + u64 os_elapsed = 0; + + u64 os_wait_time = os_freq * ms_to_wait / 1000; + + while (os_elapsed < os_wait_time) + { + os_end = OSTime(); + os_elapsed = os_end - os_start; + } + + u64 cpu_end = RDTSC(); + u64 cpu_elapsed = cpu_end - cpu_start; + u64 cpu_freq = 0; + if (os_elapsed) + { + cpu_freq = os_freq * cpu_elapsed / os_elapsed; + } + + timer.cpu_freq = cpu_freq; + timer.interval = cpu_freq/(fps+1); + timer.prev = RDTSC(); + + return timer; +} + +pragma(inline): bool +CheckTimer(IntervalTimer* t) +{ + bool result = false; + u64 time = RDTSC(); + if (time - t.prev > t.interval) + { + result = true; + t.prev = time; + } + + return result; +} + +struct Timer +{ + u64 cpu_freq; + u64 prev; +} + +Timer +CreateTimer() +{ + u64 ms_to_wait = 50; + + u64 os_freq = OSTimeFreq(); + u64 cpu_start = RDTSC(); + u64 os_start = OSTime(); + u64 os_end = 0; + u64 os_elapsed = 0; + + u64 os_wait_time = os_freq * ms_to_wait / 1000; + + while (os_elapsed < os_wait_time) + { + os_end = OSTime(); + os_elapsed = os_end - os_start; + } + + u64 cpu_end = RDTSC(); + u64 cpu_elapsed = cpu_end - cpu_start; + u64 cpu_freq = 0; + if (os_elapsed) + { + cpu_freq = os_freq * cpu_elapsed / os_elapsed; + } + + Timer timer = { + cpu_freq: cpu_freq, + prev: RDTSC(), + }; + + return timer; +} + +pragma(inline): f32 +DeltaTime(Timer* t) +{ + u64 time = RDTSC(); + u64 step = time - t.prev; + t.prev = time; + return cast(f32)(step) / cast(f32)(t.cpu_freq); +}