diff --git a/assets/shaders/pbr.frag.spv b/assets/shaders/pbr.frag.spv index f097141..4e609a2 100644 Binary files a/assets/shaders/pbr.frag.spv and b/assets/shaders/pbr.frag.spv differ diff --git a/assets/shaders/pbr.vert.spv b/assets/shaders/pbr.vert.spv index 3440819..12d75f6 100644 Binary files a/assets/shaders/pbr.vert.spv and b/assets/shaders/pbr.vert.spv differ diff --git a/src/VulkanRenderer b/src/VulkanRenderer index 1b4d997..d46741a 160000 --- a/src/VulkanRenderer +++ b/src/VulkanRenderer @@ -1 +1 @@ -Subproject commit 1b4d9979765ca8a1c1f45ddf8420edc93d1b79dc +Subproject commit d46741a48033b5136fa189c1b80a574986e68f64 diff --git a/src/gears/game2.d b/src/gears/game2.d index cfbdaf3..324d376 100644 --- a/src/gears/game2.d +++ b/src/gears/game2.d @@ -8,25 +8,28 @@ const u32 UNI_MAX = 50; struct GameState { RenderState rds; + u64 frame; + u64 frame_idx; } struct RenderState { - Renderer rd; - Arena[2] frame_arenas; + Renderer rd; + Arena[2] frame_arenas; + Arena perm_arena; - PushConst pc; - ShaderGlobals globals; + PushConst pc; + ShaderGlobals globals; - Pipeline pipeline_pbr; - DescSetLayout desc_layout_globals; - DescSetLayout desc_layout_resources; - DescSet[2] desc_set_globals; - DescSet[2] desc_set_resources; - PipelineLayout pipeline_layout_pbr; + Pipeline[PID.Max] pipelines; + DescSetLayout desc_layout_globals; + DescSetLayout desc_layout_resources; + DescSet[2] desc_set_globals; + DescSet[2] desc_set_resources; + PipelineLayout pipeline_layout_pbr; - ImageView placeholder_tex; - Buffer globals_buffer; + ImageView placeholder_tex; + Buffer globals_buffer; } struct ShaderGlobals @@ -38,6 +41,68 @@ struct ShaderGlobals f32 alpha = 0.0; } +struct Model +{ + Buffer v_buf; + Buffer i_buf; + Buffer s_buf; + ModelState state; + ModelRenderInfo info; + Vertex[] v; + u32[] idx; +} + +struct ModelRenderInfo +{ + PushConst pc; + PipelineID pid; + + alias pc this; +} + +struct ModelState +{ + Mat4 matrix; +} + +enum PBRMod : u32 +{ + AlbedoValue = 0x0001, + AmbientValue = 0x0002, + SpecularValue = 0x0004, + AlphaValue = 0x0008, + AlbedoTexture = 0x0010, + AmbientTexture = 0x0020, + SpecularTexture = 0x0040, + AlphaTexture = 0x0080, +} + +enum PipelineID : u32 +{ + None, + PBRVVVV, + PBRTVVV, + PBRVTVV, + PBRVVTV, + PBRVVVT, + PBRTTVV, + PBRTVTV, + PBRTVVT, + PBRVTTV, + PBRVTVT, + PBRVVTT, + PBRVTTT, + PBRTVTT, + PBRTTVT, + PBRTTTV, + PBRTTTT, + Max, +} + +alias PID = PipelineID; + +const PID[] PBR_PIPELINES = [PID.PBRVVVV, PID.PBRTVVV, PID.PBRVTVV, PID.PBRVVTV, PID.PBRVVVT, PID.PBRTTVV, PID.PBRTVTV, PID.PBRTVVT, PID.PBRVTTV, PID.PBRVTVT, PID.PBRVVTT, PID.PBRTTTV, PID.PBRTTVT, PID.PBRTVTT, PID.PBRVTTT, PID.PBRTTTT]; + struct PushConst { union @@ -72,6 +137,8 @@ struct Vertex Vec2 uv; } +Model g_box; + GameState InitGame(PlatformWindow* window) { @@ -81,6 +148,34 @@ InitGame(PlatformWindow* window) return g; } +void +RunCycle(GameState* g) +{ + g.frame_idx = g.frame % 2; + + Reset(&g.rds.frame_arenas[g.frame_idx]); + + Renderer* rd = &g.rds.rd; + + BeginFrame(rd); + + BeginRendering(rd); + + PushConstants(rd, g.rds.pipelines[g_box.info.pid], &g_box.info.pc); + + Bind(rd, g.rds.pipelines[g_box.info.pid], [g.rds.desc_set_globals[g.frame_idx], g.rds.desc_set_resources[g.frame_idx]]); + + BindBuffers(rd, &g_box.i_buf, &g_box.v_buf); + + DrawIndexed(rd, cast(u32)g_box.idx.length, 1, 0); + + FinishRendering(rd); + + SubmitAndPresent(rd); + + g.frame += 1; +} + void Init(RenderState* rds, PlatformWindow* window) { @@ -113,6 +208,7 @@ Init(RenderState* rds, PlatformWindow* window) ]; rds.rd = InitRenderer(handles, MB(24), MB(32)); + rds.perm_arena = CreateArena(MB(4)); rds.frame_arenas = [ CreateArena(MB(4)), CreateArena(MB(4)), @@ -129,6 +225,19 @@ Init(RenderState* rds, PlatformWindow* window) rds.desc_set_resources[i] = AllocDescSet(&rds.rd, rds.desc_layout_resources); } + u32[4] spec_data; + + Specialization spec = { + data: spec_data.ptr, + size: u32.sizeof * spec_data.length, + entries: [ + { constantID: 0, size: u32.sizeof, offset: u32.sizeof*0 }, + { constantID: 1, size: u32.sizeof, offset: u32.sizeof*1 }, + { constantID: 2, size: u32.sizeof, offset: u32.sizeof*2 }, + { constantID: 3, size: u32.sizeof, offset: u32.sizeof*3 }, + ], + }; + GfxPipelineInfo pbr_info = { vertex_shader: LoadAssetData(&rds.frame_arenas[0], "shaders/pbr.vert.spv"), frag_shader: LoadAssetData(&rds.frame_arenas[0], "shaders/pbr.frag.spv"), @@ -136,10 +245,21 @@ Init(RenderState* rds, PlatformWindow* window) input_rate_stride: Vertex.sizeof, layout: rds.pipeline_layout_pbr, vertex_attributes: attributes, + vert_spec: spec, + frag_spec: spec, }; - bool result = CreateGraphicsPipeline(&rds.rd, &rds.pipeline_pbr, &pbr_info); - assert(result); + foreach(pid; PBR_PIPELINES) + { + u32 mod = PIDToPBR(pid); + spec_data[0] = mod & PBRMod.AlbedoTexture; + spec_data[1] = mod & PBRMod.AmbientTexture; + spec_data[2] = mod & PBRMod.SpecularTexture; + spec_data[3] = mod & PBRMod.AlphaTexture; + + bool result = CreateGraphicsPipeline(&rds.rd, &rds.pipelines[pid], &pbr_info); + assert(result); + } const u64 tex_size = 32*32*4; u8[tex_size] placeholder_tex; @@ -160,4 +280,140 @@ Init(RenderState* rds, PlatformWindow* window) CreateImageView(&rds.rd, &rds.placeholder_tex, 32, 32, 4, placeholder_tex); CreateBuffer(&rds.rd, &rds.globals_buffer, BT.Uniform, ShaderGlobals.sizeof, false); + bool transfer = Transfer(&rds.rd, &rds.globals_buffer, &rds.globals); + + assert(transfer); + + g_box = MakeBox(rds, 6.0, 6.0, Vec4(0.3, 0.4, 0.8, 1.0)); + + CreateBuffer(&rds.rd, &g_box.v_buf, BT.Vertex, g_box.v.length * Vertex.sizeof, false); + CreateBuffer(&rds.rd, &g_box.i_buf, BT.Index, g_box.idx.length * u32.sizeof, false); + CreateBuffer(&rds.rd, &g_box.s_buf, BT.Uniform, ModelState.sizeof, false); + + transfer = Transfer(&rds.rd, &g_box.v_buf, g_box.v); + transfer &= Transfer(&rds.rd, &g_box.i_buf, g_box.idx); + transfer &= Transfer(&rds.rd, &g_box.s_buf, &g_box.state); + + assert(transfer); + + Write(&rds.rd, rds.desc_set_globals[0], &rds.globals_buffer, 0, DT.Uniform); + Write(&rds.rd, rds.desc_set_globals[1], &rds.globals_buffer, 0, DT.Uniform); + + Write(&rds.rd, rds.desc_set_resources[0], &g_box.s_buf, 2, 0, DT.Uniform); + Write(&rds.rd, rds.desc_set_resources[1], &g_box.s_buf, 2, 0, DT.Uniform); +} + +PipelineID +PBRToPID(u32 mod) +{ + switch(mod) + { + case GetPBRMod(false, false, false, false): return PID.PBRVVVV; + case GetPBRMod(true , false, false, false): return PID.PBRTVVV; + case GetPBRMod(false, true , false, false): return PID.PBRVTVV; + case GetPBRMod(false, false, true , false): return PID.PBRVVTV; + case GetPBRMod(false, false, false, true ): return PID.PBRVVVT; + case GetPBRMod(true , true , false, false): return PID.PBRTTVV; + case GetPBRMod(true , false, true , false): return PID.PBRTVTV; + case GetPBRMod(true , false, false, true ): return PID.PBRTVVT; + case GetPBRMod(false, true , true , false): return PID.PBRVTTV; + case GetPBRMod(false, true , false, true ): return PID.PBRVTVT; + case GetPBRMod(false, false, true , true ): return PID.PBRVVTT; + case GetPBRMod(false, true , true , true ): return PID.PBRVTTT; + case GetPBRMod(true , false, true , true ): return PID.PBRTVTT; + case GetPBRMod(true , true , false, true ): return PID.PBRTTVT; + case GetPBRMod(true , true , true , false): return PID.PBRTTTV; + case GetPBRMod(true , true , true , true ): return PID.PBRTTTT; + default: return PID.None; + } +} + +u32 +PIDToPBR(PipelineID pid) +{ + switch(pid) with(PID) + { + case PBRVVVV: return GetPBRMod(false, false, false, false); + case PBRTVVV: return GetPBRMod(true , false, false, false); + case PBRVTVV: return GetPBRMod(false, true , false, false); + case PBRVVTV: return GetPBRMod(false, false, true , false); + case PBRVVVT: return GetPBRMod(false, false, false, true ); + case PBRTTVV: return GetPBRMod(true , true , false, false); + case PBRTVTV: return GetPBRMod(true , false, true , false); + case PBRTVVT: return GetPBRMod(true , false, false, true ); + case PBRVTTV: return GetPBRMod(false, true , true , false); + case PBRVTVT: return GetPBRMod(false, true , false, true ); + case PBRVVTT: return GetPBRMod(false, false, true , true ); + case PBRTTTV: return GetPBRMod(true , true , true , false); + case PBRTTVT: return GetPBRMod(true , true , false, true ); + case PBRTVTT: return GetPBRMod(true , false, true , true ); + case PBRVTTT: return GetPBRMod(false, true , true , true ); + case PBRTTTT: return GetPBRMod(true , true , true , true ); + default: return 0; + } +} + +static u32 +GetPBRMod(bool albedo = false, bool ambient = false, bool specular = false, bool alpha = false) +{ + with(PBRMod) + { + return + (albedo ? AlbedoTexture : AlbedoValue) | + (ambient ? AmbientTexture : AmbientValue) | + (specular ? SpecularTexture : SpecularValue) | + (alpha ? AlphaTexture : AlphaValue); + } +} + +Model +MakeBox(RenderState* rds, f32 width, f32 height, Vec4 col) +{ + Model box = { + v: Alloc!(Vertex)(&rds.perm_arena, 8), + idx: Alloc!(u32)(&rds.perm_arena, 36), + info: { + pid: PID.PBRVVVV, + }, + state: { + matrix: Mat4Identity(), + }, + }; + + const Vec3[8] positions = [ + Vec3(-1.0, 0.0, -1.0), Vec3(+1.0, 0.0, -1.0), Vec3(+1.0, 1.0, -1.0), Vec3(-1.0, 1.0, -1.0), + Vec3(-1.0, 0.0, +1.0), Vec3(+1.0, 0.0, +1.0), Vec3(+1.0, 1.0, +1.0), Vec3(-1.0, 1.0, +1.0), + ]; + + const u32[36] indices = [ + 0, 1, 3, 3, 1, 2, + 1, 5, 2, 2, 5, 6, + 5, 4, 6, 6, 4, 7, + 4, 0, 7, 7, 0, 3, + 3, 2, 7, 7, 2, 6, + 4, 5, 0, 0, 5, 1, + ]; + + f32 half_width = width/2.0; + + Vec3 pos = Vec3(half_width, height, half_width); + for(u64 i = 0; i < positions.length; i += 1) + { + box.v[i].pos = pos * positions[i]; + } + + box.idx[] = indices[]; + + return box; +} + +unittest +{ + with(PBRMod) with(PID) + { + foreach(pid; PBR_PIPELINES) + { + assert(PBRToPID(PIDToPBR(pid)) == pid); + } + } } diff --git a/src/gears/main.d b/src/gears/main.d index 0e3b733..27ee0a5 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -10,5 +10,16 @@ void main(string[] argv) PlatformWindow window = CreateWindow("Video Game", 1920, 1080); GameState g = InitGame(&window); + + for(;;) + { + Inputs* inputs = GetEvents(&window); + if(window.close) + { + break; + } + + RunCycle(&g); + } } diff --git a/src/shaders/pbr.frag.glsl b/src/shaders/pbr.frag.glsl index b05c6ac..1ce8bd6 100644 --- a/src/shaders/pbr.frag.glsl +++ b/src/shaders/pbr.frag.glsl @@ -5,12 +5,14 @@ #include "structures.layout" layout (location = 0) in struct FragDataIn { + vec4 col; vec3 normal; vec2 uv; } FragData; layout (location = 0, index = 0) out vec4 FragColor; +/* vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal) { float diffuse_factor = max(dot(normal, -dir), 0.0); @@ -36,9 +38,13 @@ vec4 UnPreMultLinearToSRGB(vec4 col) col.b = UnPreMultLinearToSRGB(col.x); return col; } +*/ void main() { + FragColor = FragData.col; + + /* ivec2 coord = ivec2(gl_FragCoord.xy); int store_mask = 0; int view_size = int(G.res.x) * int(G.res.y); @@ -75,4 +81,5 @@ void main() { FragColor = vec4(0.0); //vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending } + */ } diff --git a/src/shaders/pbr.vert.glsl b/src/shaders/pbr.vert.glsl index 940b63b..5292f36 100644 --- a/src/shaders/pbr.vert.glsl +++ b/src/shaders/pbr.vert.glsl @@ -34,6 +34,7 @@ layout (location = 3) in vec3 in_normal; layout (location = 4) in vec2 in_uv; layout (location = 0) out struct FragDataOut { + vec4 col; vec3 normal; vec2 uv; } FragData; @@ -49,6 +50,7 @@ void main() { gl_Position = G.projection * G.view * ModelMatrix * vec4(in_pos, 1.0); - FragData.uv = in_uv; + FragData.uv = in_uv; FragData.normal = mat3(ModelMatrix) * in_normal; + FragData.col = in_col; }