summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile17
-rw-r--r--build.ninja9
-rw-r--r--c2.cpp175
-rw-r--r--configure.lua1
-rw-r--r--convmodel.c3
-rw-r--r--convtexture.c128
-rw-r--r--entity.hpp8
-rw-r--r--intermediate/forward.h12
-rw-r--r--intermediate/surface.glsl182
-rw-r--r--intermediate/ts.glsl148
-rw-r--r--lighting.cpp82
-rw-r--r--lighting.hpp12
-rw-r--r--model.cpp33
-rw-r--r--model.hpp4
-rw-r--r--pipeline.cpp24
-rw-r--r--qstd/memory.c2
-rw-r--r--renderer.cpp210
-rw-r--r--renderer.hpp38
-rw-r--r--sc/sc.cpp223
-rw-r--r--sc/sh_enums.h3
-rw-r--r--sc/sh_helpers.h3
-rw-r--r--todo.txt4
-rw-r--r--video.cpp355
-rw-r--r--video.hpp32
-rw-r--r--world.cpp132
-rw-r--r--world.hpp63
26 files changed, 1199 insertions, 704 deletions
diff --git a/Makefile b/Makefile
index fe8d568..4a1b27e 100644
--- a/Makefile
+++ b/Makefile
@@ -118,18 +118,15 @@ data/tonemap.csh: intermediate/tonemap.glsl shadercompiler | data
data/triangle.csh: intermediate/triangle.glsl shadercompiler | data
cpp -MMD -MF data/triangle.d -MT data/triangle.csh -Iintermediate intermediate/triangle.glsl > /dev/null
./shadercompiler intermediate/triangle.glsl data/triangle.csh
-data/ts.csh: intermediate/ts.glsl shadercompiler | data
- cpp -MMD -MF data/ts.d -MT data/ts.csh -Iintermediate intermediate/ts.glsl > /dev/null
- ./shadercompiler intermediate/ts.glsl data/ts.csh
data/ui.csh: intermediate/ui.glsl shadercompiler | data
cpp -MMD -MF data/ui.d -MT data/ui.csh -Iintermediate intermediate/ui.glsl > /dev/null
./shadercompiler intermediate/ui.glsl data/ui.csh
-data/monkey.mdl: convmodel intermediate/monkey.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh | data
+data/monkey.mdl: convmodel intermediate/monkey.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh | data
./convmodel data intermediate/monkey.glb data/monkey.mdl
-data/cube.mdl: convmodel intermediate/cube.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh | data
+data/cube.mdl: convmodel intermediate/cube.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh | data
./convmodel data intermediate/cube.glb data/cube.mdl
-data/scene.mdl: convmodel intermediate/scene.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh | data
+data/scene.mdl: convmodel intermediate/scene.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh | data
./convmodel data intermediate/scene.glb data/scene.mdl
data/22.tex: convtexture intermediate/22.bmp | data
@@ -152,16 +149,16 @@ data/plastic.mat: convmaterial intermediate/plastic.mat | data
data/greybox.mat: convmaterial intermediate/greybox.mat | data
./convmaterial intermediate/greybox.mat data/greybox.mat
-pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat data/greybox.mat
- ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh tonemap.csh triangle.csh ts.csh ui.csh monkey.mdl cube.mdl scene.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat greybox.mat
+pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat data/greybox.mat
+ ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh tonemap.csh triangle.csh ui.csh monkey.mdl cube.mdl scene.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat greybox.mat
data:
mkdir -p data
--include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ts.d data/ui.d
+-include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ui.d
clean:
- rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o renderer.o scene.o ui.o video.o world.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ts.d data/ui.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat data/greybox.mat
+ rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o renderer.o scene.o ui.o video.o world.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ui.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat data/greybox.mat
rm -f shadercompiler
rmdir data
rm -f c2
diff --git a/build.ninja b/build.ninja
index 8635232..0d15a5e 100644
--- a/build.ninja
+++ b/build.ninja
@@ -83,12 +83,11 @@ build data/surface.csh: shadercompiler intermediate/surface.glsl | shadercompile
build data/surface_depthonly.csh: shadercompiler intermediate/surface_depthonly.glsl | shadercompiler.exe
build data/tonemap.csh: shadercompiler intermediate/tonemap.glsl | shadercompiler.exe
build data/triangle.csh: shadercompiler intermediate/triangle.glsl | shadercompiler.exe
-build data/ts.csh: shadercompiler intermediate/ts.glsl | shadercompiler.exe
build data/ui.csh: shadercompiler intermediate/ui.glsl | shadercompiler.exe
-build data/monkey.mdl: convmodel intermediate/monkey.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh
-build data/cube.mdl: convmodel intermediate/cube.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh
-build data/scene.mdl: convmodel intermediate/scene.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh
+build data/monkey.mdl: convmodel intermediate/monkey.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh
+build data/cube.mdl: convmodel intermediate/cube.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh
+build data/scene.mdl: convmodel intermediate/scene.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh
build data/bricks.mat: convmaterial intermediate/bricks.mat | convmaterial.exe
build data/plastic.mat: convmaterial intermediate/plastic.mat | convmaterial.exe
@@ -107,5 +106,5 @@ build data/brick_normal.tex: convtexture intermediate/brick_normal.bmp | convtex
build data/sky.tex: convtexture intermediate/sky.hdr | convtexture.exe
format = rgba16f
-build pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/bricks.mat data/plastic.mat data/greybox.mat data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex | packer.exe
+build pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/bricks.mat data/plastic.mat data/greybox.mat data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex | packer.exe
diff --git a/c2.cpp b/c2.cpp
index 3867280..1f55c15 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -21,9 +21,11 @@ extern "C" {
#define video_arena_size (1024 * 1024 * 16)
#define asset_arena_size (1024 * 1024 * 4)
#define ui_arena_size (1024 * 1024)
-#define scene_arena_size (1024 * 4)
+#define scene_arena_size (1024 * 8)
#define per_frame_memory_size (1024 * 1024)
+#define MSAA_SAMPLES 4
+
static float verts[] = {
0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
@@ -58,33 +60,6 @@ static Buffer_Id upload_verts(Device* dev) {
return vbo;
}
-Texture_Id make_default_texture(Device* dev) {
- unsigned* mem;
- Texture_Id tex;
- Buffer_Id buf = dev->create_buffer(
- "default texture stage",
- 4,
- Buffer_Flags::copy_src |
- Buffer_Flags::cpu_readwrite
- );
- mem = (unsigned*)dev->map_buffer(buf, 0, 4);
- mem[0] = 0xffffffff;
- dev->unmap_buffer(buf);
- tex = dev->create_texture(
- "default PBR texture",
- texture_format_rgba8i,
- Texture_Flags::sampleable | Texture_Flags::copy_dst,
- 1,
- 1,
- 1,
- 1,
- 1,
- buf
- );
- dev->destroy_bufferi(buf);
- return tex;
-}
-
static Sampler_Id create_clamped_linear(Device* dev) {
Sampler_State s{};
s.min = Filter_Mode::linear;
@@ -162,6 +137,61 @@ struct Orbit_Cam {
}
};
+struct Fullscreen_Quad {
+ Buffer_Id vb;
+
+ void init(Device* d) {
+ float verts[] = {
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ -1.0f, 3.0f, 0.0f, 2.0f,
+ 3.0f, -1.0f, 2.0f, 0.0f
+ };
+ Buffer_Id stage;
+ void* mem;
+ stage = d->create_buffer(
+ "sky vb stage",
+ sizeof verts,
+ Buffer_Flags::cpu_readwrite |
+ Buffer_Flags::copy_src
+ );
+ mem = d->map_buffer(stage, 0, sizeof verts);
+ memcpy(mem, verts, sizeof verts);
+ d->unmap_buffer(stage);
+ vb = d->create_buffer(
+ "fullscreen quad",
+ sizeof verts,
+ Buffer_Flags::copy_dst |
+ Buffer_Flags::vertex_buffer
+ );
+ Context& ctx = d->acquire();
+ ctx.copy(vb, stage);
+ d->submit(ctx);
+ d->destroy_bufferi(stage);
+ }
+
+ void destroy(Device* d) {
+ d->destroy_buffer(vb);
+ }
+
+ void render(
+ Context& ctx,
+ Pipeline& pip,
+ Render_Pass& pass,
+ int bind
+ ) {
+ Vertex_Buffer_Binding vbb[] = {{
+ .id = vb,
+ .offset = 0,
+ .target = bind
+ }, {}};
+ Draw draw{};
+ draw.verts = vbb;
+ draw.vertex_count = 3;
+ draw.instance_count = 1;
+ ctx.submit(draw, pip, pass);
+ }
+};
+
struct Sky {
Staged_Buffer config;
Texture_Id texture;
@@ -585,19 +615,19 @@ struct C2 : public App {
Collider* box_col, * floor_col;
Texture* texture;
Texture* texture2;
- Texture_Id default_texture;
Entity_Id monkey, monkey2, box, floor;
Model_Scene scene;
Renderer renderer;
Lighting lighting;
Camera_Id camera;
Orbit_Cam orbit_cam;
+ Fullscreen_Quad quad;
Sky sky;
Env_Probe eprobe;
Tonemap tonemap;
Buffer_Id vbo, cbuf;
Sampler_Id clamped_linear;
- Texture_Id hdr_target;
+ Texture_Id hdr_target, hdr_resolved, ms_depth;
Texture_Id ui_texture;
Buffer_Id ui_buffer;
Line_Renderer lr;
@@ -636,17 +666,17 @@ struct C2 : public App {
);
assets.init(&asset_arena, "pack", 128);
dev = Device::create(&video_arena, this);
- default_texture = make_default_texture(dev);
make_hdr_target();
make_ui_texture();
model_loader.init(dev, &assets);
- mat_loader.init(&assets, default_texture);
+ mat_loader.init(&assets);
register_asset_loader("MODL", &model_loader);
register_asset_loader("MTRL", &mat_loader);
shader = (Shader*)assets.load("triangle.csh");
ui_shader = (Shader*)assets.load("ui.csh");
texture = (Texture*)assets.load("22.tex");
texture2 = (Texture*)assets.load("kita.tex");
+ quad.init(dev);
cbuf = dev->create_buffer(
"config buffer",
sizeof(Config_Buffer),
@@ -658,7 +688,7 @@ struct C2 : public App {
per_frame_memory_size
);
clamped_linear = create_clamped_linear(dev);
- renderer.init(arena, dev, assets);
+ renderer.init(arena, dev);
world = (World*)arena_alloc(arena, sizeof *world);
world->init(arena);
ui = UI::create(this, &ui_arena);
@@ -669,7 +699,7 @@ struct C2 : public App {
ui->layout(w, h);
fps_label = ui->create_element<UI::Label>(ui->root, "");
scene.init(&scene_arena, 32, clamped_linear);
- lighting.init(dev, w, h);
+ lighting.init(dev);
sky.init(dev, &assets);
eprobe.init(dev, &assets, 256);
tonemap.init(dev, &assets);
@@ -702,6 +732,24 @@ struct C2 : public App {
light.caster = true;
}
{
+ auto l = world->create_entity();
+ auto [t, light] = world->add<Transform, Point_Light>(l);
+ t.mat = m4f::translate(m4f::identity(), v3f(-3.0f, 1.0f, 0.0f));
+ light.colour = v3f(1.0f, 0.0f, 0.0f);
+ light.brightness = 5.0f;
+ light.caster = true;
+ light.range = 5.0f;
+ }
+ {
+ auto l = world->create_entity();
+ auto [t, light] = world->add<Transform, Point_Light>(l);
+ t.mat = m4f::translate(m4f::identity(), v3f(3.0f, 2.0f, 0.0f));
+ light.colour = v3f(0.0f, 1.0f, 0.0f);
+ light.brightness = 5.0f;
+ light.caster = true;
+ light.range = 3.0f;
+ }
+ {
box_col = make_box(&asset_arena, v3f(1.0f, 1.0f, 1.0f));
floor_col = make_box(&asset_arena, v3f(10.0f, 0.1f, 10.0f));
box = world->create_entity();
@@ -819,7 +867,7 @@ struct C2 : public App {
pb.begin_rp();
pb.rp_target(hdr_target, Clear_Mode::restore);
- pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore);
+ pb.rp_depth_target(ms_depth, Clear_Mode::restore);
Render_Pass& sky_pass = pb.build_rp();
pb.begin_rp();
@@ -827,7 +875,7 @@ struct C2 : public App {
Render_Pass& tonemap_pass = pb.build_rp();
ctx.debug_push("environment cube");
- eprobe.render(dev, &frame_arena, renderer.quad, sky);
+ eprobe.render(dev, &frame_arena, quad, sky);
ctx.debug_pop();
renderer.env_cubemap = eprobe.get_cubemap();
@@ -846,6 +894,7 @@ struct C2 : public App {
dev,
&frame_arena,
hdr_target,
+ ms_depth,
&lighting
);
ctx.debug_pop();
@@ -854,7 +903,7 @@ struct C2 : public App {
sky.render(
dev,
&frame_arena,
- renderer.quad,
+ quad,
sky_pass,
clamped_linear,
pcam,
@@ -862,15 +911,17 @@ struct C2 : public App {
);
ctx.debug_pop();
+ ctx.resolve(hdr_resolved, hdr_target);
+
tonemap.update(dev, 0.2f);
ctx.debug_push("TONEMAP");
tonemap.render(
dev,
&frame_arena,
- renderer.quad,
+ quad,
tonemap_pass,
- hdr_target,
+ hdr_resolved,
clamped_linear
);
ctx.debug_pop();
@@ -902,7 +953,7 @@ struct C2 : public App {
clamped_linear
);
Pipeline& ui_pip = pb.build();
- renderer.quad.render(
+ quad.render(
ctx,
ui_pip,
ui_pass,
@@ -944,6 +995,7 @@ struct C2 : public App {
}
void on_destroy() override {
+ quad.destroy(dev);
scene.destroy(dev);
sky.destroy(dev);
lighting.destroy(dev, renderer);
@@ -954,8 +1006,9 @@ struct C2 : public App {
ui->destroy();
deinit_editor();
assets.destroy();
- dev->destroy_texture(default_texture);
dev->destroy_texture(hdr_target);
+ dev->destroy_texture(hdr_resolved);
+ dev->destroy_texture(ms_depth);
dev->destroy_texture(ui_texture);
dev->destroy_buffer(ui_buffer);
dev->destroy_sampler(clamped_linear);
@@ -967,25 +1020,53 @@ struct C2 : public App {
void on_resize() override {
ui->layout(w, h);
dev->on_resize();
+ dev->destroy_texture(ms_depth);
dev->destroy_texture(hdr_target);
+ dev->destroy_texture(hdr_resolved);
dev->destroy_texture(ui_texture);
dev->destroy_buffer(ui_buffer);
make_hdr_target();
make_ui_texture();
- lighting.recreate(dev, w, h);
}
void make_hdr_target() {
+ int sw = dev->swap_w();
+ int sh = dev->swap_h();
hdr_target = dev->create_texture(
- "HDR target",
+ "MS HDR target",
texture_format_rgba16f,
- Texture_Flags::sampleable | Texture_Flags::colour_target,
- dev->swap_w(),
- dev->swap_h(),
+ Texture_Flags::copy_src | Texture_Flags::colour_target,
+ sw,
+ sh,
1,
1,
1,
- Buffer_Id(0)
+ Buffer_Id(0),
+ MSAA_SAMPLES
+ );
+ hdr_resolved = dev->create_texture(
+ "Resolved HDR",
+ texture_format_rgba16f,
+ Texture_Flags::sampleable | Texture_Flags::copy_dst,
+ sw,
+ sh,
+ 1,
+ 1,
+ 1,
+ Buffer_Id(0),
+ 1
+ );
+ ms_depth = dev->create_texture(
+ "MS depth",
+ texture_format_d24s8,
+ Texture_Flags::sampleable | Texture_Flags::depth_stencil_target,
+ sw,
+ sh,
+ 1,
+ 1,
+ 1,
+ 0,
+ MSAA_SAMPLES
);
}
diff --git a/configure.lua b/configure.lua
index d944308..9bfe342 100644
--- a/configure.lua
+++ b/configure.lua
@@ -50,7 +50,6 @@ config = {
"surface_depthonly",
"tonemap",
"triangle",
- "ts",
"ui",
},
materials = {
diff --git a/convmodel.c b/convmodel.c
index 31a062d..89f65c8 100644
--- a/convmodel.c
+++ b/convmodel.c
@@ -332,7 +332,7 @@ Shader_Attrib* parse_shader_attribs(const char* fname) {
FILE* f;
char magic[4];
int type, i;
- int binding_count, target_count, desc_count;
+ int binding_count, target_count, desc_count, opt_count;
char* fpath = arena_alloc(
&arena,
string_len(fname) +
@@ -362,6 +362,7 @@ Shader_Attrib* parse_shader_attribs(const char* fname) {
fread(&binding_count, 4, 1, f);
fread(&target_count, 4, 1, f);
fread(&desc_count, 4, 1, f);
+ fread(&opt_count, 4, 1, f);
assert(binding_count);
for (i = 0; i < binding_count; i++) {
char name[24];
diff --git a/convtexture.c b/convtexture.c
index e5ec996..5ad4735 100644
--- a/convtexture.c
+++ b/convtexture.c
@@ -35,6 +35,73 @@ const char* format_names[] = {
#undef x
};
+void gen_mip(Image* src, Image* dst, int w, int h) {
+ const float weight = 1.0f / 4.0f;
+ int i, x, y, sw = src->w;
+ dst->pixels = malloc(w * h * sizeof *dst->pixels);
+ dst->w = w;
+ dst->h = h;
+ assert(w == src->w / 2);
+ assert(h == src->h / 2);
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int sx = x << 1;
+ int sy = y << 1;
+ int ind[] = {
+ sx + (sy) * sw,
+ sx + 1 + (sy) * sw,
+ sx + (sy + 1) * sw,
+ sx + 1 + (sy + 1) * sw
+ };
+ float avg[4] = { 0 };
+ Colour* d = &dst->pixels[x + y * w];
+ for (i = 0; i < 4; i++) {
+ int j;
+ for (j = 0; j < 4; j++)
+ avg[j] +=
+ (float)((uint8_t*)&src->pixels[ind[i]])[j] *
+ weight;
+ }
+ d->r = (uint8_t)avg[0];
+ d->g = (uint8_t)avg[1];
+ d->b = (uint8_t)avg[2];
+ d->a = (uint8_t)avg[3];
+ }
+ }
+}
+
+int auto_count(int w, int h) {
+ int i;
+ for (i = 0; w > 1 || h > 1; i++, w >>= 1, h >>= 1);
+ return i;
+}
+
+int po2(int x) {
+ return x && (!(x & (x - 1)));
+}
+
+Image* gen_mips(Image* src, int count, int* gen_count) {
+ int i, w, h;
+ Image* imgs;
+ if (!count)
+ count = auto_count(src->w, src->h);
+ imgs = malloc(count * sizeof *imgs);
+ imgs[0] = *src;
+ w = src->w >> 1;
+ h = src->h >> 1;
+ if (count && (!po2(src->w) || !po2(src->h))) {
+ print_war("Image size not a power of 2 (no mips for you >:(\n");
+ count = 1;
+ }
+ for (i = 1; i < count; i++) {
+ gen_mip(&imgs[i - 1], &imgs[i], w, h);
+ w >>= 1;
+ h >>= 1;
+ }
+ *gen_count = i;
+ return imgs;
+}
+
unsigned encode_endpoint(const vec3* v) {
return
((unsigned)(v->r * 31.9999f) << 11) |
@@ -264,28 +331,33 @@ void compress_bc5(Colour* pixels, int w, int h, FILE* f) {
}
}
-void write_header(FILE* f, int w, int h, Texture_Format fmt) {
+void write_header(FILE* f, int w, int h, int mips, Texture_Format fmt) {
fwrite("TXTR", 1, 4, f);
fwrite(&w, 1, 4, f);
fwrite(&h, 1, 4, f);
- fwrite(&fmt, 1, 4, f);
+ fwrite(&fmt, 1, 2, f);
+ fwrite(&mips, 1, 2, f);
}
-void convert(Image* image, Texture_Format target, FILE* f) {
- write_header(f, image->w, image->h, target);
- switch (target) {
- case texture_format_bc1:
- compress_bc1(image->pixels, image->w, image->h, f);
- break;
- case texture_format_bc4:
- compress_bc4(image->pixels, image->w, image->h, f);
- break;
- case texture_format_bc5:
- compress_bc5(image->pixels, image->w, image->h, f);
- break;
- default:
- print_err("Unsupported target format.\n");
- pbreak(40);
+void convert(Image* images, int count, Texture_Format target, FILE* f) {
+ int i;
+ write_header(f, images->w, images->h, count, target);
+ for (i = 0; i < count; i++) {
+ Image* image = &images[i];
+ switch (target) {
+ case texture_format_bc1:
+ compress_bc1(image->pixels, image->w, image->h, f);
+ break;
+ case texture_format_bc4:
+ compress_bc4(image->pixels, image->w, image->h, f);
+ break;
+ case texture_format_bc5:
+ compress_bc5(image->pixels, image->w, image->h, f);
+ break;
+ default:
+ print_err("Unsupported target format.\n");
+ pbreak(40);
+ }
}
}
@@ -299,12 +371,17 @@ Texture_Format texture_format_from_string(const char* s) {
return (Texture_Format)0;
}
-int proc_bitmap(FILE* infile, FILE* outfile, Texture_Format target) {
+int proc_bitmap(
+ FILE* infile,
+ FILE* outfile,
+ Texture_Format target,
+ int mc
+) {
unsigned bmp_offset;
int bmp_w, bmp_h, s, x, y;
unsigned short bmp_bits;
Colour* buffer;
- Image img;
+ Image img, * imgs;
Colour pixel;
fseek(infile, 10, SEEK_SET);
@@ -347,7 +424,8 @@ int proc_bitmap(FILE* infile, FILE* outfile, Texture_Format target) {
img.pixels = buffer;
img.w = bmp_w;
img.h = bmp_h;
- convert(&img, target, outfile);
+ imgs = gen_mips(&img, mc, &mc);
+ convert(imgs, mc, target, outfile);
fclose(outfile);
return 0;
}
@@ -519,12 +597,13 @@ int proc_hdr(FILE* infile, FILE* outfile, int half) {
}
}
if (half) {
- write_header(outfile, w, h, texture_format_rgba16f);
+ write_header(outfile, w, h, 1, texture_format_rgba16f);
write_halves(outfile, w * h * 4, (float*)pixels);
} else {
- write_header(outfile, w, h, texture_format_rgba32f);
+ write_header(outfile, w, h, 1, texture_format_rgba32f);
fwrite(pixels, sizeof *pixels, w * h, outfile);
}
+ /* todo mipgen for hdr */
fclose(outfile);
return 0;
}
@@ -532,6 +611,7 @@ int proc_hdr(FILE* infile, FILE* outfile, int half) {
int main(int argc, const char** argv) {
FILE* outfile, * infile;
char magic[11];
+ int mips = 0;
Texture_Format target;
if (argc < 4) {
@@ -545,6 +625,8 @@ int main(int argc, const char** argv) {
return 2;
}
target = texture_format_from_string(argv[3]);
+ if (argc > 4)
+ mips = (int)strtol(argv[4], 0, 10);
outfile = fopen(argv[2], "wb");
if (!outfile) {
@@ -554,7 +636,7 @@ int main(int argc, const char** argv) {
fread(magic, 1, 10, infile); magic[10] = 0;
if (magic[0] == 'B' && magic[1] == 'M') {
- return proc_bitmap(infile, outfile, target);
+ return proc_bitmap(infile, outfile, target, mips);
}
if (string_equal(magic, "#?RADIANCE")) {
int half = target == texture_format_rgba16f;
diff --git a/entity.hpp b/entity.hpp
new file mode 100644
index 0000000..34cc84d
--- /dev/null
+++ b/entity.hpp
@@ -0,0 +1,8 @@
+#ifndef entity_hpp
+#define entity_hpp
+
+#include <stdint.h>
+
+using Entity_Id = uint32_t;
+
+#endif
diff --git a/intermediate/forward.h b/intermediate/forward.h
index 7c4c9d3..3bc2d50 100644
--- a/intermediate/forward.h
+++ b/intermediate/forward.h
@@ -5,7 +5,7 @@
[struct]
name: Light
[variable]
-name: dir
+name: pos
type: vec3
[variable]
name: brightness
@@ -16,6 +16,9 @@ type: vec3
[variable]
name: caster_id
type: int
+[variable]
+name: range
+type: float
[struct]
name: Caster
@@ -34,6 +37,12 @@ type: int
[variable]
name: frame
type: int
+[variable]
+name: sun_irange
+type: ivec2
+[variable]
+name: point_irange
+type: ivec2
[cbuffer]
name: globals
@@ -41,4 +50,5 @@ type: Globals
stage: fragment
#endif
+
#endif
diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl
index 82bf2f6..cc287e4 100644
--- a/intermediate/surface.glsl
+++ b/intermediate/surface.glsl
@@ -9,6 +9,22 @@ fragment: main
#ifdef DESC
+[option]
+name: albedomap
+stage: fragment
+[option]
+name: aomap
+stage: fragment
+[option]
+name: metalmap
+stage: fragment
+[option]
+name: roughmap
+stage: fragment
+[option]
+name: normalmap
+stage: fragment
+
[binding]
name: mesh
rate: vertex
@@ -29,9 +45,6 @@ type: vec2
name: uv
type: vec2
[interpolator]
-name: screen
-type: vec4
-[interpolator]
name: position
type: vec4
[interpolator]
@@ -117,7 +130,7 @@ dimension: cube
[texture]
name: shadowmaps
stage: fragment
-dimension: array
+dimension: shadowArray
[target]
name: colour
@@ -136,9 +149,7 @@ void main() {
interpolator.uv = uv;
interpolator.position = pos;
interpolator.tbn = mat3(t, b, n);
- pos = c_vp.view_projection * pos;
- interpolator.screen = pos;
- gl_Position = pos;
+ gl_Position = c_vp.view_projection * pos;
}
#endif
@@ -147,8 +158,8 @@ void main() {
#define pi 3.14159265358979323846
-vec3 diffuse_brdf(vec2 uv) {
- vec3 a = material.albedo * texture(albedo, uv).rgb;
+vec3 diffuse_brdf(vec2 uv, vec3 base) {
+ vec3 a = base;
return a / pi;
}
@@ -162,7 +173,11 @@ float specular_G1(float a, vec3 v, vec3 n) {
float specular_brdf(vec2 uv, vec3 ref, vec3 l, vec3 v, vec3 n) {
float ndl = max(dot(n, l), 0.0);
float ndv = max(dot(n, v), 0.0);
+#if OPT_roughmap
float a = texture(rough, uv).r * material.roughness;
+#else
+ float a = material.roughness;
+#endif
float a2 = a * a;
float ndr = max(dot(n, ref), 0.0);
float b = ((ndr * ndr) * (a2 - 1) + 1);
@@ -175,45 +190,160 @@ float specular_brdf(vec2 uv, vec3 ref, vec3 l, vec3 v, vec3 n) {
return (D * F * G) / (4.0 * ndl * ndv + 0.001);
}
-void main() {
+vec2 poissonDisk[16] = vec2[](
+ vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790)
+);
+
+float random(vec3 seed, int i){
+ vec4 seed4 = vec4(seed,i);
+ float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}
+
+float get_shadow(Light l, vec3 wpos) {
+ const int taps = 4;
+ const float w = 1.0 / float(taps);
+ const float m = 1.0 / 1000.0;
int i;
+ float d = 0.0f;
+ Caster caster = casters[l.caster_id];
+ vec4 surf = caster.projection * vec4(wpos, 1.0);
+ surf /= surf.w;
+ surf.xy = surf.xy * 0.5 + 0.5;
+ surf.z -= 0.005;
+ for (i = 0; i < taps; i++) {
+ int index = int(16.0 * random(floor(wpos.xyz * 1000.0), i)) % 16;
+ vec2 coord = surf.xy + poissonDisk[index] * m;
+ vec4 vec = vec4(coord, float(l.caster_id), surf.z);
+ d += texture(shadowmaps, vec).r * w;
+ }
+ return d;
+}
+
+vec3 apply_light(
+ Light l,
+ vec3 p,
+ vec2 uv,
+ vec3 base_diffuse,
+ vec3 spec_col,
+ vec3 ref,
+ vec3 light_dir,
+ vec3 view_dir,
+ vec3 nrm,
+ float cos_theta_i,
+ float atten
+) {
+ vec3 diffuse = base_diffuse * cos_theta_i;
+ vec3 spec =
+ spec_col *
+ specular_brdf(uv, ref, light_dir, view_dir, nrm) *
+ cos_theta_i;
+ float shadow = 1.0f;
+ if (l.caster_id >= 0)
+ shadow = get_shadow(l, p);
+ return (diffuse + spec) * atten * l.brightness * l.colour * shadow;
+}
+
+void main() {
+ int i, e;
vec2 uv = interpolator.uv;
- vec2 suv = (interpolator.screen.xy / interpolator.screen.w) * 0.5 + 0.5;
vec3 p = interpolator.position.xyz;
+#if OPT_normalmap
vec3 nrmsample = texture(normal, uv).rgb;
vec2 nrmxy = nrmsample.xy * 2.0 - 1.0;
vec3 nrm = normalize(vec3(nrmxy, 1.0));
- if (nrmsample.b == 1.0) /* default texture */
- nrm = normalize(interpolator.tbn[2]);
- else
- nrm = normalize(interpolator.tbn * nrm);
+ nrm = normalize(interpolator.tbn * nrm);
+#else
+ vec3 nrm = normalize(interpolator.tbn[2]);
+#endif
+#if OPT_albedomap
vec3 col = texture(albedo, uv).rgb * material.albedo;
- vec3 view_dir = normalize(globals.camera_pos - p);
+#else
+ vec3 col = material.albedo;
+#endif
+
+#if OPT_metalmap
float met = texture(metal, uv).r * material.metalness;
+#else
+ float met = material.metalness;
+#endif
+
+ vec3 view_dir = normalize(globals.camera_pos - p);
vec3 ref = reflect(-view_dir, nrm);
vec3 ref_col = texture(env_cube, ref, material.roughness * 8.0).rgb;
vec3 spec_col = mix(ref_col, ref_col * col, met);
vec3 amb_col = min(textureLod(env_cube, nrm, 8.0).rgb, 0.05);
+#if OPT_aomap
vec3 ambient =
amb_col *
texture(ao, uv).r * material.ao;
+#else
+ vec3 ambient = amb_col * material.ao;
+#endif
- vec3 base_diffuse = diffuse_brdf(uv) * (1.0 - met);
+ vec3 base_diffuse = diffuse_brdf(uv, col) * (1.0 - met);
vec3 light = 0.0.xxx;
- for (i = 0; i < globals.light_count; i++) {
+ e = globals.sun_irange.y;
+ for (i = globals.sun_irange.x; i < e; i++) {
Light l = lights[i];
- vec3 light_dir = l.dir;
+ vec3 light_dir = l.pos;
float cos_theta_i = max(dot(nrm, light_dir), 0.0);
- vec3 diffuse = base_diffuse * cos_theta_i;
- vec3 spec =
- spec_col *
- specular_brdf(uv, ref, light_dir, view_dir, nrm) *
- cos_theta_i;
- float shadow = texture(shadowmaps, vec3(suv, float(l.caster_id))).r;
- light += (diffuse + spec) * l.brightness * l.colour * shadow;
+ float atten = 1.0;
+ light += apply_light(
+ l,
+ p,
+ uv,
+ base_diffuse,
+ spec_col,
+ ref,
+ light_dir,
+ view_dir,
+ nrm,
+ cos_theta_i,
+ atten
+ );
+ }
+ e = globals.point_irange.y;
+ for (i = globals.point_irange.x; i < e; i++) {
+ Light l = lights[i];
+ float cos_theta_i;
+ vec3 light_dir = l.pos - p;
+ float d = length(light_dir);
+ float atten = max(d, 0.01);
+ atten = 1.0 / (atten * atten);
+ light_dir /= d;
+ cos_theta_i = max(dot(nrm, light_dir), 0.0);
+ light += apply_light(
+ l,
+ p,
+ uv,
+ base_diffuse,
+ spec_col,
+ ref,
+ light_dir,
+ view_dir,
+ nrm,
+ cos_theta_i,
+ atten
+ );
}
colour = vec4(ambient + light, 1.0);
diff --git a/intermediate/ts.glsl b/intermediate/ts.glsl
deleted file mode 100644
index 23195f6..0000000
--- a/intermediate/ts.glsl
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifdef DESC
-[program]
-type: graphics
-vertex: main
-fragment: main
-#endif
-
-#include "forward.h"
-
-#ifdef DESC
-
-[binding]
-name: verts
-rate: vertex
-[attribute]
-name: position
-type: vec2
-[attribute]
-name: uv
-type: vec2
-
-[interpolator]
-name: uv
-type: vec2
-
-[texture]
-name: shadowmaps
-stage: fragment
-dimension: shadowArray
-[texture]
-name: previous
-stage: fragment
-dimension: 2
-[texture]
-name: depthmap
-stage: fragment
-dimension: 2
-
-[struct]
-name: Config
-[variable]
-name: inv_view
-type: mat4
-[variable]
-name: inv_proj
-type: mat4
-[variable]
-name: prev_vp
-type: mat4
-
-[struct]
-name: Caster_Config
-[variable]
-name: index
-type: int
-
-[cbuffer]
-name: config
-type: Config
-stage: fragment
-
-[cbuffer]
-name: caster_config
-type: Caster_Config
-stage: fragment
-
-[sbuffer]
-name: casters
-type: Caster
-stage: fragment
-
-[target]
-name: shadow_amount
-type: float
-
-#endif
-
-#ifdef VERTEX_SHADER
-void main() {
- interpolator.uv = uv;
- gl_Position = vec4(position, 1.0, 1.0);
-}
-#endif
-
-#ifdef FRAGMENT_SHADER
-
-vec2 poissonDisk[16] = vec2[](
- vec2(-0.94201624, -0.39906216),
- vec2(0.94558609, -0.76890725),
- vec2(-0.094184101, -0.92938870),
- vec2(0.34495938, 0.29387760),
- vec2(-0.91588581, 0.45771432),
- vec2(-0.81544232, -0.87912464),
- vec2(-0.38277543, 0.27676845),
- vec2(0.97484398, 0.75648379),
- vec2(0.44323325, -0.97511554),
- vec2(0.53742981, -0.47373420),
- vec2(-0.26496911, -0.41893023),
- vec2(0.79197514, 0.19090188),
- vec2(-0.24188840, 0.99706507),
- vec2(-0.81409955, 0.91437590),
- vec2(0.19984126, 0.78641367),
- vec2(0.14383161, -0.14100790)
-);
-
-float random(vec3 seed, int i){
- vec4 seed4 = vec4(seed,i);
- float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
- return fract(sin(dot_product) * 43758.5453);
-}
-
-float get_shadow(int id, vec3 wpos) {
- const int taps = 4;
- const float w = 1.0 / float(taps);
- const float m = 1.0 / 1000.0;
- int i;
- float d = 0.0f;
- Caster caster = casters[id];
- vec4 surf = caster.projection * vec4(wpos, 1.0);
- surf /= surf.w;
- surf.xy = surf.xy * 0.5 + 0.5;
- surf.z -= 0.005;
- for (i = 0; i < taps; i++) {
- int index = int(16.0 * random(floor(wpos.xyz * 1000.0), i + globals.frame)) % 16;
- vec2 coord = surf.xy + poissonDisk[index] * m;
- vec4 vec = vec4(coord, float(id), surf.z);
- d += texture(shadowmaps, vec).r * w;
- }
- return d;
-}
-
-vec3 get_world_pos(float depth, vec2 uv) {
- float z = depth;
- vec4 clip = vec4(uv * 2.0 - 1.0, z, 1.0);
- vec4 view = config.inv_proj * clip;
- view /= view.w;
- return (config.inv_view * view).xyz;
-}
-
-void main() {
- vec2 uv = interpolator.uv;
- float d = texture(depthmap, uv).r;
- vec3 wpos = get_world_pos(d, uv);
- float prev = texture(previous, uv).r;
- float current = get_shadow(caster_config.index, wpos);
- shadow_amount = (prev + current) * 0.5;
-}
-#endif
diff --git a/lighting.cpp b/lighting.cpp
index 4f1fdfb..b140611 100644
--- a/lighting.cpp
+++ b/lighting.cpp
@@ -1,6 +1,7 @@
#include "lighting.hpp"
#include "model.hpp"
#include "renderer.hpp"
+#include "scene.hpp"
#include "world.hpp"
extern "C" {
@@ -10,17 +11,19 @@ extern "C" {
/* needs to match surface shader */
struct GPU_Light {
- v3f dir;
+ v3f pos;
float brightness;
v3f colour;
int caster_id;
+ float range;
+ int pad[3];
};
struct GPU_Caster {
m4f projection;
};
-void Lighting::init(Device* dev, int w, int h) {
+void Lighting::init(Device* dev) {
int i;
Sampler_State ss{};
lights.init(
@@ -46,9 +49,6 @@ void Lighting::init(Device* dev, int w, int h) {
max_shadows,
0
);
- zero(ss_shadows, sizeof ss_shadows);
- zero(ss_shadow_slices, sizeof ss_shadow_slices);
- recreate(dev, w, h);
for (i = 0; i < max_shadows; i++) {
cameras[i] = 0;
shadow_slices[i] = dev->alias_texture(
@@ -88,50 +88,6 @@ void Lighting::destroy(Device* dev, Renderer& r) {
r.destroy_camera(cameras[i]);
}
dev->destroy_texture(shadows);
- destroy_ss(dev);
-}
-
-void Lighting::destroy_ss(Device* dev) {
- int i, j;
- for (i = 0; i < 2; i++) {
- for (j = 0; j < max_shadows; j++)
- if (ss_shadow_slices[i][j])
- dev->destroy_texture(ss_shadow_slices[i][j]);
- if (ss_shadows[i])
- dev->destroy_texture(ss_shadows[i]);
- }
-}
-
-void Lighting::recreate(Device* dev, int w, int h) {
- int i, j;
- destroy_ss(dev);
- for (i = 0; i < 2; i++) {
- ss_shadows[i] = dev->create_texture(
- "Shadow accumulation buffer",
- texture_format_r8i,
- Texture_Flags::sampleable | Texture_Flags::colour_target,
- w,
- h,
- 1,
- 1,
- max_shadows,
- 0
- );
- for (j = 0; j < max_shadows; j++)
- ss_shadow_slices[i][j] = dev->alias_texture(
- ss_shadows[i],
- "Shadow accumulation buffer slice",
- texture_format_r8i,
- Texture_Flags::colour_target,
- shadow_res,
- shadow_res,
- 1,
- 1,
- 1,
- 0,
- j
- );
- }
}
void Lighting::write_bufs(
@@ -144,16 +100,17 @@ void Lighting::write_bufs(
GPU_Light* ldst = (GPU_Light*)lptr;
GPU_Caster* cdst = (GPU_Caster*)cptr;
int count = 0, ccount = 0;
+ sun_range[0] = count;
for (auto v : w.view<Sun_Light>()) {
GPU_Light gl;
Sun_Light& l = v.get<Sun_Light>();
if (count >= max_lights) {
print_war("Over light limit.\n");
- return;
+ goto cancel;
}
gl.brightness = l.brightness;
gl.colour = l.colour;
- gl.dir = l.dir;
+ gl.pos = l.dir;
if (l.caster && ccount < max_shadows) {
int cid = ccount++;
GPU_Caster& c = cdst[cid];
@@ -169,6 +126,29 @@ void Lighting::write_bufs(
gl.caster_id = -1;
ldst[count++] = gl;
}
+ sun_range[1] = count;
+ point_range[0] = count;
+ for (auto v : w.view<Transform, Point_Light>()) {
+ GPU_Light gl;
+ Transform& t = v.get<Transform>();
+ Point_Light& l = v.get<Point_Light>();
+ if (count >= max_lights) {
+ print_war("Over light limit.\n");
+ goto cancel;
+ }
+ gl.brightness = l.brightness;
+ gl.colour = l.colour;
+ gl.pos = v3f(
+ t.mat.m[3][0],
+ t.mat.m[3][1],
+ t.mat.m[3][2]
+ );
+ gl.caster_id = -1;
+ gl.range = l.range;
+ ldst[count++] = gl;
+ }
+ point_range[1] = count;
+cancel:
light_count = count;
caster_count = ccount;
}
diff --git a/lighting.hpp b/lighting.hpp
index 0d331d7..7c57bab 100644
--- a/lighting.hpp
+++ b/lighting.hpp
@@ -19,14 +19,12 @@ struct Lighting {
Staged_Buffer casters;
Texture_Id shadows;
Texture_Id shadow_slices[max_shadows];
- Texture_Id ss_shadows[2];
- Texture_Id ss_shadow_slices[2][max_shadows];
Sampler_Id shadow_sampler;
Camera_Id cameras[max_shadows];
+ int sun_range[2];
+ int point_range[2];
int light_count, caster_count;
- void init(Device* dev, int w, int h);
- void destroy_ss(Device* dev);
- void recreate(Device* dev, int w, int h);
+ void init(Device* dev);
void destroy(Device* dev, Renderer& r);
void update(
Device* dev,
@@ -54,4 +52,8 @@ struct Sun_Light : Light {
v3f dir;
};
+struct Point_Light : Light {
+ float range;
+};
+
#endif
diff --git a/model.cpp b/model.cpp
index 5806655..ed6e968 100644
--- a/model.cpp
+++ b/model.cpp
@@ -32,20 +32,26 @@ void Material::use(
Sampler_Id sampler,
Shader& shader
) {
- auto bind = [&shader, &pb, sampler](
+ int opt = 0;
+ auto bind = [&shader, &pb, &opt, sampler](
const char* name,
+ const char* optname,
Texture_Id t
) {
int loc = shader.descriptor_binding(name);
if (loc >= 0) {
- pb.texture(loc, t, sampler);
+ if (t) {
+ pb.texture(loc, t, sampler);
+ opt |= shader.opt_mask(shader_type_fragment, optname);
+ }
}
};
- bind("albedo", tex.albedo);
- bind("ao", tex.ao);
- bind("metal", tex.metal);
- bind("rough", tex.rough);
- bind("normal", tex.normal);
+ bind("albedo", "albedomap", tex.albedo);
+ bind("ao", "aomap", tex.ao);
+ bind("metal", "metalmap", tex.metal);
+ bind("rough", "roughmap", tex.rough);
+ bind("normal", "normalmap", tex.normal);
+ pb.option(shader_type_fragment, opt);
}
void Model_Loader::init(Device* device, Asset_Arena* shader_arena) {
@@ -214,10 +220,8 @@ void Model::update_transforms() {
}
void Material_Loader::init(
- Asset_Arena* texture_arena,
- Texture_Id dt
+ Asset_Arena* texture_arena
) {
- default_tex = dt;
textures = texture_arena;
}
@@ -235,11 +239,11 @@ Asset* Material_Loader::load(
return r;
};
auto read_tex = [&](int len) {
- if (!len) return default_tex;
+ if (!len) return Texture_Id(0);
const char* name = read_name(len);
auto t = (Texture*)textures->load(name);
if (!t)
- return default_tex;
+ return Texture_Id(0);
return t->id;
};
(void)filename;
@@ -308,6 +312,7 @@ void Model_Instance::update() {
);
bound.encompass(bounds[i]);
}
+ centre = bound.min + bound.max * 0.5f;
}
void Model_Instance::update_cbuffers(Device* dev) {
@@ -384,11 +389,11 @@ void Model_Instance::render(
res.vp
);
} else {
- pb.depth(true, false, Depth_Mode::equal);
+ pb.depth(true, true, Depth_Mode::less);
pb.shader(mesh.shader);
pb.sbuffer(mesh.light_binding, lighting->lights.gpuonly);
pb.sbuffer(mesh.casters_binding, lighting->casters.gpuonly);
- pb.texture(mesh.shadowmaps_binding, res.shadows, res.sampler);
+ pb.texture(mesh.shadowmaps_binding, lighting->shadows, lighting->shadow_sampler);
mesh.material->use(pb, res.sampler, dev->get_shader(mesh.shader));
pb.cbuffer(
mesh.mat_binding,
diff --git a/model.hpp b/model.hpp
index 022ec27..3ededa7 100644
--- a/model.hpp
+++ b/model.hpp
@@ -85,7 +85,7 @@ struct Model_Loader : public Asset_Loader {
struct Material_Loader : public Asset_Loader {
Asset_Arena* textures;
Texture_Id default_tex;
- void init(Asset_Arena* texture_arena, Texture_Id dt);
+ void init(Asset_Arena* texture_arena);
Asset* load(
Arena* a,
Arena* s,
@@ -97,7 +97,6 @@ struct Material_Loader : public Asset_Loader {
struct Model_Resources {
Texture_Id env_cubemap;
- Texture_Id shadows;
Sampler_Id sampler;
Buffer_Id vp;
Buffer_Id globals;
@@ -111,6 +110,7 @@ struct Model_Instance {
Model* m;
AABB* bounds;
AABB bound;
+ v3f centre;
void init(Device* dev, Heap* h, Model* model);
void destroy(Device* dev, Heap* h);
diff --git a/pipeline.cpp b/pipeline.cpp
index 0636a1c..4d34ebd 100644
--- a/pipeline.cpp
+++ b/pipeline.cpp
@@ -23,6 +23,7 @@ Pipeline_Builder& Pipeline_Builder::rp_target(Texture_Id id, Colour clear) {
Render_Pass::Target t{
.id = id,
.fmt = texture.fmt,
+ .samples = texture.samples,
.mode = Clear_Mode::clear,
.clear = { .colour = clear }
};
@@ -37,6 +38,7 @@ Pipeline_Builder& Pipeline_Builder::rp_target(Texture_Id id, Clear_Mode clear) {
Render_Pass::Target t{
.id = id,
.fmt = texture.fmt,
+ .samples = texture.samples,
.mode = clear,
.clear = { .depth = 0.0f }
};
@@ -51,6 +53,7 @@ Pipeline_Builder& Pipeline_Builder::rp_depth_target(Texture_Id id, float clear)
Render_Pass::Target t{
.id = id,
.fmt = texture.fmt,
+ .samples = texture.samples,
.mode = Clear_Mode::clear,
.clear = { .depth = clear }
};
@@ -63,6 +66,7 @@ Pipeline_Builder& Pipeline_Builder::rp_depth_target(Texture_Id id, Clear_Mode mo
Render_Pass::Target t{
.id = id,
.fmt = texture.fmt,
+ .samples = texture.samples,
.mode = mode,
.clear = { .depth = 0.0f }
};
@@ -73,7 +77,7 @@ Pipeline_Builder& Pipeline_Builder::rp_depth_target(Texture_Id id, Clear_Mode mo
void Pipeline_Builder::validate_rp() {
int i, c = pass->colour_count;
- int w, h;
+ int w, h, s;
assert(c || pass->depth.id);
if (c) {
Texture& tex = dev->get_texture(pass->colours[0].id);
@@ -81,7 +85,8 @@ void Pipeline_Builder::validate_rp() {
assert(pass->colours[0].fmt == tex.fmt);
w = tex.w;
h = tex.h;
- assert(w && h);
+ s = tex.samples;
+ assert(w && h && s);
}
for (i = 1; i < c; i++) {
Texture& tex = dev->get_texture(pass->colours[i].id);
@@ -89,6 +94,7 @@ void Pipeline_Builder::validate_rp() {
assert(pass->colours[i].fmt == tex.fmt);
assert(tex.w == w);
assert(tex.h == h);
+ assert(tex.samples == s);
}
if (pass->depth.id) {
Texture& d = dev->get_texture(pass->depth.id);
@@ -101,6 +107,7 @@ void Pipeline_Builder::validate_rp() {
if (c) {
assert(d.w == w);
assert(d.h == h);
+ assert(d.samples == s);
}
}
}
@@ -247,6 +254,14 @@ Pipeline_Builder& Pipeline_Builder::shader(Shader_Id s) {
return *this;
}
+Pipeline_Builder& Pipeline_Builder::option(
+ Shader_Type type,
+ int mask
+) {
+ pip->shader_masks[type] = mask;
+ return *this;
+}
+
Pipeline_Builder& Pipeline_Builder::texture(
int binding,
Texture_Id t,
@@ -314,6 +329,7 @@ Pipeline& Pipeline_Builder::build() {
}
void Pipeline::hash() {
+ int i;
#define h(n, v) \
n = fnv1a64_2(n, (uint8_t*)&v, sizeof v)
pipeline_hash = fnv1a64(0, 0);
@@ -340,8 +356,10 @@ void Pipeline::hash() {
h(pipeline_hash, blend_src_alpha);
h(pipeline_hash, blend_dst_alpha);
h(pipeline_hash, cull_mode);
+ for (i = 0; i < shader_type_count; i++)
+ h(pipeline_hash, shader_masks[i]);
{
- int i, e = descriptor_count;
+ int e = descriptor_count;
descriptor_resource_hash = fnv1a64(0, 0);
for (i = 0; i < e; i++) {
Descriptor* d = &descriptors[i];
diff --git a/qstd/memory.c b/qstd/memory.c
index 87618f9..6db9ad9 100644
--- a/qstd/memory.c
+++ b/qstd/memory.c
@@ -86,7 +86,7 @@ void arena_push(Arena* a) {
void arena_pop(Arena* a) {
assert(a->last_push);
- a->ptr -= a->last_push;
+ a->ptr = a->last_push;
a->last_push = *(int*)&a->buf[a->ptr];
}
diff --git a/renderer.cpp b/renderer.cpp
index ffc0a3c..6208d3c 100644
--- a/renderer.cpp
+++ b/renderer.cpp
@@ -5,27 +5,19 @@ extern "C" {
#include "memory.h"
}
-#include <string.h>
+#include <algorithm>
struct VP_Cbuffer {
m4f view_projection;
};
-struct TS_Cbuffer {
- m4f inv_view;
- m4f inv_proj;
- m4f prev_vp;
-};
-
-struct TS_Caster_Config {
- int index;
- char pad[60];
-};
-
struct Global_Cbuffer {
v3f camera_pos;
int light_count;
int frame;
+ int pad;
+ int sun_irange[2];
+ int point_irange[2];
};
void init_drawlist(
@@ -49,22 +41,7 @@ void init_drawlist(
);
}
-void Renderer::make_ts_sampler(Device* d) {
- Sampler_State s{};
- s.min = Filter_Mode::point;
- s.mag = Filter_Mode::point;
- s.mip = Filter_Mode::point;
- s.address_u = Address_Mode::border;
- s.address_v = Address_Mode::border;
- s.border[0] = 0.0f;
- ts_sampler = d->create_sampler("temporal shadow sampler", s);
-}
-
-void Renderer::init(
- Arena* arena,
- Device* d,
- Asset_Arena& assets
-) {
+void Renderer::init(Arena* arena, Device* d) {
int i;
auto id = [&](int did, int cap) {
init_drawlist(&drawlists[did], d, arena, cap);
@@ -80,37 +57,6 @@ void Renderer::init(
sizeof(Global_Cbuffer),
Buffer_Flags::constant_buffer
);
- ts_config.init(
- d,
- "Temporal shadow cbuffer",
- sizeof(TS_Cbuffer),
- Buffer_Flags::constant_buffer
- );
- ts_config2.init(
- d,
- "Temporal shadow casters",
- sizeof(TS_Caster_Config) * Lighting::max_shadows,
- Buffer_Flags::constant_buffer
- );
- quad.init(d);
- ts_shader = (Shader*)assets.load("ts.csh");
- ts_shadowmap_binding = ts_shader->descriptor_binding("shadowmaps");
- ts_depthmap_binding = ts_shader->descriptor_binding("depthmap");
- ts_prev_binding = ts_shader->descriptor_binding("previous");
- ts_vert_binding = ts_shader->binding_index("verts");
- ts_config_binding = ts_shader->descriptor_binding("config");
- ts_caster_config_binding = ts_shader->descriptor_binding("caster_config");
- ts_casters_binding = ts_shader->descriptor_binding("casters");
- ts_globals_binding = ts_shader->descriptor_binding("globals");
- assert(ts_shadowmap_binding >= 0);
- assert(ts_depthmap_binding >= 0);
- assert(ts_prev_binding >= 0);
- assert(ts_vert_binding >= 0);
- assert(ts_config_binding >= 0);
- assert(ts_caster_config_binding >= 0);
- assert(ts_casters_binding >= 0);
- assert(ts_globals_binding >= 0);
- make_ts_sampler(d);
frame = 0;
}
@@ -119,10 +65,6 @@ void Renderer::destroy(Device* d) {
for (i = 0; i < drawlist_count; i++)
drawlists[i].vp.destroy(d);
globals.destroy(d);
- ts_config.destroy(d);
- ts_config2.destroy(d);
- quad.destroy(d);
- d->destroy_sampler(ts_sampler);
}
void Renderer::set_camera(Camera_Id cam, int drawlist) {
@@ -144,7 +86,6 @@ void Drawlist::render(
vpc->view_projection = cam.get_proj() * cam.get_view();
vp.unmap(dev);
vp.update(dev->get_ctx());
- res.shadows = l->ss_shadows[r.frame & 1];
res.sampler = r.clamped_linear;
res.env_cubemap = r.env_cubemap;
res.vp = vp.gpuonly;
@@ -155,6 +96,21 @@ void Drawlist::render(
}
}
+void Drawlist::sort(const Renderer& r) {
+ const Camera& cam = r.get_camera(camera);
+ v3f far = cam.position + cam.far * cam.forward;
+ /* ideally want to sort the meshes within each model as
+ * well but as long as the models are small it wont matter
+ * too much... */
+ std::sort(
+ models,
+ models + count,
+ [&far](const Model_Instance* a, const Model_Instance* b) {
+ return v3f::dot(a->centre, far) < v3f::dot(b->centre, far);
+ }
+ );
+}
+
void Renderer::update_globals(
const Lighting* l,
Device* d,
@@ -166,74 +122,19 @@ void Renderer::update_globals(
cb->camera_pos = cp;
cb->frame = frame;
cb->light_count = l->light_count;
+ cb->sun_irange[0] = l->sun_range[0];
+ cb->sun_irange[1] = l->sun_range[1];
+ cb->point_irange[0] = l->point_range[0];
+ cb->point_irange[1] = l->point_range[1];
globals.unmap(d);
globals.update(ctx);
}
-void Renderer::temporal_shadows(
- Device* dev,
- Context& ctx,
- const Lighting* l,
- Pipeline_Builder& pb
-) {
- int i, c = l->caster_count;
- Camera& cam = get_camera(drawlists[FORWARD].camera);
- TS_Cbuffer* cbuf = (TS_Cbuffer*)ts_config.map(dev);
- TS_Caster_Config* casters = (TS_Caster_Config*)ts_config.map(dev);
- for (i = 0; i < c; i++) {
- casters[i].index = i;
- }
- cbuf->inv_view = cam.get_view().inverse();
- cbuf->inv_proj = cam.get_proj().inverse();
- ts_config.unmap(dev);
- ts_config2.unmap(dev);
- ctx.debug_push("temporal shadows");
- ts_config.update(ctx);
- ts_config2.update(ctx);
- for (i = 0; i < c; i++) {
- int ind = frame & 1;
- auto& pass = pb
- .begin_rp()
- .rp_target(l->ss_shadow_slices[ind][i], Clear_Mode::discard)
- .build_rp();
- auto& pip = pb
- .begin()
- .shader(ts_shader->id)
- .vertex_format(ts_shader->vf)
- .texture(
- ts_shadowmap_binding,
- l->shadows,
- l->shadow_sampler)
- .texture(
- ts_prev_binding,
- l->ss_shadow_slices[!ind][i],
- ts_sampler)
- .texture(
- ts_depthmap_binding,
- dev->get_depth_target(),
- ts_sampler)
- .cbuffer(ts_config_binding, ts_config.gpuonly)
- .cbuffer(
- ts_caster_config_binding,
- ts_config2.gpuonly,
- i * sizeof(TS_Caster_Config),
- sizeof(TS_Caster_Config))
- .cbuffer(ts_globals_binding, globals.gpuonly)
- .sbuffer(ts_casters_binding, l->casters.gpuonly)
- .build();
- quad.render(
- ctx,
- pip,
- pass,
- ts_vert_binding
- );
- }
- ctx.debug_pop();
-}
-
void Renderer::render(
Device* dev,
- Arena* a, Texture_Id hdr_target,
+ Arena* a,
+ Texture_Id hdr_target,
+ Texture_Id depth_target,
const Lighting* l
) {
int i, j;
@@ -249,7 +150,7 @@ void Renderer::render(
Render_Pass& forward_pass = pb
.begin_rp()
.rp_target(hdr_target, Clear_Mode::restore)
- .rp_depth_target(dev->get_depth_target(), Clear_Mode::restore)
+ .rp_depth_target(depth_target, 1.0f)
.build_rp();
Render_Pass* shadow_passes[Lighting::max_shadows];
for (i = 0; i < Lighting::max_shadows; i++) {
@@ -259,6 +160,8 @@ void Renderer::render(
.build_rp();
}
+ drawlists[FORWARD].sort(*this);
+
ctx.debug_push("depth prepass");
drawlists[FORWARD].render(*this, dev, a, l, depth_prepass, 0);
ctx.debug_pop();
@@ -279,8 +182,6 @@ void Renderer::render(
}
ctx.debug_pop();
- temporal_shadows(dev, ctx, l, pb);
-
ctx.debug_push("forward");
drawlists[FORWARD].render(*this, dev, a, l, forward_pass, 0);
ctx.debug_pop();
@@ -337,54 +238,3 @@ void Renderer::setcam(int did, Camera_Id cam) {
assert(cam.index);
drawlists[did].camera = cam;
}
-
-void Fullscreen_Quad::init(Device* d) {
- float verts[] = {
- -1.0f, -1.0f, 0.0f, 0.0f,
- -1.0f, 3.0f, 0.0f, 2.0f,
- 3.0f, -1.0f, 2.0f, 0.0f
- };
- Buffer_Id stage;
- void* mem;
- stage = d->create_buffer(
- "sky vb stage",
- sizeof verts,
- Buffer_Flags::cpu_readwrite |
- Buffer_Flags::copy_src
- );
- mem = d->map_buffer(stage, 0, sizeof verts);
- memcpy(mem, verts, sizeof verts);
- d->unmap_buffer(stage);
- vb = d->create_buffer(
- "fullscreen quad",
- sizeof verts,
- Buffer_Flags::copy_dst |
- Buffer_Flags::vertex_buffer
- );
- Context& ctx = d->acquire();
- ctx.copy(vb, stage);
- d->submit(ctx);
- d->destroy_bufferi(stage);
-}
-
-void Fullscreen_Quad::destroy(Device* d) {
- d->destroy_buffer(vb);
-}
-
-void Fullscreen_Quad::render(
- Context& ctx,
- Pipeline& pip,
- Render_Pass& pass,
- int bind
-) {
- Vertex_Buffer_Binding vbb[] = {{
- .id = vb,
- .offset = 0,
- .target = bind
- }, {}};
- Draw draw{};
- draw.verts = vbb;
- draw.vertex_count = 3;
- draw.instance_count = 1;
- ctx.submit(draw, pip, pass);
-}
diff --git a/renderer.hpp b/renderer.hpp
index 46f5331..a76afa9 100644
--- a/renderer.hpp
+++ b/renderer.hpp
@@ -12,7 +12,6 @@ enum {
SHADOW_MAP_END = SHADOW_MAP_START + Lighting::max_shadows,
drawlist_count = SHADOW_MAP_END };
-struct Asset_Arena;
struct Model_Instance;
struct Renderer;
@@ -31,19 +30,7 @@ struct Drawlist {
Render_Pass& pass,
void (*overrider)(Pipeline_Builder&)
);
-};
-
-struct Fullscreen_Quad {
- Buffer_Id vb;
-
- void init(Device* d);
- void destroy(Device* d);
- void render(
- Context& ctx,
- Pipeline& pip,
- Render_Pass& pass,
- int bind
- );
+ void sort(const Renderer& r);
};
struct Renderer {
@@ -51,41 +38,22 @@ struct Renderer {
Hash_Map<Camera_Id, Camera, max_cameras> cameras;
Drawlist drawlists[drawlist_count];
Staged_Buffer globals;
- Fullscreen_Quad quad;
int camera_count;
int frame;
- Shader* ts_shader;
- int ts_shadowmap_binding;
- int ts_depthmap_binding;
- int ts_prev_binding;
- int ts_vert_binding;
- int ts_config_binding;
- int ts_caster_config_binding;
- int ts_casters_binding;
- int ts_globals_binding;
- Sampler_Id ts_sampler;
- Staged_Buffer ts_config, ts_config2;
-
Sampler_Id clamped_linear;
Texture_Id env_cubemap;
- void init(Arena* arena, Device* d, Asset_Arena& assets);
+ void init(Arena* arena, Device* d);
void destroy(Device* d);
void set_camera(Camera_Id cam, int drawlist);
- void make_ts_sampler(Device* d);
void render(
Device* dev,
Arena* a,
Texture_Id hdr_target,
+ Texture_Id depth_target,
const Lighting* l
);
- void temporal_shadows(
- Device* dev,
- Context& ctx,
- const Lighting* l,
- Pipeline_Builder& pb
- );
void add_model(int drawlist, Model_Instance* m);
void rem_model(int drawlist, Model_Instance* m);
diff --git a/sc/sc.cpp b/sc/sc.cpp
index 9232e10..69a7377 100644
--- a/sc/sc.cpp
+++ b/sc/sc.cpp
@@ -168,14 +168,16 @@ struct Desc {
std::pair<int, int> size() const {
switch (type) {
case svariable_type_float:
- return { 4, 4 };
case svariable_type_int:
return { 4, 4 };
case svariable_type_vec2:
+ case svariable_type_ivec2:
return { 8, 8 };
case svariable_type_vec3:
+ case svariable_type_ivec3:
return { 12, 16 };
case svariable_type_vec4:
+ case svariable_type_ivec4:
return { 16, 16 };
case svariable_type_mat2:
return { 16, 16 };
@@ -223,6 +225,10 @@ struct Desc {
int stage;
std::string strct;
};
+ struct Option {
+ int stage;
+ int mask;
+ };
int type;
std::vector<Binding> bindings;
std::vector<Variable> trgts;
@@ -231,8 +237,10 @@ struct Desc {
std::unordered_map<std::string, Texture> textures;
std::unordered_map<std::string, CBuffer> cbuffers;
std::unordered_map<std::string, SBuffer> sbuffers;
+ std::unordered_map<std::string, Option> options;
std::vector<Descriptor> descriptors;
std::string entrypoints[shader_type_count];
+ int copts[shader_type_count];
void read_var(Variable& d, cfg_Object* desc) {
const char* sname = find_string_default(desc, "name", 0);
if (!sname) {
@@ -395,10 +403,40 @@ struct Desc {
buf.stage |= 1 << stage_from_string(sstage);
}
+ void read_opt(cfg_Object* desc) {
+ const char* sname = find_string_default(desc, "name", 0);
+ if (!sname) {
+ print_err("%s must have a name.\n", desc->name);
+ pbreak(1001);
+ }
+ const char* sstage = find_string_default(desc, "stage", 0);
+ if (!sstage) {
+ print_err("%s must define a stage.\n", sname);
+ pbreak(1002);
+ }
+ std::string n(sname);
+ if (n.size() > 23) {
+ print_err("Option name %s is too long (max 23 chars).\n", sname);
+ pbreak(1003);
+ }
+ if (!options.contains(n)) {
+ Option& o = options[n];
+ o.mask = 0;
+ o.stage = 0;
+ }
+ int stage = stage_from_string(sstage);
+ Option& opt = options[n];
+ opt.stage |= 1 << stage;
+ opt.mask = copts[stage];
+ copts[stage] <<= 1;
+ }
+
void build(cfg_Object* desc) {
int i;
Binding* cur_binding = 0;
type = get_program_type(desc);
+ for (i = 0; i < shader_type_count; i++)
+ copts[i] = 1;
if (type != sprogram_type_graphics) {
assert(0); /* todo */
return;
@@ -448,6 +486,8 @@ struct Desc {
} else if (!strcmp(desc->name, "struct")) {
desc = read_struct(desc);
continue;
+ } else if (!strcmp(desc->name, "option")) {
+ read_opt(desc);
}
desc = desc->next;
}
@@ -626,22 +666,35 @@ std::vector<uint32_t> compile_shader(
const char* src,
const char* define,
int stage,
+ int opt,
EShLanguage lang
) {
std::string vars = d.build_vs();
- const char* srcs[] = {
+ std::vector<const char*> srcs = {
glsl_version_s, "\n",
"#define ", define, "\n",
builtin_src,
- presrc,
- src
+ presrc
};
- const char* src_names[] = {
+ std::vector<const char*> src_names = {
sname, sname,
sname, sname, sname,
- sname, sname, sname
+ sname, sname
};
- static_assert(sizeof srcs == sizeof src_names);
+ for (const auto& p : d.options) {
+ const auto& o = p.second;
+ std::string def = "#define OPT_" + p.first + " ";
+ if (opt & o.mask)
+ def += "1\n";
+ else
+ def += "0\n";
+ /* memory leak lol */
+ srcs.push_back(strdup(def.c_str()));
+ src_names.push_back(sname);
+ }
+ srcs.push_back(src);
+ src_names.push_back(sname);
+ assert(src_names.size() == srcs.size());
glslang::TShader shader(lang);
glslang::TProgram program;
glslang::TIntermediate* ir;
@@ -661,10 +714,10 @@ std::vector<uint32_t> compile_shader(
#endif
EShMessages msg = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
shader.setStringsWithLengthsAndNames(
- srcs,
+ &srcs[0],
0,
- src_names,
- sizeof srcs / sizeof *srcs
+ &src_names[0],
+ src_names.size()
);
shader.setEnvClient(glslang::EShClientVulkan, client_version);
shader.setEnvTarget(glslang::EShTargetSpv, target_version);
@@ -734,10 +787,23 @@ void configure(
}
}
+struct H_Variant {
+ int o = -1, s;
+ int mask;
+ int pad = 0;
+};
+struct H_Option {
+ char name[24] = { 0 };
+ int mask;
+ int stage;
+};
+static_assert(sizeof(H_Variant) == 16);
+using Variant_Map = std::unordered_map<int, std::vector<uint32_t>>;
+
void compile_shaders(
const char* sname,
const char* fname,
- std::vector<uint32_t>* spv,
+ Variant_Map* spv,
const char* src,
Desc& d
) {
@@ -745,19 +811,40 @@ void compile_shaders(
EShLanguage lang;
int i;
for (i = 0; i < shader_type_count; i++) {
+ int sm = 1 << i;
if (!d.entrypoints[i].empty()) {
std::string ps;
+ int opt = 0, j;
configure(d, i, define, lang, ps);
- spv[i] = compile_shader(
- d,
- sname,
- fname,
- ps.c_str(),
- src,
- define,
- i,
- lang
- );
+ for (const auto& p : d.options) {
+ if (~p.second.stage & sm) continue;
+ opt |= p.second.mask;
+ }
+ for (j = 0; j <= opt; j++) {
+ spv[i][j] = compile_shader(
+ d,
+ sname,
+ fname,
+ ps.c_str(),
+ src,
+ define,
+ i,
+ j,
+ lang
+ );
+ }
+ if (!opt)
+ spv[i][0] = compile_shader(
+ d,
+ sname,
+ fname,
+ ps.c_str(),
+ src,
+ define,
+ i,
+ 0,
+ lang
+ );
}
}
}
@@ -765,10 +852,14 @@ void compile_shaders(
void write_csh(
const char* fname,
const Desc& d,
- const std::vector<uint32_t>* stages
+ Variant_Map* stages
) {
- int hsize = 20, i, coff;
+ int hsize = 24, i, coff;
FILE* f = fopen(fname, "wb");
+ H_Variant* variants[shader_type_count];
+ H_Option* hopts = 0;
+ int vc[shader_type_count];
+ std::vector<const std::vector<uint32_t>*> order;
if (!f) {
print_err("Failed to open %s\n", fname);
pbreak(500);
@@ -779,6 +870,7 @@ void write_csh(
c = d.bindings.size(); fwrite(&c, 4, 1, f);
c = d.trgts.size(); fwrite(&c, 4, 1, f);
c = d.descriptors.size(); fwrite(&c, 4, 1, f);
+ c = d.options.size(); fwrite(&c, 4, 1, f);
for (const auto& b : d.bindings) {
char buf[24];
int count = b.attrs.size();
@@ -814,36 +906,79 @@ void write_csh(
fwrite(&d.stage, 4, 1, f);
hsize += 32;
}
- hsize += shader_type_count * 32;
- for (i = 0, coff = 0; i < shader_type_count; i++) {
- int o = 0;
- char buf[24];
- memset(buf, 0, sizeof buf);
- if (d.entrypoints[i].empty()) {
- fwrite(&o, 4, 1, f);
- fwrite(&o, 4, 1, f);
- } else {
- int size = stages[i].size() * sizeof(uint32_t);
- strcpy(buf, d.entrypoints[i].c_str());
- o = hsize + coff;
- fwrite(&o, 4, 1, f);
- fwrite(&size, 4, 1, f);
- coff += size;
+ if (d.options.size())
+ hopts = new H_Option[d.options.size()];
+ for (const auto& p : d.options) {
+ const auto& name = p.first;
+ const auto& o = p.second;
+ int count = d.options.size();
+ int j, bucket = (int)(
+ hash_string(name.c_str()) %
+ count
+ );
+ for (j = 0; j < count; j++) {
+ auto& ho = hopts[j];
+ if (!ho.name[0]) {
+ strcpy(ho.name, name.c_str());
+ ho.mask = o.mask;
+ ho.stage = o.stage;
+ goto oklmao;
+ }
+ bucket = (bucket + 1) % count;
}
- fwrite(buf, 1, sizeof buf, f);
+ assert(0);
+ oklmao:
+ hsize += 32;
}
- for (i = 0; i < shader_type_count; i++)
- if (!d.entrypoints[i].empty()) {
- auto& stage = stages[i];
- fwrite(&stage[0], sizeof(uint32_t), stage.size(), f);
+ fwrite(hopts, sizeof *hopts, d.options.size(), f);
+ delete[] hopts;
+ for (i = 0; i < shader_type_count; i++) {
+ vc[i] = stages[i].size();
+ hsize += vc[i] * 16 + 4;
+ variants[i] = new H_Variant[vc[i]];
+ }
+ for (i = 0, coff = 0; i < shader_type_count; i++) {
+ fwrite(&vc[i], 4, 1, f);
+ for (const auto& p : stages[i]) {
+ int mask = p.first, j;
+ int bucket = (int)(
+ fnv1a64((uint8_t*)&mask, sizeof mask) %
+ vc[i]
+ );
+ for (j = 0; j < vc[i]; j++) {
+ H_Variant& v = variants[i][bucket];
+ if (v.o == -1) {
+ auto& arr = p.second;
+ v.o = coff + hsize;
+ v.s = arr.size() * sizeof(uint32_t);
+ v.mask = mask;
+ coff += v.s;
+ order.push_back(&arr);
+ goto done;
+ }
+ bucket = (bucket + 1) % vc[i];
+ }
+ assert(0);
+ done:;
}
+ fwrite(variants[i], sizeof(H_Variant), vc[i], f);
+ delete[] variants[i];
+ }
+ for (auto bytecode : order) {
+ fwrite(
+ &(*bytecode)[0],
+ sizeof(uint32_t),
+ bytecode->size(),
+ f
+ );
+ }
}
int main(int argc, const char** argv) {
char* src;
size_t src_size;
std::string desc_src;
- std::vector<uint32_t> spv[shader_type_count];
+ Variant_Map spv[shader_type_count];
cfg_Object* cdesc;
void* dp_mem;
Desc desc;
diff --git a/sc/sh_enums.h b/sc/sh_enums.h
index e9a33b8..6cf9495 100644
--- a/sc/sh_enums.h
+++ b/sc/sh_enums.h
@@ -28,6 +28,9 @@ sprogram_type_xmacro()
x(vec2) \
x(vec3) \
x(vec4) \
+ x(ivec2) \
+ x(ivec3) \
+ x(ivec4) \
x(mat2) \
x(mat3) \
x(mat4)
diff --git a/sc/sh_helpers.h b/sc/sh_helpers.h
index fa503dc..1b81bd6 100644
--- a/sc/sh_helpers.h
+++ b/sc/sh_helpers.h
@@ -5,6 +5,9 @@ int svariable_type_size(SVariable_Type type) {
case svariable_type_vec2: return 8;
case svariable_type_vec3: return 12;
case svariable_type_vec4: return 16;
+ case svariable_type_ivec2: return 8;
+ case svariable_type_ivec3: return 12;
+ case svariable_type_ivec4: return 16;
case svariable_type_mat2: return 16;
case svariable_type_mat3: return 36;
case svariable_type_mat4: return 64;
diff --git a/todo.txt b/todo.txt
index 5212343..04e8bd7 100644
--- a/todo.txt
+++ b/todo.txt
@@ -19,8 +19,8 @@ todo list
- [x] render a sky box
- [x] PBR + IBL
- [x] Tonemapping
- - [ ] shadows
- - [ ] MSAA
+ - [x] shadows
+ - [x] MSAA
- [ ] GI
- [ ] clustering
- [ ] bloom
diff --git a/video.cpp b/video.cpp
index 28df58b..b9cd098 100644
--- a/video.cpp
+++ b/video.cpp
@@ -430,6 +430,12 @@ enum {
context_state_init = 1 << 1
};
+
+struct Shader_Module {
+ int mask;
+ VkShaderModule mod;
+};
+
struct Shader_Vk : public Shader, public Late_Terminated {
struct Attribute {
char name[28];
@@ -464,23 +470,31 @@ struct Shader_Vk : public Shader, public Late_Terminated {
int stage;
};
+ struct Option {
+ char name[24];
+ int mask;
+ int stage;
+ };
+
SProgram_Type type;
- VkShaderModule modules[shader_type_count];
- char entrypoints[shader_type_count][24];
Vertex_Format vfd;
Desc* descs;
- int desc_count;
+ Shader_Module* modules[shader_type_count];
+ Option* options;
+ int desc_count, opt_count;
+ int module_count[shader_type_count];
- bool init(Device_Vk* dev, Pack_File* f);
- bool init_module(
+ bool init(Device_Vk* dev, Arena* a, Pack_File* f);
+ VkShaderModule make_module(
Device_Vk* dev,
- int stage,
char* buf,
int size
);
void destroy(Device_Vk* dev) override;
int find_descriptor(const char* name);
+ int find_module(Shader_Type type, int mask);
+ int find_opt(Shader_Type, const char* name);
static VkShaderStageFlagBits stage(Shader_Type type) {
switch (type) {
@@ -561,7 +575,8 @@ struct Texture_Vk : public Texture, public Late_Terminated {
int array_size,
int start_mip,
int start_array,
- bool alias
+ bool alias,
+ int samples
);
void destroy(Device_Vk*) override;
void set_name(Device_Vk* dev, const char* name);
@@ -732,7 +747,8 @@ struct Pipeline_Vk {
Arena& scope,
Device_Vk* dev,
VkGraphicsPipelineCreateInfo& info,
- const Pipeline& desc
+ const Pipeline& desc,
+ const Render_Pass& rpo
);
void init_depthstencil(
Arena& scope,
@@ -934,6 +950,7 @@ struct Device_Vk : public Device {
VkPhysicalDevice phys_dev;
VkSurfaceKHR surf;
uint32_t backbuffer_index;
+ VkSampleCountFlagBits max_samples;
Texture_Id backbuffer_id;
Swap_Cap swap_cap;
VkPhysicalDeviceMemoryProperties mem_props;
@@ -1021,6 +1038,9 @@ struct Device_Vk : public Device {
void create_terminators();
void create_depth(int w, int h);
+ VkSampleCountFlagBits get_max_samples();
+ VkSampleCountFlagBits get_samples(int);
+
int find_memory_type(
uint32_t filter,
VkMemoryPropertyFlags flags
@@ -1114,6 +1134,37 @@ void Device_Vk::init_validation() {
#endif
+VkSampleCountFlagBits Device_Vk::get_max_samples() {
+ VkPhysicalDeviceProperties p;
+ VkSampleCountFlagBits
+ i = VK_SAMPLE_COUNT_64_BIT,
+ e = VK_SAMPLE_COUNT_1_BIT;
+ VkSampleCountFlags c;
+ vkGetPhysicalDeviceProperties(phys_dev, &p);
+ c =
+ p.limits.framebufferColorSampleCounts &
+ p.limits.framebufferDepthSampleCounts;
+ for (; i >= e; i = (VkSampleCountFlagBits)(i >> 1))
+ if (c & i) return i;
+ return VK_SAMPLE_COUNT_1_BIT;
+}
+
+VkSampleCountFlagBits Device_Vk::get_samples(
+ int c
+) {
+ VkSampleCountFlagBits b = VK_SAMPLE_COUNT_1_BIT;
+ switch (c) {
+ case 1: b = VK_SAMPLE_COUNT_1_BIT; break;
+ case 2: b = VK_SAMPLE_COUNT_2_BIT; break;
+ case 4: b = VK_SAMPLE_COUNT_4_BIT; break;
+ case 8: b = VK_SAMPLE_COUNT_8_BIT; break;
+ case 16: b = VK_SAMPLE_COUNT_16_BIT; break;
+ case 32: b = VK_SAMPLE_COUNT_32_BIT; break;
+ case 64: b = VK_SAMPLE_COUNT_64_BIT; break;
+ default: break;
+ }
+ return std::min(max_samples, b);
+}
bool Device_Vk::has_validation() {
unsigned count, i;
@@ -1352,6 +1403,7 @@ void Device_Vk::init_internal() {
#endif
surf = app_create_vk_surface(app, inst);
create_dev(&swap_cap);
+ max_samples = get_max_samples();
vrama.init(this);
gladLoaderLoadVulkan(inst, phys_dev, dev);
vkGetDeviceQueue(dev, (uint32_t)queue_index, 0, &queue);
@@ -1386,7 +1438,7 @@ void Device_Vk::create_depth(int w, int h) {
destroy_texture(depth);
depth = create_texture(
"default depth",
- texture_format_d32,
+ texture_format_d24s8,
Texture_Flags::sampleable | Texture_Flags::depth_stencil_target,
w,
h,
@@ -1642,7 +1694,7 @@ void Renderpass_Vk::init(
auto& colour = rp.colours[i];
auto& ad = ads[index];
ad.format = get_vk_format(colour.fmt);
- ad.samples = VK_SAMPLE_COUNT_1_BIT;
+ ad.samples = dev->get_samples(colour.samples);
ad.loadOp = load_op_from_mode(colour.mode);
ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@@ -1659,9 +1711,10 @@ void Renderpass_Vk::init(
if (has_depth) {
int i = count++;
auto& ad = ads[i];
- ad.format = get_vk_format(dev->get_texture(rp.depth.id).fmt);
- ad.samples = VK_SAMPLE_COUNT_1_BIT;
- ad.loadOp = load_op_from_mode(rp.depth.mode);
+ auto& depth = rp.depth;
+ ad.format = get_vk_format(dev->get_texture(depth.id).fmt);
+ ad.samples = dev->get_samples(depth.samples);
+ ad.loadOp = load_op_from_mode(depth.mode);
ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ad.stencilLoadOp = ad.loadOp;
ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -1887,7 +1940,8 @@ Texture_Id Swapchain::create_image(
1,
0,
0,
- true
+ true,
+ 1
);
return id;
}
@@ -2016,6 +2070,8 @@ void Device::present() {
VkSubmitInfo si{};
VkPipelineStageFlags stage =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ heap_defrag(dev->heap);
+ // ^ this makes it >4x the speed
ctx->check_end_rp();
ctx->transition(
dev->get_backbuffer(),
@@ -2252,6 +2308,71 @@ void Context::copy(Texture_Id dst, Buffer_Id src) {
);
}
+void Context::copy(
+ Texture_Id dst,
+ Buffer_Id src,
+ int mip,
+ int x,
+ int y,
+ int w,
+ int h
+) {
+ Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
+ Texture_Vk& a = *(Texture_Vk*)&dev->get_texture(dst);
+ Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(src);
+ VkBufferImageCopy c{};
+ transition(dst, Resource_State::copy_dst);
+ c.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ c.imageSubresource.layerCount = 1;
+ c.imageSubresource.mipLevel = mip;
+ c.imageExtent.width = w;
+ c.imageExtent.height = h;
+ c.imageExtent.depth = 1;
+ c.imageOffset.x = x;
+ c.imageOffset.y = y;
+ ctx->check_end_rp();
+ vkCmdCopyBufferToImage(
+ ctx->cb,
+ b.buf,
+ a.image,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &c
+ );
+}
+
+void Context::resolve(Texture_Id dst, Texture_Id src) {
+ Context_Vk* ctx = (Context_Vk*)this;
+ Device_Vk* dev = ctx->dev;
+ Texture_Vk& d = *(Texture_Vk*)&dev->get_texture(dst);
+ Texture_Vk& s = *(Texture_Vk*)&dev->get_texture(src);
+ VkImageResolve r{};
+ r.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ r.srcSubresource.layerCount = 1;
+ r.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ r.dstSubresource.layerCount = 1;
+ r.extent.width = d.w;
+ r.extent.height = d.h;
+ r.extent.depth = 1;
+ assert(d.w == s.w);
+ assert(d.h == s.h);
+ assert(d.d == 1 && s.d == 1);
+ assert(d.samples == 1 && s.samples > 1);
+ ctx->check_end_rp();
+ transition(src, Resource_State::copy_src);
+ transition(dst, Resource_State::copy_dst);
+ vkCmdResolveImage(
+ ctx->cb,
+ s.image,
+ state_to_image_layout(s.state),
+ d.image,
+ state_to_image_layout(d.state),
+ 1,
+ &r
+ );
+}
+
void Context::transition(Texture_Id id, Resource_State state) {
Context_Vk* ctx = (Context_Vk*)this;
Device_Vk* dev = ctx->dev;
@@ -2400,6 +2521,14 @@ void Context::transition(Texture_Id id, Resource_State state) {
b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ } else if (
+ src_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL &&
+ dst_layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
+ ) {
+ b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ b.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dst_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
} else {
print_err("Bad resource transition.\n");
assert(0);
@@ -2698,12 +2827,24 @@ void Pipeline_Vk::init_stages(
zero(sis, sizeof *sis * count);
for (i = 0, count = 0; i < shader_type_count; i++) {
if (shader.modules[i]) {
+ int idx = shader.find_module(
+ (Shader_Type)i,
+ desc.shader_masks[i]
+ );
+ VkShaderModule mod;
+ if (idx < 0) {
+ mod = shader.modules[i][0].mod;
+ print_war("Shader variant not found; using the default >~<\n");
+ print(" ^ mask was 0x%x\n", desc.shader_masks[i]);
+ } else
+ mod = shader.modules[i][idx].mod;
+ assert(idx >= 0);
auto& si = sis[i];
si.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
si.flags = 0;
si.stage = Shader_Vk::stage((Shader_Type)i);
- si.module = shader.modules[i];
- si.pName = shader.entrypoints[i];
+ si.module = mod;
+ si.pName = "main";
count++;
}
}
@@ -2823,7 +2964,8 @@ void Pipeline_Vk::init_msaa(
Arena& scope,
Device_Vk* dev,
VkGraphicsPipelineCreateInfo& info,
- const Pipeline& desc
+ const Pipeline& desc,
+ const Render_Pass& rpo
) {
VkPipelineMultisampleStateCreateInfo& mi =
*(VkPipelineMultisampleStateCreateInfo*)arena_alloc(
@@ -2835,7 +2977,7 @@ void Pipeline_Vk::init_msaa(
zero(&mi, sizeof mi);
mi.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
mi.sampleShadingEnable = VK_FALSE;
- mi.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ mi.rasterizationSamples = dev->get_samples(rpo.get_samples());
info.pMultisampleState = &mi;
}
@@ -3030,7 +3172,7 @@ void Pipeline_Vk::init(Device_Vk* dev, const Pso_Key& key) {
init_input_assembly(scope, dev, info, desc);
init_viewport(scope, info, desc);
init_rasterisation(scope, dev, info, desc);
- init_msaa(scope, dev, info, desc);
+ init_msaa(scope, dev, info, desc, key.rpo.rpo);
init_depthstencil(scope, dev, info, desc);
init_blending(scope, dev, info, key.rpo.rpo, desc);
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
@@ -3282,9 +3424,8 @@ void Vertex_Format_Vk::optimise(const Vertex_Format_Vk* shadervf) {
}
}
-bool Shader_Vk::init_module(
+VkShaderModule Shader_Vk::make_module(
Device_Vk* dev,
- int stage,
char* buf,
int size
) {
@@ -3295,8 +3436,9 @@ bool Shader_Vk::init_module(
mi.codeSize = size;
mi.pCode = (uint32_t*)buf;
r = vkCreateShaderModule(dev->dev, &mi, &dev->ac, &m);
- modules[stage] = m;
- return r == VK_SUCCESS;
+ if (r == VK_SUCCESS)
+ return m;
+ return 0;
}
int Shader_Vk::Vertex_Format::find_binding(const char* name) {
@@ -3408,8 +3550,11 @@ void Shader_Vk::Vertex_Format::destroy(Device_Vk* dev) {
void Shader_Vk::destroy(Device_Vk* dev) {
int i;
for (i = 0; i < shader_type_count; i++)
- if (modules[i])
- vkDestroyShaderModule(dev->dev, modules[i], &dev->ac);
+ if (modules[i]) {
+ int j, e = module_count[i];
+ for (j = 0; j < e; j++)
+ vkDestroyShaderModule(dev->dev, modules[i][j].mod, &dev->ac);
+ }
vfd.destroy(dev);
heap_free(dev->heap, descs);
dev->destroy_vertex_format(vf);
@@ -3440,6 +3585,11 @@ int Shader::descriptor_binding(const char* name) {
return sh->descs[idx].slot;
}
+int Shader::opt_mask(Shader_Type type, const char* name) {
+ Shader_Vk* sh = (Shader_Vk*)this;
+ return sh->find_opt(type, name);
+}
+
int Shader::descriptor_stage(int slot) {
Shader_Vk* sh = (Shader_Vk*)this;
int i;
@@ -3560,7 +3710,8 @@ Texture_Id Device::create_texture(
int d,
int mip_count,
int array_size,
- Buffer_Id init
+ Buffer_Id init,
+ int samples
) {
VkImageCreateInfo ii{};
VkResult r;
@@ -3592,7 +3743,7 @@ Texture_Id Device::create_texture(
ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ii.usage = get_texture_usage(flags);
ii.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- ii.samples = VK_SAMPLE_COUNT_1_BIT;
+ ii.samples = dev->get_samples(samples);
ii.flags = image_flags;
r = vkCreateImage(dev->dev, &ii, &dev->ac, &image);
if (r != VK_SUCCESS) {
@@ -3650,7 +3801,8 @@ Texture_Id Device::create_texture(
array_size,
0,
0,
- false
+ false,
+ samples
);
if (init) {
Context& ctx = dev->acquire();
@@ -3713,7 +3865,8 @@ Texture_Id Device::alias_texture(
array_size,
start_mip,
start_array,
- true
+ true,
+ texture.samples
);
nt.set_name(dev, name);
return ntid;
@@ -3792,11 +3945,10 @@ Asset* Shader_Loader::load(
Shader_Vk* shader;
Shader_Id id;
(void)s;
- (void)a;
(void)filename;
id = dev->alloc_shader();
shader = (Shader_Vk*)&dev->get_shader(id);
- if (!shader->init(dev, f)) {
+ if (!shader->init(dev, a, f)) {
dev->shaders.remove(id);
return 0;
}
@@ -3822,7 +3974,46 @@ int Shader_Vk::find_descriptor(const char* name) {
return -1;
}
-bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
+int Shader_Vk::find_module(
+ Shader_Type type,
+ int mask
+) {
+ int i;
+ int count = module_count[type];
+ Shader_Module* arr = modules[type];
+ int bucket = (int)(
+ fnv1a64((uint8_t*)&mask, sizeof mask) %
+ count
+ );
+ for (i = 0; i < count; i++) {
+ Shader_Module& mod = arr[bucket];
+ if (mod.mask == mask)
+ return bucket;
+ bucket = (bucket + 1) % count;
+ }
+ return -1;
+}
+
+int Shader_Vk::find_opt(
+ Shader_Type type,
+ const char* name
+) {
+ int count = opt_count, i;
+ int bucket = (int)(
+ hash_string(name) %
+ count
+ );
+ int stage = 1 << type;
+ for (i = 0; i < count; i++) {
+ Option& o = options[bucket];
+ if (string_equal(name, o.name) && (o.stage & stage))
+ return o.mask;
+ bucket = (bucket + 1) % count;
+ }
+ return 0;
+}
+
+bool Shader_Vk::init(Device_Vk* dev, Arena* a, Pack_File* f) {
char magic[4];
int binding_count, target_count, i;
pack_read(f, magic, 4);
@@ -3836,6 +4027,7 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
pack_read(f, &binding_count, 4);
pack_read(f, &target_count, 4);
pack_read(f, &desc_count, 4);
+ pack_read(f, &opt_count, 4);
assert(binding_count);
vfd.binding_count = binding_count;
if (!vfd.init(dev, f))
@@ -3883,24 +4075,60 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {
desc_count * sizeof *descs
);
pack_read(f, descs, desc_count * sizeof *descs);
+ options = (Option*)arena_alloc(
+ a,
+ opt_count * sizeof *options
+ );
+ pack_read(f, options, opt_count * sizeof *options);
for (i = 0; i < shader_type_count; i++) {
- int o, s;
- pack_read(f, &o, 4);
- pack_read(f, &s, 4);
- if (o) {
- bool r;
- int before = pack_tell(f);
- char* buf = (char*)heap_alloc(dev->heap, s);
- pack_seek(f, o, seek_rel_start);
- pack_read(f, buf, s);
- r = init_module(dev, i, buf, s);
- heap_free(dev->heap, buf);
- pack_seek(f, before, seek_rel_start);
- if (!r) return false;
+ int c;
+ pack_read(f, &c, 4);
+ module_count[i] = c;
+ if (c) {
+ int o, s, mask;
+ int bucket, j;
+ Shader_Module* m = (Shader_Module*)arena_alloc(
+ a,
+ c * sizeof *m
+ );
+ for (j = 0; j < c; j++) {
+ m[j].mask = -1;
+ }
+ for (j = 0; j < c; j++) {
+ int k;
+ pack_read(f, &o, 4); /* H_Variant */
+ pack_read(f, &s, 4);
+ pack_read(f, &mask, 4);
+ pack_seek(f, 4, seek_rel_cur);
+ bucket = (int)(
+ fnv1a64((uint8_t*)&m, sizeof m) %
+ c
+ );
+ for (k = 0; k < c; k++) {
+ Shader_Module& mod = m[bucket];
+ if (mod.mask == -1)
+ goto found;
+ bucket = (bucket + 1) % c;
+ }
+ assert(0);
+ {
+ found:
+ char* buf = (char*)heap_alloc(dev->heap, s);
+ VkShaderModule r;
+ int before = pack_tell(f);
+ pack_seek(f, o, seek_rel_start);
+ pack_read(f, buf, s);
+ r = make_module(dev, buf, s);
+ heap_free(dev->heap, buf);
+ pack_seek(f, before, seek_rel_start);
+ if (!r) return false;
+ m[bucket] = Shader_Module { mask, r };
+ }
+ }
+ modules[i] = m;
} else {
- modules[i] = VK_NULL_HANDLE;
+ modules[i] = 0;
}
- pack_read(f, entrypoints[i], 24);
}
return true;
}
@@ -3946,13 +4174,15 @@ Asset* Texture_Loader::load(
char magic[4];
int w, h;
size_t size;
- Texture_Format fmt;
+ Texture_Format fmt = texture_format_r8i;
+ int mips = 0;
(void)a;
(void)s;
pack_read(f, magic, 4);
pack_read(f, &w, 4);
pack_read(f, &h, 4);
- pack_read(f, &fmt, 4);
+ pack_read(f, &fmt, 2);
+ pack_read(f, &mips, 2);
size = calc_size(fmt, w, h);
{
Buffer_Id buf = dev->create_buffer(
@@ -3961,9 +4191,6 @@ Asset* Texture_Loader::load(
Buffer_Flags::copy_src |
Buffer_Flags::cpu_readwrite
);
- void* mem = dev->map_buffer(buf, 0, size);
- pack_read(f, mem, size);
- dev->unmap_buffer(buf);
Texture_Id tex = dev->create_texture(
filename,
fmt,
@@ -3971,11 +4198,25 @@ Asset* Texture_Loader::load(
w,
h,
1,
+ mips,
1,
- 1,
- buf
+ 0
);
- dev->destroy_buffer(buf);
+ {
+ int i;
+ for (i = 0; i < mips; i++) {
+ size = calc_size(fmt, w, h);
+ void* mem = dev->map_buffer(buf, 0, size);
+ pack_read(f, mem, size);
+ dev->unmap_buffer(buf);
+ auto& ctx = dev->acquire();
+ ctx.copy(tex, buf, i, 0, 0, w, h);
+ dev->submit(ctx);
+ w >>= 1;
+ h >>= 1;
+ }
+ }
+ dev->destroy_bufferi(buf);
return &dev->get_texture(tex);
}
}
@@ -4002,7 +4243,8 @@ void Texture_Vk::init(
int array_size,
int start_mip,
int start_array,
- bool alias
+ bool alias,
+ int samples
) {
t->id = id;
t->parent = parent;
@@ -4022,6 +4264,7 @@ void Texture_Vk::init(
t->start_mip = start_mip;
t->start_array = start_array;
t->alias = alias;
+ t->samples = samples;
}
void Texture_Vk::destroy(Device_Vk* dev) {
diff --git a/video.hpp b/video.hpp
index 5aa25bc..f1bedb1 100644
--- a/video.hpp
+++ b/video.hpp
@@ -133,12 +133,19 @@ struct Pipeline {
Cull_Mode cull_mode;
Vertex_Format_Id vertex_format;
Shader_Id shader;
+ int samples;
+ int shader_masks[shader_type_count];
Descriptor descriptors[pipeline_max_descriptors];
int descriptor_count;
void hash();
bool pipeline_eq(const Pipeline& other) const {
+ int i;
+ for (i = 0; i < shader_type_count; i++) {
+ if (other.shader_masks[i] != shader_masks[i])
+ return false;
+ }
return
shader == other.shader &&
vertex_format == other.vertex_format &&
@@ -161,7 +168,8 @@ struct Pipeline {
blend_dst_alpha == other.blend_dst_alpha &&
blend_mode == other.blend_mode &&
blend_mode_alpha == other.blend_mode_alpha &&
- cull_mode == other.cull_mode;
+ cull_mode == other.cull_mode &&
+ samples == other.samples;
}
bool desc_layout_eq(const Pipeline& other) const {
@@ -228,6 +236,7 @@ struct Render_Pass {
struct Target {
Texture_Id id;
Texture_Format fmt;
+ int samples;
Clear_Mode mode;
union {
Colour colour;
@@ -266,6 +275,11 @@ struct Render_Pass {
}
return true;
}
+
+ int get_samples() const {
+ if (colour_count) return colours[0].samples;
+ return depth.samples;
+ }
};
struct Vertex_Buffer_Binding {
@@ -325,6 +339,7 @@ struct Pipeline_Builder {
);
PB& cull(Cull_Mode mode);
PB& shader(Shader_Id s);
+ PB& option(Shader_Type type, int mask);
PB& vertex_format(Vertex_Format_Id vf);
PB& texture(int binding, Texture_Id t, Sampler_Id s);
PB& cbuffer(
@@ -359,6 +374,7 @@ struct Texture : public Asset {
int w, h, d;
int mip_count, array_size;
int start_mip, start_array;
+ int samples;
bool alias;
};
@@ -486,7 +502,8 @@ struct Device {
int d,
int mip_count,
int array_size,
- Buffer_Id init
+ Buffer_Id init,
+ int samples = 1
);
Texture_Id alias_texture(
Texture_Id o,
@@ -553,6 +570,16 @@ struct Context {
void submit(const Render_Pass& rp);
void copy(Buffer_Id dst, Buffer_Id src);
void copy(Texture_Id dst, Buffer_Id src);
+ void copy(
+ Texture_Id dst,
+ Buffer_Id src,
+ int mip,
+ int x,
+ int y,
+ int w,
+ int h
+ );
+ void resolve(Texture_Id dst, Texture_Id src);
void transition(Texture_Id id, Resource_State state);
void debug_push(const char* name);
void debug_pop();
@@ -568,6 +595,7 @@ struct Shader : public Asset {
int attribute_index(const char* name);
int target_index(const char* name);
int descriptor_binding(const char* name);
+ int opt_mask(Shader_Type type, const char* name);
int descriptor_stage(int slot);
};
diff --git a/world.cpp b/world.cpp
index 5cfd8bf..a08c024 100644
--- a/world.cpp
+++ b/world.cpp
@@ -8,12 +8,33 @@ extern "C" {
static int component_sizes[max_components];
+void Slinky::init(Arena* a, int size) {
+ data = arena_alloc(a, size * slinky_size);
+ entities = (Entity_Id*)arena_alloc(
+ a,
+ sizeof *entities * slinky_size
+ );
+ count = 0;
+}
+
+void* Slinky::add(Entity_Id eid, int size, int& mapping) {
+ int idx = count++;
+ assert(count <= slinky_size);
+ entities[idx] = eid;
+ mapping = idx;
+ return &((char*)data)[idx * size];
+}
+
+void* Slinky::get(Entity_Id eid, int mapping, int size) {
+ char* e = &((char*)data)[mapping * size];
+ assert(eid == entities[mapping]);
+ (void)eid;
+ return e;
+}
+
void Pool::init(Arena* a, Component_Mask m) {
int i, coff;
- next = 0;
- size = 0;
mask = m;
- count = 0;
for (i = 0, coff = 0; i < max_components; i++) {
if (m & ((Component_Mask)1 << i)) {
offsets[i] = coff;
@@ -21,50 +42,76 @@ void Pool::init(Arena* a, Component_Mask m) {
}
}
size = coff;
- data = arena_alloc(a, size * pool_cap);
+ slinkies[0].init(a, size);
+ slinky_count = 1;
+ count = 0;
}
-void* Pool::add(Arena* a, Entity_Id eid) {
- int idx;
- if (next)
- return next->add(a, eid);
- if (count >= pool_cap) {
- next = (Pool*)arena_alloc(a, sizeof *next);
- next->init(a, mask);
- return next->add(a, eid);
+Slinky& Pool::get_slinky(Arena* a) {
+ int i, e = slinky_count;
+ for (i = 0; i < e; i++) {
+ Slinky& s = slinkies[i];
+ if (s.count < slinky_size)
+ return s;
}
- idx = count++;
- entities[idx] = eid;
- mapping[entity_index(eid)] = idx;
- return &((char*)data)[idx * size];
+ assert(slinky_count < max_slinkies);
+ Slinky& s = slinkies[slinky_count++];
+ s.init(a, size);
+ return s;
+}
+
+void* Pool::add(Arena* a, Entity_Id eid) {
+ Slinky& slinky = get_slinky(a);
+ Mapping& m = mapping[entity_index(eid)];
+ m.slinky = &slinky - slinkies;
+ count++;
+ return slinky.add(eid, size, m.mapping);
}
void Pool::remove(Entity_Id eid) {
- int eind = entity_index(eid);
- int end = count - 1;
- assert(eid == entities[mapping[eind]]);
- memmove(
- (char*)data + eind * size,
- (char*)data + end * size,
- size
- );
- entities[eind] = entities[count];
- mapping[end] = eind;
- count = end;
+ Mapping& m = mapping[entity_index(eid)];
+ Slinky& s = slinkies[m.slinky];
+ assert(m.slinky >= 0);
+ if (count > 1) {
+ int idx = slinky_count - 1;
+ Entity_Id le;
+ void* last;
+#ifdef DEBUG
+ last = 0;
+#endif
+ for (; idx >= 0; idx--) {
+ Slinky& s = slinkies[idx];
+ int& c = s.count;
+ if (c) {
+ c--;
+ last = (char*)s.data + c * size;
+ le = s.entities[c];
+ s.entities[c] = 0;
+ break;
+ }
+ }
+ assert(last != 0);
+ memcpy((char*)s.data + m.mapping * size, last, size);
+ s.entities[m.mapping] = le;
+ mapping[entity_index(le)] = m;
+ m = Mapping { -1, -1 };
+ } else
+ s.count--;
+ count--;
}
void* Pool::get(Entity_Id eid, int cid) {
- int eind = entity_index(eid);
- char* e = &((char*)data)[mapping[eind] * size];
- assert(eid == entities[mapping[eind]]);
- return &e[offsets[cid]];
+ Mapping m = mapping[entity_index(eid)];
+ Slinky& s = slinkies[m.slinky];
+ char* ptr = (char*)s.get(eid, m.mapping, size);
+ return ptr + offsets[cid];
}
void* Pool::get(Entity_Id eid) {
- int eind = entity_index(eid);
- void* e = &((char*)data)[mapping[eind] * size];
- assert(eid == entities[mapping[eind]]);
- return e;
+ Mapping m = mapping[entity_index(eid)];
+ Slinky& s = slinkies[m.slinky];
+ char* ptr = (char*)s.get(eid, m.mapping, size);
+ return ptr;
}
int get_new_component_id(int size) {
@@ -91,6 +138,7 @@ void World::init(Arena* a) {
arena = a;
count = 0;
free_count = 0;
+ dq_count = 0;
for (i = 0; i < max_entities; i++)
versions[i] = 1;
for (i = 0; i < max_pools; i++)
@@ -166,7 +214,6 @@ void* World::get(Entity_Id eid, int cid) {
int eind = entity_index(eid);
Pool& p = get_pool(masks[eind]);
assert(versions[eind] == entity_version(eid));
- assert(p.entities[p.mapping[eind]] == eid);
return p.get(eid, cid);
}
@@ -202,3 +249,16 @@ void World::destroy(Entity_Id e) {
versions[entity_index(e)]++;
}
+void World::qdestroy(Entity_Id e) {
+ assert(e);
+ assert(dq_count < max_entities);
+ dq[dq_count++] = e;
+}
+
+void World::update() {
+ int i, e = dq_count;
+ Entity_Id* d = dq;
+ for (i = 0; i < e; i++, d++)
+ destroy(*d);
+ dq_count = 0;
+}
diff --git a/world.hpp b/world.hpp
index 267b58a..c944b12 100644
--- a/world.hpp
+++ b/world.hpp
@@ -3,28 +3,59 @@
struct Arena;
+#include "entity.hpp"
+
#include <stdint.h>
#include <new>
+#include <tuple>
#include <utility>
-
+extern "C" {
+#include "plat.h"
+}
using Component_Mask = uint64_t;
-using Entity_Id = uint32_t;
#define max_entities 1024
-#define pool_cap 128
+#define slinky_size 1
#define max_components 64
+#define max_slinkies (max_entities / slinky_size)
+
+static_assert((!(slinky_size & (slinky_size - 1))));
+/* slinky_size needs to be a power of 2 */
+static consteval int get_slinky_size_bit() {
+ int i;
+ int m = slinky_size;
+ for (i = 0; m; m >>= 1, i++);
+ if (i == 0)
+ throw "wtf";
+ return i - 1;
+}
+static constexpr int slinky_size_bit = get_slinky_size_bit();
+
+struct Slinky {
+ Entity_Id* entities;
+ void* data;
+ int count;
+
+ void init(Arena* a, int size);
+ void* add(Entity_Id eid, int size, int& mapping);
+ void* get(Entity_Id eid, int mapping, int size);
+};
struct Pool {
+ struct Mapping {
+ int slinky;
+ int mapping;
+ };
+
Component_Mask mask;
- Pool* next;
- void* data;
- Entity_Id entities[pool_cap];
- int mapping[max_entities];
+ Slinky slinkies[max_slinkies];
+ Mapping mapping[max_entities];
int offsets[max_components];
- int size, count;
+ int size, count, slinky_count;
void init(Arena* a, Component_Mask m);
+ Slinky& get_slinky(Arena* a);
void* add(Arena* a, Entity_Id eid);
void* get(Entity_Id eid, int cid);
void* get(Entity_Id eid);
@@ -43,8 +74,9 @@ struct World {
uint8_t versions[max_entities];
Entity_Id entities[max_entities];
Entity_Id freelist[max_entities];
+ Entity_Id dq[max_entities];
Arena* arena;
- int count, free_count;
+ int count, dq_count, free_count;
void init(Arena* a);
uint64_t hash_mask(Component_Mask m);
@@ -94,6 +126,8 @@ struct World {
void* get(Entity_Id eid, int cid);
void remove(Entity_Id eid, int cid);
void destroy(Entity_Id e);
+ void qdestroy(Entity_Id e);
+ void update();
struct View {
World* w;
@@ -126,8 +160,11 @@ struct World {
template <typename C>
C& get() {
Pool* p = v->pools[ind];
+ Slinky& s = p->slinkies[ptr >> slinky_size_bit];
+ int si = &s - p->slinkies;
+ int off = ptr - (si << slinky_size_bit);
return *(C*)(
- (char*)p->data + ptr * p->size +
+ (char*)s.data + off * p->size +
p->offsets[v->w->get_component_id<C>()]
);
}
@@ -138,7 +175,11 @@ struct World {
Entity_Id entity() {
Pool* p = v->pools[ind];
- return p->entities[ptr];
+ Slinky& s = p->slinkies[ptr >> slinky_size_bit];
+ int si = &s - p->slinkies;
+ int off = ptr - (si << slinky_size_bit);
+ assert(s.entities[off]);
+ return s.entities[off];
}
};