summaryrefslogtreecommitdiff
path: root/video.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'video.cpp')
-rw-r--r--video.cpp168
1 files changed, 118 insertions, 50 deletions
diff --git a/video.cpp b/video.cpp
index 7c88b54..6dc0ef7 100644
--- a/video.cpp
+++ b/video.cpp
@@ -200,12 +200,15 @@ static VkFormat get_vk_format(Texture_Format fmt) {
VkImageLayout state_to_image_layout(Resource_State s) {
switch (s) {
- case undefined: return VK_IMAGE_LAYOUT_UNDEFINED;
- case copy_dst: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- case copy_src: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- case shader_read: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- default: assert(0); return VK_IMAGE_LAYOUT_UNDEFINED;
+ case undefined: return VK_IMAGE_LAYOUT_UNDEFINED;
+ case copy_dst: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ case copy_src: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+ case shader_read: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ case render_target: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ case presentable: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
+ assert(0);
+ return VK_IMAGE_LAYOUT_UNDEFINED;
}
static void* vk_alloc(
@@ -501,28 +504,25 @@ struct Buffer_Vk : public Buffer, public Late_Terminated {
}
};
-struct Renderpass_Vk {
- VkRenderPass rpo;
- VkFramebuffer fbo;
- VkClearValue clear;
- int age;
+struct Rpo_Key {
+ bool is_first;
+ Render_Pass rpo;
- void on_submit() {
- age = 0;
+ bool operator==(const Rpo_Key& other) const {
+ return
+ is_first == other.is_first &&
+ rpo == other.rpo;
}
-
- void init_rp(Device_Vk* dev, const Render_Pass& rp);
- void init_fb(Device_Vk* dev, const Render_Pass& rp);
- void destroy(Device_Vk* dev);
};
struct Pso_Key {
Pipeline pso;
- Render_Pass rpo;
+ Rpo_Key rpo;
bool operator==(const Pso_Key& other) const {
return
rpo == other.rpo &&
+ pso.pipeline_eq(other.pso) &&
pso.desc_layout_eq(other.pso);
}
};
@@ -535,6 +535,23 @@ struct Dso_Key {
}
};
+struct Renderpass_Vk {
+ VkRenderPass rpo;
+ VkFramebuffer fbo;
+ VkClearValue clear;
+ int age;
+
+ void on_submit() {
+ age = 0;
+ }
+
+ 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 destroy(Device_Vk* dev);
+};
+
struct Pipeline_Vk {
VkPipeline pip;
VkPipelineLayout lay;
@@ -566,7 +583,7 @@ struct Pipeline_Vk {
Arena& scope,
Device_Vk* dev,
VkGraphicsPipelineCreateInfo& info,
- const Render_Pass& desc
+ const Pipeline& desc
);
void init_rasterisation(
Arena& scope,
@@ -646,10 +663,12 @@ struct Sampler_Vk : public Late_Terminated {
};
template<>
-struct Hash_Function<Render_Pass>
-{
- size_t operator()(const Render_Pass& rp) const {
- return (size_t)fnv1a64((uint8_t*)&rp, sizeof rp);
+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);
}
};
@@ -794,12 +813,13 @@ struct Device_Vk : public Device {
uint32_t shader_count;
uint32_t sampler_count;
- Hash_Map<Render_Pass, Renderpass_Vk, max_rpos> rpo_cache;
+ Hash_Map<Rpo_Key, Renderpass_Vk, max_rpos> rpo_cache;
Hash_Map<Pso_Key, Pipeline_Vk, max_pipelines> pso_cache;
Hash_Map<Dso_Key, Descriptor_Set_Vk, max_descriptor_sets> dso_cache;
Terminator* terminators;
uint32_t terminator_index;
+ bool first_rp;
Texture_Id alloc_texture();
Buffer_Id alloc_buffer();
@@ -820,8 +840,8 @@ struct Device_Vk : public Device {
void create_surf();
void on_resize_internal(int w, int h);
- Renderpass_Vk& create_rpo(const Render_Pass& rp);
- Renderpass_Vk& get_rpo(const Render_Pass& rp);
+ Renderpass_Vk& create_rpo(const Rpo_Key& rp);
+ Renderpass_Vk& get_rpo(const Rpo_Key& rp);
Pipeline_Vk& create_pso(const Pso_Key& pip);
Pipeline_Vk& get_pso(const Pso_Key& pop);
Descriptor_Set_Vk& create_dso(
@@ -1168,12 +1188,12 @@ void Device_Vk::init_internal() {
create_dev(&swap_cap);
gladLoaderLoadVulkan(inst, phys_dev, dev);
vkGetDeviceQueue(dev, (uint32_t)queue_index, 0, &queue);
- swapchain.init(*app, this);
terminators = 0;
terminator_index = 0;
- create_terminators();
for (i = 0; i < max_contexts; i++)
contexts[i].state = context_state_avail;
+ swapchain.init(*app, this);
+ create_terminators();
}
void Device_Vk::create_terminators() {
@@ -1233,21 +1253,22 @@ void Device_Vk::on_resize_internal(int w, int h) {
create_terminators();
}
-Renderpass_Vk& Device_Vk::create_rpo(const Render_Pass& rp) {
+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, rp);
+ rpo.init_rp(this, k);
rpo.init_fb(this, rp);
rpo.age = 0;
rpo.clear = clear;
- return rpo_cache.set(rp, rpo);
+ return rpo_cache.set(k, rpo);
}
-Renderpass_Vk& Device_Vk::get_rpo(const Render_Pass& rp) {
+Renderpass_Vk& Device_Vk::get_rpo(const Rpo_Key& rp) {
Renderpass_Vk* rpo = rpo_cache.get(rp);
if (!rpo)
return create_rpo(rp);
@@ -1340,25 +1361,40 @@ int Device_Vk::find_memory_type(
return -1;
}
+VkAttachmentLoadOp Renderpass_Vk::load_op_from_mode(
+ Clear_Mode m
+) {
+ switch (m) {
+ case Clear_Mode::discard: return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ case Clear_Mode::clear: return VK_ATTACHMENT_LOAD_OP_CLEAR;
+ case Clear_Mode::restore: return VK_ATTACHMENT_LOAD_OP_LOAD;
+ }
+ assert(0);
+ return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+}
+
void Renderpass_Vk::init_rp(
Device_Vk* dev,
- const Render_Pass& rp
+ const Rpo_Key& rpk
) {
VkRenderPassCreateInfo ri{};
VkAttachmentDescription ad{};
VkAttachmentReference ar{};
VkSubpassDescription sd{};
VkResult r;
- (void)rp;
+ auto& rp = rpk.rpo;
ad.format = dev->swapchain.format.format;
ad.samples = VK_SAMPLE_COUNT_1_BIT;
- ad.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ 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;
- ad.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- ad.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ 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;
@@ -1527,6 +1563,7 @@ void Swapchain::get_images(Device_Vk* dev) {
int i;
VkImage* images;
vkGetSwapchainImagesKHR(dev->dev, swapchain, &count, 0);
+ Context& ctx = dev->acquire();
image_count = count;
images = (VkImage*)heap_alloc(
dev->heap,
@@ -1550,7 +1587,11 @@ void Swapchain::get_images(Device_Vk* dev) {
size.width,
size.height
);
+ /* needs to be presentable since the first renderpass
+ * will expect it to be presentable from "last" frame */
+ ctx.transition(textures[i], Resource_State::presentable);
}
+ dev->submit(ctx);
heap_free(dev->heap, images);
}
@@ -1604,6 +1645,7 @@ void Device::begin_frame() {
&dev->backbuffer_index
);
dev->backbuffer_id = dev->swapchain.textures[dev->backbuffer_index];
+ dev->first_rp = true;
}
void Device::submit(Context& ctx_) {
@@ -1631,6 +1673,10 @@ void Device::present() {
VkSubmitInfo si{};
VkPipelineStageFlags stage =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ ctx->transition(
+ dev->get_backbuffer(),
+ Resource_State::presentable
+ );
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
si.waitSemaphoreCount = 1;
si.pWaitSemaphores = &ctx->semaphore;
@@ -1735,10 +1781,15 @@ void Context::submit(
Context_Vk* ctx = (Context_Vk*)this;
Device_Vk* dev = ctx->dev;
Vertex_Buffer_Binding* binding;
- Pso_Key pso_key = { p, rp };
+ Rpo_Key rpo_key = { dev->first_rp, rp };
+ Pso_Key pso_key = { p, rpo_key };
Pipeline_Vk& pso = dev->get_pso(pso_key);
Descriptor_Set_Vk& dso = dev->get_dso(pso, *(Dso_Key*)&p);
auto& rpo = ctx->begin_rp(rp);
+ Texture_Vk& target = *(Texture_Vk*)&dev->get_texture(
+ dev->get_backbuffer()
+ );
+ target.state = Resource_State::render_target;
vkCmdBindPipeline(
ctx->cb,
VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -1835,6 +1886,7 @@ void Context::transition(Texture_Id id, Resource_State state) {
VkImageLayout src_layout = state_to_image_layout(tex.state);
VkImageLayout dst_layout = state_to_image_layout(state);
VkPipelineStageFlags src_stage, dst_stage;
+ tex.state = state;
b.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
b.oldLayout = src_layout;
b.newLayout = dst_layout;
@@ -1878,6 +1930,22 @@ void Context::transition(Texture_Id id, Resource_State state) {
b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else if (
+ src_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL &&
+ dst_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
+ ) {
+ b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ b.dstAccessMask = 0;
+ src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ } else if (
+ src_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
+ dst_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
+ ) {
+ b.srcAccessMask = 0;
+ b.dstAccessMask = 0;
+ src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ dst_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
} else {
print_err("Bad resource transition.\n");
pbreak(389);
@@ -1897,19 +1965,20 @@ void Context::transition(Texture_Id id, Resource_State state) {
}
Renderpass_Vk& Context_Vk::begin_rp(const Render_Pass& rp) {
- Renderpass_Vk& rpo = dev->get_rpo(rp);
+ Renderpass_Vk& rpo = dev->get_rpo({ dev->first_rp, rp});
VkRenderPassBeginInfo rpbi{};
rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpbi.renderPass = rpo.rpo;
rpbi.framebuffer = rpo.fbo;
rpbi.renderArea.extent = dev->swapchain.size;
- rpbi.clearValueCount = 1;
+ rpbi.clearValueCount = rp.mode == Clear_Mode::clear? 1: 0;
rpbi.pClearValues = &rpo.clear;
vkCmdBeginRenderPass(
cb,
&rpbi,
VK_SUBPASS_CONTENTS_INLINE
);
+ dev->first_rp = false;
return rpo;
}
@@ -2102,9 +2171,8 @@ void Pipeline_Vk::init_viewport(
Arena& scope,
Device_Vk* dev,
VkGraphicsPipelineCreateInfo& info,
- const Render_Pass& desc
+ const Pipeline& desc
) {
- Texture& texture = dev->get_texture(desc.target);
VkPipelineViewportStateCreateInfo& vi =
*(VkPipelineViewportStateCreateInfo*)arena_alloc(
&scope,
@@ -2121,14 +2189,14 @@ void Pipeline_Vk::init_viewport(
memset(&vi, 0, sizeof vi);
memset(&scissor, 0, sizeof scissor);
memset(&viewport, 0, sizeof viewport);
- scissor.offset.x = 0;
- scissor.offset.y = 0;
- scissor.extent.width = texture.w;
- scissor.extent.height = texture.h;
- viewport.x = 0;
- viewport.y = 0;
- viewport.width = texture.w;
- viewport.height = texture.h;
+ scissor.offset.x = desc.scissor[0];
+ scissor.offset.y = desc.scissor[1];
+ scissor.extent.width = desc.scissor[2];
+ scissor.extent.height = desc.scissor[3];
+ viewport.x = desc.viewport[0];
+ viewport.y = desc.viewport[1];
+ viewport.width = desc.viewport[2];
+ viewport.height = desc.viewport[3];
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
@@ -2335,7 +2403,7 @@ void Pipeline_Vk::init(Device_Vk* dev, const Pso_Key& key) {
init_stages(scope, dev, info, desc);
init_vertex_input(scope, dev, info, desc);
init_input_assembly(scope, dev, info, desc);
- init_viewport(scope, dev, info, key.rpo);
+ init_viewport(scope, dev, info, desc);
init_rasterisation(scope, dev, info, desc);
init_msaa(scope, dev, info, desc);
init_depthstencil(scope, dev, info, desc);