summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c2.cpp5
-rw-r--r--model.cpp5
-rw-r--r--pipeline.cpp117
-rw-r--r--todo.txt4
-rw-r--r--ui.cpp5
-rw-r--r--vid_enums.h7
-rw-r--r--video.cpp363
-rw-r--r--video.hpp89
8 files changed, 483 insertions, 112 deletions
diff --git a/c2.cpp b/c2.cpp
index 9327727..573744e 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -174,12 +174,12 @@ extern "C" int entrypoint() {
dev->unmap_buffer(cbuf2);
}
- Pipeline_Builder pb(&frame_arena);
+ Pipeline_Builder pb(&frame_arena, dev);
pb.begin_rp();
pb.rp_target(dev->get_backbuffer(), { r, 0x00, 0xff, 0xff });
Render_Pass& pass = pb.build_rp();
- pb.begin(dev);
+ pb.begin();
pb.shader(shader->id);
pb.vertex_format(shader->vf);
pb.texture(
@@ -208,6 +208,7 @@ extern "C" int entrypoint() {
pb.begin_rp();
pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore);
+ pb.rp_depth_target(dev->get_depth_target(), 1.0f);
Render_Pass& pass2 = pb.build_rp();
monkey->render(dev, &frame_arena, pass2, cbuf2);
diff --git a/model.cpp b/model.cpp
index dac91e4..4c3e40f 100644
--- a/model.cpp
+++ b/model.cpp
@@ -127,14 +127,15 @@ void Model::render(
.offset = 0
};
Draw draw{};
- Pipeline_Builder pb(a);
+ Pipeline_Builder pb(a, dev);
draw.verts = vbb;
draw.inds = ibb;
draw.vertex_count = mesh.count;
draw.instance_count = 1;
draw.first_vertex = mesh.offset;
draw.vertex_offset = mesh.vbo_offset;
- pb.begin(dev);
+ pb.begin();
+ pb.depth(true, true, Depth_Mode::less);
pb.shader(mesh.shader);
pb.cbuffer(
shader.descriptor_binding("config_buffer"),
diff --git a/pipeline.cpp b/pipeline.cpp
index 88b2009..c31ef69 100644
--- a/pipeline.cpp
+++ b/pipeline.cpp
@@ -8,37 +8,115 @@ extern "C" {
#include "str.h"
}
-Pipeline_Builder::Pipeline_Builder(Arena* arena):
- arena(arena) {}
+Pipeline_Builder::Pipeline_Builder(Arena* arena, Device* dev):
+ arena(arena), dev(dev) {}
void Pipeline_Builder::begin_rp() {
pass = (Render_Pass*)arena_alloc(arena, sizeof *pass);
- pass->target = 0;
- pass->clear = { 0, 0, 0, 0 };
+ zero(pass, sizeof *pass);
}
void Pipeline_Builder::rp_target(Texture_Id id, Colour clear) {
- pass->target = id;
- pass->clear = clear;
- pass->mode = Clear_Mode::clear;
+ int i = pass->colour_count++;
+ Texture& texture = dev->get_texture(id);
+ Render_Pass::Target t{
+ .id = id,
+ .fmt = texture.fmt,
+ .mode = Clear_Mode::clear,
+ .clear = { .colour = clear }
+ };
+ assert(i < max_colour_attachments);
+ pass->colours[i] = t;
}
void Pipeline_Builder::rp_target(Texture_Id id, Clear_Mode clear) {
- pass->target = id;
+ int i = pass->colour_count++;
+ Texture& texture = dev->get_texture(id);
+ Render_Pass::Target t{
+ .id = id,
+ .fmt = texture.fmt,
+ .mode = clear,
+ .clear = { .depth = 0.0f }
+ };
+ assert(i < max_colour_attachments);
assert(clear != Clear_Mode::clear);
- pass->mode = clear;
+ pass->colours[i] = t;
+}
+
+void Pipeline_Builder::rp_depth_target(Texture_Id id, float clear) {
+ Texture& texture = dev->get_texture(id);
+ Render_Pass::Target t{
+ .id = id,
+ .fmt = texture.fmt,
+ .mode = Clear_Mode::clear,
+ .clear = { .depth = clear }
+ };
+ pass->depth = t;
+}
+
+void Pipeline_Builder::rp_depth_target(Texture_Id id, Clear_Mode mode) {
+ Texture& texture = dev->get_texture(id);
+ Render_Pass::Target t{
+ .id = id,
+ .fmt = texture.fmt,
+ .mode = mode,
+ .clear = { .depth = 0.0f }
+ };
+ assert(mode != Clear_Mode::clear);
+ pass->depth = t;
}
void Pipeline_Builder::validate_rp() {
- assert(pass->target);
+ int i, c = pass->colour_count;
+ int w, h;
+ assert(c || pass->depth.id);
+ if (c) {
+ Texture& tex = dev->get_texture(pass->colours[0].id);
+ assert(pass->colours[0].id != 0);
+ assert(pass->colours[0].fmt == tex.fmt);
+ w = tex.w;
+ h = tex.h;
+ assert(w && h);
+ }
+ for (i = 1; i < c; i++) {
+ Texture& tex = dev->get_texture(pass->colours[i].id);
+ assert(pass->colours[i].id != 0);
+ assert(pass->colours[i].fmt == tex.fmt);
+ assert(tex.w == w);
+ assert(tex.h == h);
+ }
+ if (pass->depth.id) {
+ Texture& d = dev->get_texture(pass->depth.id);
+ assert(d.fmt == pass->depth.fmt);
+ assert(
+ d.fmt == texture_format_d16 ||
+ d.fmt == texture_format_d24s8 ||
+ d.fmt == texture_format_d32
+ );
+ assert(d.w == w);
+ assert(d.h == h);
+ }
}
Render_Pass& Pipeline_Builder::build_rp() {
+ int i, c = pass->colour_count;
+#define h(n, v) \
+ n = fnv1a64_2(n, (uint8_t*)&v, sizeof v)
validate_rp();
+ h(pass->layout_hash, pass->colour_count);
+ h(pass->layout_hash, pass->depth.fmt);
+ h(pass->layout_hash, pass->depth.mode);
+ h(pass->resource_hash, pass->depth.id);
+ for (i = 0; i < c; i++) {
+ Render_Pass::Target& ct = pass->colours[i];
+ h(pass->layout_hash, ct.fmt);
+ h(pass->layout_hash, ct.mode);
+ h(pass->resource_hash, ct.id);
+ }
return *pass;
}
-void Pipeline_Builder::begin(Device* dev) {
+void Pipeline_Builder::begin() {
pip = (Pipeline*)arena_alloc(arena, sizeof *pip);
zero(pip, sizeof *pip);
if (dev) {
@@ -79,6 +157,12 @@ void Pipeline_Builder::scissor(
pip->scissor[3] = h;
}
+void Pipeline_Builder::depth(bool test, bool write, Depth_Mode mode) {
+ pip->depth_test = test;
+ pip->depth_write = write;
+ pip->depth_mode = mode;
+}
+
void Pipeline_Builder::shader(Shader_Id s) {
pip->shader = s;
}
@@ -122,6 +206,17 @@ Pipeline& Pipeline_Builder::build() {
h(pip->pipeline_hash, pip->vertex_format);
h(pip->pipeline_hash, pip->shader);
h(pip->pipeline_hash, pip->descriptor_count);
+ h(pip->pipeline_hash, pip->viewport[0]);
+ h(pip->pipeline_hash, pip->viewport[1]);
+ h(pip->pipeline_hash, pip->viewport[2]);
+ h(pip->pipeline_hash, pip->viewport[3]);
+ h(pip->pipeline_hash, pip->scissor[0]);
+ h(pip->pipeline_hash, pip->scissor[1]);
+ h(pip->pipeline_hash, pip->scissor[2]);
+ h(pip->pipeline_hash, pip->scissor[3]);
+ h(pip->pipeline_hash, pip->depth_test);
+ h(pip->pipeline_hash, pip->depth_write);
+ h(pip->pipeline_hash, pip->depth_mode);
{
int i, e = pip->descriptor_count;
pip->descriptor_resource_hash = fnv1a64(0, 0);
diff --git a/todo.txt b/todo.txt
index 69ec369..ca35bdf 100644
--- a/todo.txt
+++ b/todo.txt
@@ -10,8 +10,8 @@ todo list
- [x] 3D maths library
- [x] model conversion
- [x] render a model
- - [ ] depth buffer
- - [ ] seperate framebuffers renderpasses
+ - [x] depth buffer
+ - [x] seperate framebuffers and renderpasses
- [ ] VRAM allocator
- [ ] don't re-bind pipelines and descriptors if not necessary
- [ ] material system
diff --git a/ui.cpp b/ui.cpp
index d142586..47c362c 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -99,6 +99,7 @@ static Texture_Id create_atlas(Device* d, Arena* a) {
d->unmap_buffer(buf);
tex = d->create_texture(
texture_format_r8i,
+ Texture_Flags::sampleable | Texture_Flags::copy_dst,
font_w,
10,
buf
@@ -267,12 +268,12 @@ void UI::render(Arena* s, Texture_Id target) {
}
}
- Pipeline_Builder pb(s);
+ Pipeline_Builder pb(s, device);
pb.begin_rp();
pb.rp_target(device->get_backbuffer(), Clear_Mode::restore);
Render_Pass& pass = pb.build_rp();
- pb.begin(device);
+ pb.begin();
pb.shader(shader);
pb.vertex_format(vertex_format);
pb.cbuffer(shader_info.config_binding, config_buf);
diff --git a/vid_enums.h b/vid_enums.h
index fca4f06..d96f57c 100644
--- a/vid_enums.h
+++ b/vid_enums.h
@@ -12,9 +12,14 @@
x(rgb16f) \
x(rgb32f) \
x(rgba8i) \
+ x(rgba8i_srgb) \
+ x(bgra8i_srgb) \
x(rgba16f) \
x(rgba32f) \
- x(bc1)
+ x(bc1) \
+ x(d16) \
+ x(d24s8) \
+ x(d32)
typedef enum {
#define x(n) texture_format_ ## n,
diff --git a/video.cpp b/video.cpp
index 4a79adb..ba6fd7c 100644
--- a/video.cpp
+++ b/video.cpp
@@ -6,6 +6,7 @@
#define max_buffers 1024
#define max_vertex_formats 64
#define max_rpos 64
+#define max_fbos 64
#define max_pipelines 64
#define max_descriptor_sets 64
#define max_shaders 32
@@ -203,11 +204,42 @@ static VkFormat get_vk_format(Texture_Format fmt) {
case texture_format_rgb16f: return VK_FORMAT_R16G16B16_SFLOAT;
case texture_format_rgb32f: return VK_FORMAT_R32G32B32_SFLOAT;
case texture_format_rgba8i: return VK_FORMAT_R8G8B8A8_UNORM;
+ case texture_format_rgba8i_srgb: return VK_FORMAT_R8G8B8A8_SRGB;
+ case texture_format_bgra8i_srgb: return VK_FORMAT_B8G8R8A8_SRGB;
case texture_format_rgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
case texture_format_rgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
case texture_format_bc1: return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
- default: assert(0); return VK_FORMAT_UNDEFINED;
+ case texture_format_d16: return VK_FORMAT_D16_UNORM;
+ case texture_format_d24s8: return VK_FORMAT_D24_UNORM_S8_UINT;
+ case texture_format_d32: return VK_FORMAT_D32_SFLOAT;
+ case texture_format_count: break;
}
+ assert(0);
+ return VK_FORMAT_UNDEFINED;
+}
+
+static VkImageUsageFlags get_texture_usage(int flags) {
+ VkImageUsageFlags f = 0;
+ if (flags & Texture_Flags::sampleable)
+ f |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ if (flags & Texture_Flags::colour_target)
+ f |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ if (flags & Texture_Flags::depth_stencil_target)
+ f |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ if (flags & Texture_Flags::copy_src)
+ f |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ if (flags & Texture_Flags::copy_dst)
+ f |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ return f;
+}
+
+static VkImageAspectFlags get_image_aspect(int flags) {
+ VkImageUsageFlags f = 0;
+ if (flags & Texture_Flags::depth_stencil_target)
+ f |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ else
+ f |= VK_IMAGE_ASPECT_COLOR_BIT;
+ return f;
}
VkImageLayout state_to_image_layout(Resource_State s) {
@@ -446,6 +478,7 @@ struct Shader_Vk : public Shader, public Late_Terminated {
};
struct Renderpass_Vk;
+struct Framebuffer_Vk;
struct Context_Vk : public Context {
int state;
Device_Vk* dev;
@@ -463,8 +496,10 @@ struct Context_Vk : public Context {
void release();
void destroy();
- Renderpass_Vk& begin_rp(const Render_Pass& rp);
- void end_rp(Renderpass_Vk& rpo);
+ std::pair<Renderpass_Vk&, Framebuffer_Vk&> begin_rp(
+ const Render_Pass& rp
+ );
+ void end_rp(Renderpass_Vk& rpo, Framebuffer_Vk& fbo);
};
struct Texture_Vk : public Texture, public Late_Terminated {
@@ -520,7 +555,14 @@ struct Rpo_Key {
bool operator==(const Rpo_Key& other) const {
return
is_first == other.is_first &&
- rpo == other.rpo;
+ rpo.layout_eq(other.rpo);
+ }
+};
+
+struct Fbo_Key {
+ Render_Pass rpo;
+ bool operator==(const Fbo_Key& other) const {
+ return rpo.resources_eq(other.rpo);
}
};
@@ -546,8 +588,6 @@ struct Dso_Key {
struct Renderpass_Vk {
VkRenderPass rpo;
- VkFramebuffer fbo;
- VkClearValue clear;
int age;
void on_submit() {
@@ -556,8 +596,23 @@ struct Renderpass_Vk {
VkAttachmentLoadOp load_op_from_mode(Clear_Mode m);
- void init_rp(Device_Vk* dev, const Rpo_Key& rp);
- void init_fb(Device_Vk* dev, const Render_Pass& rp);
+ void init(Device_Vk* dev, const Rpo_Key& rp);
+ void destroy(Device_Vk* dev);
+};
+
+struct Framebuffer_Vk {
+ VkFramebuffer fbo;
+ int age;
+
+ void on_submit() {
+ age = 0;
+ }
+
+ void init(
+ Device_Vk* dev,
+ const Renderpass_Vk& rpo,
+ const Render_Pass& rp
+ );
void destroy(Device_Vk* dev);
};
@@ -626,6 +681,8 @@ struct Pipeline_Vk {
const Pipeline& desc
);
+ static VkCompareOp get_compare_op(Depth_Mode m);
+
void on_submit() {
age = 0;
}
@@ -673,10 +730,18 @@ struct Sampler_Vk : public Late_Terminated {
template<>
struct Hash_Function<Rpo_Key> {
size_t operator()(const Rpo_Key& k) const {
- return (size_t)fnv1a64_2(fnv1a64(
- (uint8_t*)&k.rpo,
- sizeof k.rpo
- ), (uint8_t*)&k.is_first, 1);
+ return (size_t)fnv1a64_2(
+ k.rpo.layout_hash,
+ (uint8_t*)&k.is_first,
+ 1
+ );
+ }
+};
+
+template<>
+struct Hash_Function<Fbo_Key> {
+ size_t operator()(const Fbo_Key& k) const {
+ return k.rpo.resource_hash;
}
};
@@ -736,13 +801,6 @@ struct Hash_Function<Sampler_Id> {
}
};
-template<>
-struct std::hash<Render_Pass> {
- size_t operator()(const Render_Pass& rp) const {
- return (size_t)fnv1a64((uint8_t*)&rp, sizeof rp);
- }
-};
-
struct Shader_Loader : public Asset_Loader {
Device_Vk* dev;
void init(Device_Vk* d);
@@ -818,6 +876,7 @@ struct Device_Vk : public Device {
uint32_t sampler_count;
Hash_Map<Rpo_Key, Renderpass_Vk, max_rpos> rpo_cache;
+ Hash_Map<Fbo_Key, Framebuffer_Vk, max_fbos> fbo_cache;
Hash_Map<Pso_Key, Pipeline_Vk, max_pipelines> pso_cache;
Hash_Map<Dso_Key, Descriptor_Set_Vk, max_descriptor_sets> dso_cache;
@@ -825,6 +884,8 @@ struct Device_Vk : public Device {
uint32_t terminator_index;
bool first_rp;
+ Texture_Id depth;
+
Texture_Id alloc_texture();
Buffer_Id alloc_buffer();
Vertex_Format_Id alloc_vf();
@@ -846,6 +907,14 @@ struct Device_Vk : public Device {
Renderpass_Vk& create_rpo(const Rpo_Key& rp);
Renderpass_Vk& get_rpo(const Rpo_Key& rp);
+ Framebuffer_Vk& create_fbo(
+ const Renderpass_Vk& rpo,
+ const Fbo_Key& fb
+ );
+ Framebuffer_Vk& get_fbo(
+ const Renderpass_Vk& rpo,
+ const Fbo_Key& fb
+ );
Pipeline_Vk& create_pso(const Pso_Key& pip);
Pipeline_Vk& get_pso(const Pso_Key& pop);
Descriptor_Set_Vk& create_dso(
@@ -860,6 +929,7 @@ struct Device_Vk : public Device {
void collect_garbage();
void queue_destroy(Late_Terminated* obj);
void create_terminators();
+ void create_depth(int w, int h);
int find_memory_type(
uint32_t filter,
@@ -1175,6 +1245,7 @@ void Device_Vk::init_internal() {
samplers.init();
sampler_count = 1;
rpo_cache.init();
+ fbo_cache.init();
pso_cache.init();
dso_cache.init();
shader_loader.init(this);
@@ -1198,6 +1269,8 @@ void Device_Vk::init_internal() {
contexts[i].state = context_state_avail;
swapchain.init(*app, this);
create_terminators();
+ depth = 0;
+ create_depth(app->w, app->h);
}
void Device_Vk::create_terminators() {
@@ -1216,14 +1289,29 @@ void Device_Vk::create_terminators() {
}
}
+void Device_Vk::create_depth(int w, int h) {
+ if (depth)
+ destroy_texture(depth);
+ depth = create_texture(
+ texture_format_d24s8,
+ Texture_Flags::sampleable | Texture_Flags::depth_stencil_target,
+ w,
+ h,
+ 0
+ );
+}
+
void Device_Vk::deinit_internal() {
int i, image_count = swapchain.image_count;
vkDeviceWaitIdle(dev);
+ destroy_texture(depth);
swapchain.destroy(this);
deinit_swap_cap(this, &swap_cap);
app_destroy_vk_surface(app, inst, surf);
for (auto i : rpo_cache)
i.second.destroy(this);
+ for (auto i : fbo_cache)
+ i.second.destroy(this);
for (auto i : pso_cache)
i.second.destroy(this);
for (auto i : dso_cache)
@@ -1255,20 +1343,13 @@ void Device_Vk::on_resize_internal(int w, int h) {
get_swap_cap(this, phys_dev, surf, &swap_cap);
swapchain.recreate(*app, this);
create_terminators();
+ create_depth(w, h);
}
Renderpass_Vk& Device_Vk::create_rpo(const Rpo_Key& k) {
- VkClearValue clear{};
- auto& rp = k.rpo;
- clear.color.float32[0] = (float)rp.clear.r / 255.0f;
- clear.color.float32[1] = (float)rp.clear.g / 255.0f;
- clear.color.float32[2] = (float)rp.clear.b / 255.0f;
- clear.color.float32[3] = (float)rp.clear.a / 255.0f;
Renderpass_Vk rpo;
- rpo.init_rp(this, k);
- rpo.init_fb(this, rp);
+ rpo.init(this, k);
rpo.age = 0;
- rpo.clear = clear;
return rpo_cache.set(k, rpo);
}
@@ -1279,6 +1360,27 @@ Renderpass_Vk& Device_Vk::get_rpo(const Rpo_Key& rp) {
return *rpo;
}
+Framebuffer_Vk& Device_Vk::create_fbo(
+ const Renderpass_Vk& rpo,
+ const Fbo_Key& k
+) {
+ auto& fb = k.rpo;
+ Framebuffer_Vk fbo;
+ fbo.init(this, rpo, fb);
+ fbo.age = 0;
+ return fbo_cache.set(k, fbo);
+}
+
+Framebuffer_Vk& Device_Vk::get_fbo(
+ const Renderpass_Vk& rpo,
+ const Fbo_Key& fb
+) {
+ Framebuffer_Vk* fbo = fbo_cache.get(fb);
+ if (!fbo)
+ return create_fbo(rpo, fb);
+ return *fbo;
+}
+
Pipeline_Vk& Device_Vk::create_pso(const Pso_Key& pip) {
Pipeline_Vk pso;
pso.age = 0;
@@ -1313,11 +1415,6 @@ Descriptor_Set_Vk& Device_Vk::get_dso(
return *dso;
}
-void Renderpass_Vk::destroy(Device_Vk* dev) {
- vkDestroyRenderPass(dev->dev, rpo, &dev->ac);
- vkDestroyFramebuffer(dev->dev, fbo, &dev->ac);
-}
-
void Device_Vk::collect_garbage() {
int max_age = swapchain.image_count + 3;
for (const auto& i: rpo_cache) {
@@ -1328,6 +1425,14 @@ void Device_Vk::collect_garbage() {
rpo_cache.remove(i.first);
}
}
+ for (const auto& i: fbo_cache) {
+ auto& fb = i.second;
+ fb.age++;
+ if (fb.age > max_age) {
+ fb.destroy(this);
+ fbo_cache.remove(i.first);
+ }
+ }
for (const auto& i: pso_cache) {
auto& pip = i.second;
pip.age++;
@@ -1377,39 +1482,63 @@ VkAttachmentLoadOp Renderpass_Vk::load_op_from_mode(
return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
-void Renderpass_Vk::init_rp(
+void Renderpass_Vk::init(
Device_Vk* dev,
const Rpo_Key& rpk
) {
VkRenderPassCreateInfo ri{};
- VkAttachmentDescription ad{};
- VkAttachmentReference ar{};
+ VkAttachmentDescription ads[2];
+ VkAttachmentReference car, dar;
VkSubpassDescription sd{};
VkResult r;
auto& rp = rpk.rpo;
-
- ad.format = dev->swapchain.format.format;
- ad.samples = VK_SAMPLE_COUNT_1_BIT;
- ad.loadOp = load_op_from_mode(rp.mode);
- ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- if (rpk.is_first)
- ad.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
- else
- ad.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- ad.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- ar.attachment = 0;
- ar.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ bool has_depth = rp.depth.id;
+ int count = 0, i, c = rp.colour_count;
+ zero(ads, sizeof ads);
+ for (i = 0; i < c; i++) {
+ int index = count++;
+ auto& colour = rp.colours[i];
+ auto& ad = ads[index];
+ ad.format = get_vk_format(colour.fmt);
+ ad.samples = VK_SAMPLE_COUNT_1_BIT;
+ ad.loadOp = load_op_from_mode(colour.mode);
+ ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ if (rpk.is_first)
+ ad.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ else
+ ad.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ ad.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ car.attachment = index;
+ car.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ }
+ 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);
+ ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ ad.stencilLoadOp = ad.loadOp;
+ ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ if (rpk.is_first)
+ ad.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ else
+ ad.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ ad.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ dar.attachment = i;
+ dar.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ }
sd.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
sd.colorAttachmentCount = 1;
- sd.pColorAttachments = &ar;
+ sd.pColorAttachments = &car;
+ sd.pDepthStencilAttachment = has_depth? &dar: 0;
ri.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- ri.attachmentCount = 1;
- ri.pAttachments = &ad;
+ ri.attachmentCount = count;
+ ri.pAttachments = ads;
ri.subpassCount = 1;
ri.pSubpasses = &sd;
@@ -1420,21 +1549,42 @@ void Renderpass_Vk::init_rp(
}
}
-void Renderpass_Vk::init_fb(
+void Renderpass_Vk::destroy(Device_Vk* dev) {
+ vkDestroyRenderPass(dev->dev, rpo, &dev->ac);
+}
+
+void Framebuffer_Vk::init(
Device_Vk* dev,
+ const Renderpass_Vk& rpo,
const Render_Pass& rp
) {
- const Texture_Vk& texture =
- *(const Texture_Vk*)&dev->get_texture(rp.target);
+ bool has_depth = rp.depth.id;
+ int i, count = 0, w, h;
+ VkImageView atts[2];
VkResult r;
VkFramebufferCreateInfo fbi{};
+ for (i = 0; i < rp.colour_count; i++) {
+ const auto& tar = rp.colours[i];
+ const Texture_Vk& texture =
+ *(const Texture_Vk*)&dev->get_texture(tar.id);
+ atts[count++] = texture.view;
+ w = texture.w;
+ h = texture.h;
+ }
+ if (has_depth) {
+ const Texture_Vk& texture =
+ *(const Texture_Vk*)&dev->get_texture(rp.depth.id);
+ atts[count++] = texture.view;
+ w = texture.w;
+ h = texture.h;
+ }
fbi.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- fbi.renderPass = rpo;
- fbi.width = texture.w;
- fbi.height = texture.h;
+ fbi.renderPass = rpo.rpo;
+ fbi.width = w;
+ fbi.height = h;
fbi.layers = 1;
- fbi.attachmentCount = 1;
- fbi.pAttachments = &texture.view;
+ fbi.attachmentCount = count;
+ fbi.pAttachments = atts;
r = vkCreateFramebuffer(dev->dev, &fbi, &dev->ac, &fbo);
if (r != VK_SUCCESS) {
print_err("Failed to create a framebuffer.\n");
@@ -1442,6 +1592,10 @@ void Renderpass_Vk::init_fb(
}
}
+void Framebuffer_Vk::destroy(Device_Vk* dev) {
+ vkDestroyFramebuffer(dev->dev, fbo, &dev->ac);
+}
+
static int get_image_count(const Swap_Cap& s) {
const VkSurfaceCapabilitiesKHR& cap = s.cap;
return cap.minImageCount + (cap.minImageCount < cap.maxImageCount);
@@ -1479,7 +1633,7 @@ static VkImageView make_view(
Device_Vk* dev,
VkImage image,
VkFormat fmt,
- VkImageAspectFlagBits flags
+ VkImageAspectFlags flags
) {
VkImageViewCreateInfo vi{};
VkResult r;
@@ -1568,6 +1722,7 @@ Texture_Id Swapchain::create_image(
tex.view = view;
tex.w = w;
tex.h = h;
+ tex.fmt = texture_format_bgra8i_srgb;
tex.alias = true;
return id;
}
@@ -1716,6 +1871,10 @@ Texture_Id Device::get_backbuffer() {
return ((Device_Vk*)this)->backbuffer_id;
}
+Texture_Id Device::get_depth_target() {
+ return ((Device_Vk*)this)->depth;
+}
+
Texture& Device::get_texture(Texture_Id id) {
return ((Device_Vk*)this)->textures[id];
}
@@ -1802,7 +1961,7 @@ void Context::submit(
Descriptor_Set_Vk* dso = 0;
if (p.descriptor_count)
dso = &dev->get_dso(pso, *(Dso_Key*)&p);
- auto& rpo = ctx->begin_rp(rp);
+ auto [rpo, fbo] = ctx->begin_rp(rp);
Texture_Vk& target = *(Texture_Vk*)&dev->get_texture(
dev->get_backbuffer()
);
@@ -1855,7 +2014,7 @@ void Context::submit(
draw.first_instance
);
}
- ctx->end_rp(rpo);
+ ctx->end_rp(rpo, fbo);
pso.on_submit();
if (dso)
dso->on_submit();
@@ -2003,33 +2162,56 @@ void Context::transition(Texture_Id id, Resource_State state) {
);
}
-Renderpass_Vk& Context_Vk::begin_rp(const Render_Pass& rp) {
+std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp(
+ const Render_Pass& rp
+) {
Renderpass_Vk& rpo = dev->get_rpo({ dev->first_rp, rp});
+ Framebuffer_Vk& fbo = dev->get_fbo(rpo, { rp });
VkRenderPassBeginInfo rpbi{};
+ VkClearValue clears[max_colour_attachments + 1];
+ int i, c = rp.colour_count, clear_count = 0;
+ bool has_depth = rp.depth.id;
+ for (i = 0; i < c; i++) {
+ VkClearValue clear{};
+ const auto& tar = rp.colours[i];
+ const auto col = tar.clear.colour;
+ clear.color.float32[0] = (float)col.r / 255.0f;
+ clear.color.float32[1] = (float)col.g / 255.0f;
+ clear.color.float32[2] = (float)col.b / 255.0f;
+ clear.color.float32[3] = (float)col.a / 255.0f;
+ clears[clear_count++] = clear;
+ }
+ if (has_depth) {
+ VkClearValue dc{};
+ dc.depthStencil.depth = rp.depth.clear.depth;
+ dc.depthStencil.stencil = 0; /* todo */
+ clears[clear_count++] = dc;
+ }
rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpbi.renderPass = rpo.rpo;
- rpbi.framebuffer = rpo.fbo;
+ rpbi.framebuffer = fbo.fbo;
rpbi.renderArea.extent = dev->swapchain.size;
- rpbi.clearValueCount = rp.mode == Clear_Mode::clear? 1: 0;
- rpbi.pClearValues = &rpo.clear;
+ rpbi.clearValueCount = clear_count;
+ rpbi.pClearValues = clears;
vkCmdBeginRenderPass(
cb,
&rpbi,
VK_SUBPASS_CONTENTS_INLINE
);
dev->first_rp = false;
- return rpo;
+ return { rpo, fbo };
}
-void Context_Vk::end_rp(Renderpass_Vk& rpo) {
+void Context_Vk::end_rp(Renderpass_Vk& rpo, Framebuffer_Vk& fbo) {
vkCmdEndRenderPass(cb);
rpo.on_submit();
+ fbo.on_submit();
}
void Context::submit(const Render_Pass& rp) {
Context_Vk* ctx = (Context_Vk*)this;
- auto& rpo = ctx->begin_rp(rp);
- ctx->end_rp(rpo);
+ auto [rpo, fbo] = ctx->begin_rp(rp);
+ ctx->end_rp(rpo, fbo);
}
void Context_Vk::init_pool() {
@@ -2305,9 +2487,9 @@ void Pipeline_Vk::init_depthstencil(
(void)desc;
zero(&ds, sizeof ds);
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- ds.depthTestEnable = VK_FALSE;
- ds.depthWriteEnable = VK_FALSE;
- ds.depthCompareOp = VK_COMPARE_OP_LESS;
+ ds.depthTestEnable = desc.depth_test;
+ ds.depthWriteEnable = desc.depth_write;
+ ds.depthCompareOp = get_compare_op(desc.depth_mode);
ds.depthBoundsTestEnable = VK_FALSE;
ds.stencilTestEnable = VK_FALSE;
info.pDepthStencilState = &ds;
@@ -2403,6 +2585,20 @@ void Pipeline_Vk::init_descriptors(
}
}
+VkCompareOp Pipeline_Vk::get_compare_op(Depth_Mode m) {
+ switch (m) {
+ case Depth_Mode::less: return VK_COMPARE_OP_LESS;
+ case Depth_Mode::less_equal: return VK_COMPARE_OP_LESS_OR_EQUAL;
+ case Depth_Mode::equal: return VK_COMPARE_OP_EQUAL;
+ case Depth_Mode::greater: return VK_COMPARE_OP_GREATER;
+ case Depth_Mode::greater_equal: return VK_COMPARE_OP_GREATER_OR_EQUAL;
+ case Depth_Mode::always: return VK_COMPARE_OP_ALWAYS;
+ case Depth_Mode::never: return VK_COMPARE_OP_NEVER;
+ }
+ assert(0);
+ return VK_COMPARE_OP_LESS;
+}
+
void Pipeline_Vk::init_layout(
Device_Vk* dev,
const Pipeline& desc
@@ -2903,6 +3099,7 @@ Buffer& Device::get_buffer(Buffer_Id id) {
Texture_Id Device::create_texture(
Texture_Format fmt,
+ int flags,
int w,
int h,
Buffer_Id init
@@ -2913,6 +3110,7 @@ Texture_Id Device::create_texture(
Texture_Id id = dev->alloc_texture();
Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id);
VkMemoryRequirements req;
+ VkImageAspectFlags aspect = get_image_aspect(flags);
tex.state = Resource_State::undefined;
ii.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
ii.imageType = VK_IMAGE_TYPE_2D;
@@ -2924,7 +3122,7 @@ Texture_Id Device::create_texture(
ii.format = get_vk_format(fmt);
ii.tiling = VK_IMAGE_TILING_OPTIMAL;
ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- ii.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ ii.usage = get_texture_usage(flags);
ii.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ii.samples = VK_SAMPLE_COUNT_1_BIT;
r = vkCreateImage(dev->dev, &ii, &dev->ac, &tex.image);
@@ -2957,12 +3155,13 @@ Texture_Id Device::create_texture(
vkBindImageMemory(dev->dev, tex.image, tex.memory, 0);
tex.w = w;
tex.h = h;
+ tex.fmt = fmt;
tex.alias = false;
tex.view = make_view(
dev,
tex.image,
ii.format,
- VK_IMAGE_ASPECT_COLOR_BIT
+ aspect
);
if (init) {
Context& ctx = dev->acquire();
@@ -3170,7 +3369,13 @@ Asset* Texture_Loader::load(Arena* a, Arena* s, Pack_File* f) {
pack_read(f, data, size);
{
Buffer_Id buf = upload(data, size);
- Texture_Id tex = dev->create_texture(fmt, w, h, buf);
+ Texture_Id tex = dev->create_texture(
+ fmt,
+ Texture_Flags::sampleable | Texture_Flags::copy_dst,
+ w,
+ h,
+ buf
+ );
dev->destroy_buffer(buf);
return &dev->get_texture(tex);
}
diff --git a/video.hpp b/video.hpp
index d524d81..fa479f1 100644
--- a/video.hpp
+++ b/video.hpp
@@ -69,11 +69,23 @@ static_assert(sizeof(Constant_Buffer_Descriptor) <= descriptor_payload_size);
#define pipeline_max_descriptors 16
+enum class Depth_Mode {
+ less,
+ less_equal,
+ equal,
+ greater,
+ greater_equal,
+ always,
+ never
+};
+
struct Pipeline {
uint64_t pipeline_hash;
uint64_t descriptor_resource_hash;
int viewport[4];
int scissor[4];
+ bool depth_test, depth_write;
+ Depth_Mode depth_mode;
Vertex_Format_Id vertex_format;
Shader_Id shader;
Descriptor descriptors[pipeline_max_descriptors];
@@ -90,7 +102,10 @@ struct Pipeline {
scissor[0] == other.scissor[0] &&
scissor[1] == other.scissor[1] &&
scissor[2] == other.scissor[2] &&
- scissor[3] == other.scissor[3];
+ scissor[3] == other.scissor[3] &&
+ depth_test == other.depth_test &&
+ depth_write == other.depth_write &&
+ depth_mode == other.depth_mode;
}
bool desc_layout_eq(const Pipeline& other) const {
@@ -148,17 +163,48 @@ struct Colour {
uint8_t r, g, b, a;
};
+#define max_colour_attachments 8
+
struct Render_Pass {
- Texture_Id target;
- Colour clear;
- Clear_Mode mode;
-
- bool operator==(const Render_Pass& other) const {
- int size = sizeof *this, i;
- uint8_t* bba = (uint8_t*)this;
- uint8_t* bbb = (uint8_t*)&other;
- for (i = 0; i < size; i++, bba++, bbb++)
- if (*bba != *bbb) return false;
+ struct Target {
+ Texture_Id id;
+ Texture_Format fmt;
+ Clear_Mode mode;
+ union {
+ Colour colour;
+ float depth;
+ } clear;
+ };
+ Target colours[max_colour_attachments];
+ int colour_count;
+ Target depth;
+ uint64_t layout_hash;
+ uint64_t resource_hash;
+
+ bool layout_eq(const Render_Pass& other) const {
+ int i, c = colour_count;
+ if (layout_hash != other.layout_hash) return false;
+ if (c != other.colour_count) return false;
+ if (depth.fmt != other.depth.fmt) return false;
+ if (depth.mode != other.depth.mode) return false;
+ for (i = 0; i < c; i++) {
+ const Target& ac = colours[i];
+ const Target& bc = other.colours[i];
+ if (ac.fmt != bc.fmt) return false;
+ if (ac.mode != bc.mode) return false;
+ }
+ return true;
+ }
+
+ bool resources_eq(const Render_Pass& other) const {
+ int i, c = colour_count;
+ if (resource_hash != other.resource_hash) return false;
+ if (!layout_eq(other)) return false;
+ for (i = 0; i < c; i++) {
+ const Target& ac = colours[i];
+ const Target& bc = other.colours[i];
+ if (ac.id != bc.id) return false;
+ }
return true;
}
};
@@ -189,18 +235,22 @@ struct Pipeline_Builder {
Arena* arena;
Render_Pass* pass;
Pipeline* pip;
+ Device* dev;
- Pipeline_Builder(Arena* arena);
+ Pipeline_Builder(Arena* arena, Device* dev);
void begin_rp();
void rp_target(Texture_Id id, Colour clear_colour);
void rp_target(Texture_Id id, Clear_Mode mode);
+ void rp_depth_target(Texture_Id id, float clear_depth);
+ void rp_depth_target(Texture_Id id, Clear_Mode mode);
Render_Pass& build_rp();
void validate_rp();
- void begin(Device* dev);
+ void begin();
void viewport(float x, float y, float w, float h);
void scissor(float x, float y, float w, float h);
+ void depth(bool test, bool write, Depth_Mode mode);
void shader(Shader_Id s);
void vertex_format(Vertex_Format_Id vf);
void texture(int binding, Texture_Id t, Sampler_Id s);
@@ -220,6 +270,7 @@ enum Resource_State {
struct Texture : public Asset {
Texture_Id id;
+ Texture_Format fmt;
int w, h;
bool alias;
};
@@ -237,6 +288,16 @@ namespace Buffer_Flags {
};
};
+namespace Texture_Flags {
+ enum {
+ sampleable = 1 << 0,
+ colour_target = 1 << 1,
+ depth_stencil_target = 1 << 2,
+ copy_src = 1 << 3,
+ copy_dst = 1 << 4
+ };
+};
+
struct Buffer {
Buffer_Id id;
};
@@ -305,11 +366,13 @@ struct Device {
Texture_Id create_texture(
Texture_Format fmt,
+ int flags,
int w,
int h,
Buffer_Id init
);
Texture_Id get_backbuffer();
+ Texture_Id get_depth_target();
Texture& get_texture(Texture_Id id);
void destroy_texture(Texture_Id id);