work on basic rendering

This commit is contained in:
matthew 2025-11-01 16:16:46 +11:00
parent 77ce53d4f1
commit 119f5f069c
7 changed files with 292 additions and 16 deletions

Binary file not shown.

Binary file not shown.

@ -1 +1 @@
Subproject commit 1b4d9979765ca8a1c1f45ddf8420edc93d1b79dc Subproject commit d46741a48033b5136fa189c1b80a574986e68f64

View File

@ -8,17 +8,20 @@ const u32 UNI_MAX = 50;
struct GameState struct GameState
{ {
RenderState rds; RenderState rds;
u64 frame;
u64 frame_idx;
} }
struct RenderState struct RenderState
{ {
Renderer rd; Renderer rd;
Arena[2] frame_arenas; Arena[2] frame_arenas;
Arena perm_arena;
PushConst pc; PushConst pc;
ShaderGlobals globals; ShaderGlobals globals;
Pipeline pipeline_pbr; Pipeline[PID.Max] pipelines;
DescSetLayout desc_layout_globals; DescSetLayout desc_layout_globals;
DescSetLayout desc_layout_resources; DescSetLayout desc_layout_resources;
DescSet[2] desc_set_globals; DescSet[2] desc_set_globals;
@ -38,6 +41,68 @@ struct ShaderGlobals
f32 alpha = 0.0; 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 struct PushConst
{ {
union union
@ -72,6 +137,8 @@ struct Vertex
Vec2 uv; Vec2 uv;
} }
Model g_box;
GameState GameState
InitGame(PlatformWindow* window) InitGame(PlatformWindow* window)
{ {
@ -81,6 +148,34 @@ InitGame(PlatformWindow* window)
return g; 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 void
Init(RenderState* rds, PlatformWindow* window) Init(RenderState* rds, PlatformWindow* window)
{ {
@ -113,6 +208,7 @@ Init(RenderState* rds, PlatformWindow* window)
]; ];
rds.rd = InitRenderer(handles, MB(24), MB(32)); rds.rd = InitRenderer(handles, MB(24), MB(32));
rds.perm_arena = CreateArena(MB(4));
rds.frame_arenas = [ rds.frame_arenas = [
CreateArena(MB(4)), CreateArena(MB(4)),
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); 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 = { GfxPipelineInfo pbr_info = {
vertex_shader: LoadAssetData(&rds.frame_arenas[0], "shaders/pbr.vert.spv"), vertex_shader: LoadAssetData(&rds.frame_arenas[0], "shaders/pbr.vert.spv"),
frag_shader: LoadAssetData(&rds.frame_arenas[0], "shaders/pbr.frag.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, input_rate_stride: Vertex.sizeof,
layout: rds.pipeline_layout_pbr, layout: rds.pipeline_layout_pbr,
vertex_attributes: attributes, vertex_attributes: attributes,
vert_spec: spec,
frag_spec: spec,
}; };
bool result = CreateGraphicsPipeline(&rds.rd, &rds.pipeline_pbr, &pbr_info); 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); assert(result);
}
const u64 tex_size = 32*32*4; const u64 tex_size = 32*32*4;
u8[tex_size] placeholder_tex; 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); CreateImageView(&rds.rd, &rds.placeholder_tex, 32, 32, 4, placeholder_tex);
CreateBuffer(&rds.rd, &rds.globals_buffer, BT.Uniform, ShaderGlobals.sizeof, false); 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);
}
}
} }

View File

@ -10,5 +10,16 @@ void main(string[] argv)
PlatformWindow window = CreateWindow("Video Game", 1920, 1080); PlatformWindow window = CreateWindow("Video Game", 1920, 1080);
GameState g = InitGame(&window); GameState g = InitGame(&window);
for(;;)
{
Inputs* inputs = GetEvents(&window);
if(window.close)
{
break;
}
RunCycle(&g);
}
} }

View File

@ -5,12 +5,14 @@
#include "structures.layout" #include "structures.layout"
layout (location = 0) in struct FragDataIn { layout (location = 0) in struct FragDataIn {
vec4 col;
vec3 normal; vec3 normal;
vec2 uv; vec2 uv;
} FragData; } FragData;
layout (location = 0, index = 0) out vec4 FragColor; layout (location = 0, index = 0) out vec4 FragColor;
/*
vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal) vec4 CalculateDirectionalLight(vec4 diff_col, vec4 diff_samp, vec4 light_col, vec3 dir, vec3 normal)
{ {
float diffuse_factor = max(dot(normal, -dir), 0.0); float diffuse_factor = max(dot(normal, -dir), 0.0);
@ -36,9 +38,13 @@ vec4 UnPreMultLinearToSRGB(vec4 col)
col.b = UnPreMultLinearToSRGB(col.x); col.b = UnPreMultLinearToSRGB(col.x);
return col; return col;
} }
*/
void main() void main()
{ {
FragColor = FragData.col;
/*
ivec2 coord = ivec2(gl_FragCoord.xy); ivec2 coord = ivec2(gl_FragCoord.xy);
int store_mask = 0; int store_mask = 0;
int view_size = int(G.res.x) * int(G.res.y); 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 FragColor = vec4(0.0); //vec4(out_col.rgb * out_col.a, out_col.a); // Change to vec4(0.0) to disable tail blending
} }
*/
} }

View File

@ -34,6 +34,7 @@ layout (location = 3) in vec3 in_normal;
layout (location = 4) in vec2 in_uv; layout (location = 4) in vec2 in_uv;
layout (location = 0) out struct FragDataOut { layout (location = 0) out struct FragDataOut {
vec4 col;
vec3 normal; vec3 normal;
vec2 uv; vec2 uv;
} FragData; } FragData;
@ -51,4 +52,5 @@ void main()
FragData.uv = in_uv; FragData.uv = in_uv;
FragData.normal = mat3(ModelMatrix) * in_normal; FragData.normal = mat3(ModelMatrix) * in_normal;
FragData.col = in_col;
} }