Omg, I just deleted all the crap I wrote 12.02. I made static resource transfer SO MUCH EASIER. But in exchange for simplicity, the rules for when you can acreate and ddelete meshes and font faces are ultra-convoluted. Because I removed all the deletions©ing queues. Everything is super-low-level now
This commit is contained in:
parent
b05c64a131
commit
248b81f2ec
@ -26,4 +26,7 @@ void generate_margaret_eve_for_vulkan_utils() {
|
||||
|
||||
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("MargaretImgAllocatorOneBlock"), true, false);
|
||||
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){.T = cstr("MargaretBufAllocatorOneBlock")}, true);
|
||||
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("MargaretSubbuf"),
|
||||
cstr("#include \"../../../src/l2/margaret/vulkan_utils.h\"\n"), true, false);
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ NODISCARD VecU8 generate_List_template_instantiation(list_instantiation_op op, b
|
||||
"} List%s;\n\n", /* op.T */
|
||||
op.T, op.T);
|
||||
VecU8_append_fmt(&res,
|
||||
"#define List%s_new() {0}\n\n" /* op.T */
|
||||
"#define List%s_new() ((List%s){0})\n\n" /* op.T, op.T */
|
||||
"void List%s_drop(List%s self) {\n" /* op.T, op.T */
|
||||
SPACE "ListNode%s* cur = self.first;\n" /* op.T */
|
||||
SPACE "while (cur){\n"
|
||||
@ -40,7 +40,7 @@ NODISCARD VecU8 generate_List_template_instantiation(list_instantiation_op op, b
|
||||
SPACE SPACE "cur = next;\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n",
|
||||
op.T, op.T, op.T, op.T, op.T,
|
||||
op.T, op.T, op.T, op.T, op.T, op.T,
|
||||
op.t_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE "%s_drop(cur->el);\n", op.T));
|
||||
VecU8_append_fmt(&res,
|
||||
"ListNode%s* List%s_insert(List%s* self, %s el) {\n" /* op.T, op.T, op.T, op.T */
|
||||
|
||||
@ -6,12 +6,6 @@
|
||||
#include "transfer_in_mainloop.h"
|
||||
#include "../lucy/glyph_render.h"
|
||||
|
||||
typedef struct {
|
||||
U64 count;
|
||||
MargaretSubbuf staging;
|
||||
MargaretSubbuf device_local;
|
||||
} PatriciaBuf;
|
||||
|
||||
typedef struct {
|
||||
/* Each generic model has its own descriptor set
|
||||
* It's because it has its own textures. But it also has copies of references to light UBO
|
||||
@ -27,30 +21,25 @@ typedef struct {
|
||||
TextureDataR8G8B8A8 pixels_normal;
|
||||
TextureDataR8 pixels_specular;
|
||||
|
||||
AliceBufferUplOnce* vbo;
|
||||
AliceBufferUplOnce* ebo;
|
||||
MargaretSubbuf vbo;
|
||||
MargaretSubbuf ebo;
|
||||
|
||||
AliceTextureUplOnce* diffuse_texture;
|
||||
AliceTextureUplOnce* normal_texture;
|
||||
AliceTextureUplOnce* specular_texture;
|
||||
MargaretTexture diffuse_texture;
|
||||
MargaretTexture normal_texture;
|
||||
MargaretTexture specular_texture;
|
||||
|
||||
PatriciaBuf instance_attr;
|
||||
|
||||
AliceGenericMeshMemDependantVkObj mem_dependant_vk_obj;
|
||||
|
||||
bool scheduled_for_deletion;
|
||||
} AliceGenericMeshHand;
|
||||
|
||||
#include "../../../gen/l1/eve/alice/ListAliceGenericMeshHand.h"
|
||||
|
||||
typedef struct {
|
||||
size_t indexes;
|
||||
|
||||
AliceBufferUplOnce* vbo;
|
||||
AliceBufferUplOnce* ebo;
|
||||
MargaretSubbuf vbo;
|
||||
MargaretSubbuf ebo;
|
||||
PatriciaBuf instance_attr;
|
||||
|
||||
bool scheduled_for_deletion;
|
||||
} AliceShinyMeshHand;
|
||||
|
||||
#include "../../../gen/l1/eve/alice/ListAliceShinyMeshHand.h"
|
||||
@ -712,34 +701,9 @@ float AliceWaylandApp_get_elapsed_time(const AliceWaylandApp* self){
|
||||
typedef struct ListNodeAliceGenericMeshHand* RefListNodeAliceGenericMeshHand;
|
||||
#include "../../../gen/l1/eve/alice/VecRefListNodeAliceGenericMeshHand.h"
|
||||
|
||||
typedef struct {
|
||||
ListAliceGenericMeshHand hands;
|
||||
VecRefListNodeAliceGenericMeshHand to_be_deleted;
|
||||
} AliceAllMeshesGeneric;
|
||||
|
||||
AliceAllMeshesGeneric AliceAllMeshesGeneric_new(){
|
||||
return (AliceAllMeshesGeneric){
|
||||
.hands = ListAliceGenericMeshHand_new(),
|
||||
.to_be_deleted = VecRefListNodeAliceGenericMeshHand_new(),
|
||||
};
|
||||
}
|
||||
|
||||
typedef struct ListNodeAliceShinyMeshHand* RefListNodeAliceShinyMeshHand;
|
||||
#include "../../../gen/l1/eve/alice/VecRefListNodeAliceShinyMeshHand.h"
|
||||
|
||||
typedef struct {
|
||||
ListAliceShinyMeshHand hands;
|
||||
/* Ah */
|
||||
VecRefListNodeAliceShinyMeshHand to_be_deleted;
|
||||
} AliceAllMeshesShiny;
|
||||
|
||||
AliceAllMeshesShiny AliceAllMeshesShiny_new(){
|
||||
return (AliceAllMeshesShiny){
|
||||
.hands = ListAliceShinyMeshHand_new(),
|
||||
.to_be_deleted = VecRefListNodeAliceShinyMeshHand_new(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct Alice {
|
||||
AliceCallbacks callbacks;
|
||||
@ -780,12 +744,11 @@ struct Alice {
|
||||
Jane_alice jane; // todo: figure out my own design
|
||||
MargaretSwapchainBundle swfb;
|
||||
|
||||
AliceAllSingleUploadBuffers single_upload_buffers;
|
||||
AliceAllSingleUploadTextures single_upload_textures;
|
||||
Abigail abigail;
|
||||
|
||||
AlicePipline0LightConf pipeline0_light_conf;
|
||||
AliceAllMeshesGeneric generic_models;
|
||||
AliceAllMeshesShiny shiny_models;
|
||||
ListAliceGenericMeshHand generic_models;
|
||||
ListAliceShinyMeshHand shiny_models;
|
||||
AliceCamVerticalControl cam_info;
|
||||
/* stuff like background color, hdr factor and
|
||||
* postprocessing kernel. Mostly related to renderpass 1 */
|
||||
@ -803,6 +766,13 @@ struct Alice {
|
||||
VkFramebuffer IT1_framebuffer;
|
||||
VkDescriptorSet descriptor_set_for_pipeline_0;
|
||||
VkDescriptorSet descriptor_set_for_pipeline_1;
|
||||
|
||||
/* You see, there are two places when user can write to transfer_command_buffer: When Alice is initialized, but
|
||||
* the very first frame was not sent in flight, and when we are in a gap between two frames in flight.
|
||||
* transfer_command_buffer is immediately opened for writing on input, and won't be re-began on the first frame.
|
||||
* But on the subsequent frames it will be reste and bagan-for-writing after we done waiting for in-flight fence
|
||||
*/
|
||||
bool transfer_command_buf_already_reset;
|
||||
};
|
||||
|
||||
ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const GenericMeshTopology* topology,
|
||||
@ -824,36 +794,43 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
|
||||
VecU8_drop(t_paths.normal_texture_path);
|
||||
VecU8_drop(t_paths.specular_texture_path);
|
||||
|
||||
mm->vbo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers,
|
||||
GenericMeshVertex* staging_vbo;
|
||||
mm->vbo = Abigail_register_new_buffer(&alice->abigail,
|
||||
topology->vertices.len * sizeof(GenericMeshVertex),
|
||||
&alice->staging_buffers, &alice->dev_local_buffers);
|
||||
mm->ebo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers,
|
||||
topology->indexes.len * sizeof(U32),
|
||||
&alice->staging_buffers, &alice->dev_local_buffers);
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
|
||||
(void**)&staging_vbo /* We return values here */);
|
||||
|
||||
mm->diffuse_texture = AliceAllSingleUploadTextures_register_new(&alice->single_upload_textures,
|
||||
U32* staging_ebo;
|
||||
mm->ebo = Abigail_register_new_buffer(&alice->abigail,
|
||||
topology->indexes.len * sizeof(U32),
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
|
||||
(void**)&staging_ebo /* We return values here */);
|
||||
|
||||
void* diffuse_tex_staging;
|
||||
mm->diffuse_texture = Abigail_register_new_texture(&alice->abigail,
|
||||
mm->pixels_diffuse.width, mm->pixels_diffuse.height,
|
||||
sizeof(cvec4), VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
&alice->staging_buffers, &alice->dev_local_images);
|
||||
mm->normal_texture = AliceAllSingleUploadTextures_register_new(&alice->single_upload_textures,
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images,
|
||||
&diffuse_tex_staging);
|
||||
void *normal_tex_staging;
|
||||
mm->normal_texture = Abigail_register_new_texture(&alice->abigail,
|
||||
mm->pixels_normal.width, mm->pixels_normal.height,
|
||||
sizeof(cvec4), VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
&alice->staging_buffers, &alice->dev_local_images);
|
||||
mm->specular_texture = AliceAllSingleUploadTextures_register_new(&alice->single_upload_textures,
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images,
|
||||
&normal_tex_staging);
|
||||
void* specular_tex_staging;
|
||||
mm->specular_texture = Abigail_register_new_texture(&alice->abigail,
|
||||
mm->pixels_specular.width, mm->pixels_specular.height,
|
||||
sizeof(U8), VK_FORMAT_R8_UNORM,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
&alice->staging_buffers, &alice->dev_local_images);
|
||||
|
||||
mm->scheduled_for_deletion = false;
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_images,
|
||||
&specular_tex_staging);
|
||||
|
||||
assert(mm->vbo.len >= topology->vertices.len * sizeof(GenericMeshVertex));
|
||||
/* We allocated enough memory, but now it's time to actually fill staging buffers */
|
||||
/* Filling staging VBO */
|
||||
assert(mm->vbo->staging.len >= topology->vertices.len * sizeof(GenericMeshVertex));
|
||||
assert(mm->vbo->device_buf.len >= topology->vertices.len * sizeof(GenericMeshVertex));
|
||||
GenericMeshVertex* staging_vbo = (GenericMeshVertex*)AliceBufferUplOnce_get_mapped_staging(mm->vbo);
|
||||
for (U64 i = 0; i < topology->vertices.len; i++) {
|
||||
staging_vbo[i].base = topology->vertices.buf[i];
|
||||
}
|
||||
@ -883,16 +860,14 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
|
||||
/* Filling EBO is easy */
|
||||
assert(topology->indexes.len == mm->indexes);
|
||||
size_t ebo_len = topology->indexes.len * sizeof(U32);
|
||||
assert(mm->ebo->staging.len >= ebo_len);
|
||||
U32* staging_ebo = (U32*)AliceBufferUplOnce_get_mapped_staging(mm->ebo);
|
||||
memcpy(staging_ebo, topology->indexes.buf, ebo_len);
|
||||
/* Filling staging textures from memory pixel data */
|
||||
/* todo: do it immediately ON THE READ */
|
||||
memcpy(AliceTextureUplOnce_get_mapped_staging(mm->diffuse_texture), mm->pixels_diffuse.pixels.buf,
|
||||
TextureDataR8G8B8A8_get_size_in_bytes(&mm->pixels_diffuse));
|
||||
memcpy(AliceTextureUplOnce_get_mapped_staging(mm->normal_texture), mm->pixels_normal.pixels.buf,
|
||||
memcpy(diffuse_tex_staging, mm->pixels_diffuse.pixels.buf,
|
||||
TextureDataR8G8B8A8_get_size_in_bytes(&mm->pixels_diffuse));
|
||||
memcpy(normal_tex_staging, mm->pixels_normal.pixels.buf,
|
||||
TextureDataR8G8B8A8_get_size_in_bytes(&mm->pixels_normal));
|
||||
memcpy(AliceTextureUplOnce_get_mapped_staging(mm->specular_texture), mm->pixels_specular.pixels.buf,
|
||||
memcpy(specular_tex_staging, mm->pixels_specular.pixels.buf,
|
||||
TextureDataR8_get_size_in_bytes(&mm->pixels_specular));
|
||||
// todo: that is about time when we can delete mm->pixels_* buffers. They are still wasting space out there
|
||||
// todo: BUt I won't do it, because I chose inplace texture reading (from png)
|
||||
@ -913,7 +888,7 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = alice->linear_sampler, .imageView = mm->diffuse_texture->view,
|
||||
.sampler = alice->linear_sampler, .imageView = mm->diffuse_texture.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
},
|
||||
},
|
||||
@ -925,7 +900,7 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = alice->nearest_sampler, .imageView = mm->normal_texture->view,
|
||||
.sampler = alice->nearest_sampler, .imageView = mm->normal_texture.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
},
|
||||
},
|
||||
@ -937,14 +912,14 @@ ListNodeAliceGenericMeshHand* Alice_add_generic_mesh(Alice* alice, const Generic
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = alice->nearest_sampler, .imageView = mm->specular_texture->view,
|
||||
.sampler = alice->nearest_sampler, .imageView = mm->specular_texture.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
},
|
||||
},
|
||||
};
|
||||
vkUpdateDescriptorSets(alice->device, ARRAY_SIZE(writes_in_descriptor_set), writes_in_descriptor_set, 0, NULL);
|
||||
|
||||
ListAliceGenericMeshHand_insert_node(&alice->generic_models.hands, mm_node);
|
||||
ListAliceGenericMeshHand_insert_node(&alice->generic_models, mm_node);
|
||||
return mm_node;
|
||||
}
|
||||
|
||||
@ -958,18 +933,21 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo
|
||||
mm->instance_attr.staging = MargaretBufAllocator_alloc(&alice->staging_buffers, 128);
|
||||
mm->instance_attr.device_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, 128);
|
||||
|
||||
mm->vbo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers,
|
||||
ShinyMeshVertex* staging_vbo;
|
||||
mm->vbo = Abigail_register_new_buffer(&alice->abigail,
|
||||
topology->vertices.len * sizeof(ShinyMeshVertex),
|
||||
&alice->staging_buffers, &alice->dev_local_buffers);
|
||||
mm->ebo = AliceAllSingleUploadBuffers_register_new(&alice->single_upload_buffers,
|
||||
topology->indexes.len * sizeof(U32),
|
||||
&alice->staging_buffers, &alice->dev_local_buffers);
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
|
||||
(void**)&staging_vbo);
|
||||
|
||||
U32* staging_ebo;
|
||||
mm->ebo = Abigail_register_new_buffer(&alice->abigail,
|
||||
topology->indexes.len * sizeof(U32),
|
||||
alice->transfer_command_buf, &alice->staging_buffers, &alice->dev_local_buffers,
|
||||
(void**)&staging_ebo);
|
||||
|
||||
assert(mm->vbo.len >= topology->vertices.len * sizeof(ShinyMeshVertex));
|
||||
/* We allocated enough memory, now it's time to actually fill staging buffers */
|
||||
/* And we start by filling staging VBO */
|
||||
assert(mm->vbo->staging.len >= topology->vertices.len * sizeof(ShinyMeshVertex));
|
||||
assert(mm->vbo->device_buf.len >= topology->vertices.len * sizeof(ShinyMeshVertex));
|
||||
ShinyMeshVertex* staging_vbo = (ShinyMeshVertex*)AliceBufferUplOnce_get_mapped_staging(mm->vbo);
|
||||
for (U64 i = 0; i < topology->vertices.len; i++) {
|
||||
staging_vbo[i].base = topology->vertices.buf[i];
|
||||
}
|
||||
@ -988,31 +966,38 @@ ListNodeAliceShinyMeshHand* Alice_add_shiny_mesh(Alice* alice, const ShinyMeshTo
|
||||
/* Filling staging EBO is super-duper easy */
|
||||
assert(topology->indexes.len == mm->indexes);
|
||||
size_t ebo_len = topology->indexes.len * sizeof(U32);
|
||||
assert(mm->ebo->staging.len >= ebo_len);
|
||||
U32* staging_ebo = (U32*)AliceBufferUplOnce_get_mapped_staging(mm->ebo);
|
||||
memcpy(staging_ebo, topology->indexes.buf, ebo_len);
|
||||
|
||||
ListAliceShinyMeshHand_insert_node(&alice->shiny_models.hands, mm_node);
|
||||
ListAliceShinyMeshHand_insert_node(&alice->shiny_models, mm_node);
|
||||
return mm_node;
|
||||
}
|
||||
|
||||
|
||||
// todo: write deletion after I separate textures from Meshes
|
||||
void Alice_delete_generic_mesh(Alice* alice, ListNodeAliceGenericMeshHand* hand) {
|
||||
AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.vbo);
|
||||
AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.ebo);
|
||||
AliceAllSingleUploadTextures_delete(&alice->single_upload_textures, hand->el.diffuse_texture);
|
||||
AliceAllSingleUploadTextures_delete(&alice->single_upload_textures, hand->el.normal_texture);
|
||||
AliceAllSingleUploadTextures_delete(&alice->single_upload_textures, hand->el.specular_texture);
|
||||
hand->el.normal_texture = hand->el.normal_texture = hand->el.specular_texture = NULL;
|
||||
hand->el.vbo = hand->el.ebo = NULL;
|
||||
VecRefListNodeAliceGenericMeshHand_append(&alice->generic_models.to_be_deleted, hand);
|
||||
AliceGenericMeshHand* mm = &hand->el;
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->vbo);
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->ebo);
|
||||
MargaretImgAllocator_free(&alice->dev_local_images, mm->diffuse_texture.img.a);
|
||||
MargaretImgAllocator_free(&alice->dev_local_images, mm->normal_texture.img.a);
|
||||
MargaretImgAllocator_free(&alice->dev_local_images, mm->specular_texture.img.a);
|
||||
|
||||
MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging);
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local);
|
||||
// todo: the problem is, here we don't free some memory stored in AliceGenericMeshHand to store texture.
|
||||
// todo: but the truth is: I am gonna get rid of pixels_{,,} fields very soon, so AliceGenericMeshHand would
|
||||
// todo: be primitive again, without stupid crap
|
||||
ListAliceGenericMeshHand_erase_by_it(&alice->generic_models, hand);
|
||||
}
|
||||
|
||||
/* Be careful to only delete meshes when you actually allowed to do so */
|
||||
void Alice_delete_shiny_mesh(Alice* alice, ListNodeAliceShinyMeshHand* hand) {
|
||||
AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.vbo);
|
||||
AliceAllSingleUploadBuffers_delete(&alice->single_upload_buffers, hand->el.ebo);
|
||||
hand->el.vbo = hand->el.ebo = NULL;
|
||||
VecRefListNodeAliceShinyMeshHand_append(&alice->shiny_models.to_be_deleted, hand);
|
||||
AliceShinyMeshHand* mm = &hand->el;
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, hand->el.vbo);
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, hand->el.ebo);
|
||||
|
||||
MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging);
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local);
|
||||
ListAliceShinyMeshHand_erase_by_it(&alice->shiny_models, hand);
|
||||
}
|
||||
|
||||
|
||||
@ -1058,37 +1043,6 @@ void AliceShinyMeshHand_set_inst(AliceShinyMeshHand* self, size_t instance, Shin
|
||||
tr_inv.x.z, tr_inv.y.z, tr_inv.z.z );
|
||||
}
|
||||
|
||||
void AliceAllMeshesGeneric__resolve_on_another_frame(Alice* alice, AliceAllMeshesGeneric* self){
|
||||
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
|
||||
ListNodeAliceGenericMeshHand* mm_node = self->to_be_deleted.buf[i];
|
||||
AliceGenericMeshHand* mm = &mm_node->el;
|
||||
assert(mm->scheduled_for_deletion);
|
||||
assert(mm->vbo == NULL);
|
||||
assert(mm->ebo == NULL);
|
||||
MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging);
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local);
|
||||
// todo: the problem is, here we don't free some memory stored in AliceGenericMeshHand to store texture.
|
||||
// todo: but the truth is: I am gonna get rid of pixels_{,,} fields very soon, so AliceGenericMeshHand would
|
||||
// todo: be primitive again, without stupid crap
|
||||
ListAliceGenericMeshHand_erase_by_it(&self->hands, mm_node);
|
||||
}
|
||||
self->to_be_deleted.len = 0;
|
||||
}
|
||||
|
||||
void AliceAllMeshesShiny__resolve_on_another_frame(Alice* alice, AliceAllMeshesShiny* self){
|
||||
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
|
||||
ListNodeAliceShinyMeshHand* mm_node = self->to_be_deleted.buf[i];
|
||||
AliceShinyMeshHand* mm = &mm_node->el;
|
||||
assert(mm->scheduled_for_deletion);
|
||||
assert(mm->vbo == NULL);
|
||||
assert(mm->ebo == NULL);
|
||||
MargaretBufAllocator_free(&alice->staging_buffers, mm->instance_attr.staging);
|
||||
MargaretBufAllocator_free(&alice->dev_local_buffers, mm->instance_attr.device_local);
|
||||
ListAliceShinyMeshHand_erase_by_it(&self->hands, mm_node);
|
||||
}
|
||||
self->to_be_deleted.len = 0;
|
||||
}
|
||||
|
||||
/* No buffer rerecording, no buffer beginning, no buffer ending,
|
||||
* 1) It copies initial generic model and shiny model topology. Textures of generic models included
|
||||
* 2) For all models and for all light sources it copies EVERYTHING.
|
||||
@ -1096,10 +1050,8 @@ void AliceAllMeshesShiny__resolve_on_another_frame(Alice* alice, AliceAllMeshesS
|
||||
* 3) As mentioned before, Pipeline0UBO also gets copied
|
||||
*/
|
||||
void AliceScene__another_frame(Alice* alice) {
|
||||
AliceAllMeshesGeneric__resolve_on_another_frame(alice, &alice->generic_models);
|
||||
AliceAllMeshesShiny__resolve_on_another_frame(alice, &alice->shiny_models);
|
||||
|
||||
for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.hands.first; mm_node; mm_node = mm_node->next) {
|
||||
for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.first; mm_node; mm_node = mm_node->next) {
|
||||
AliceGenericMeshHand* mm = &mm_node->el;
|
||||
assert(mm->instance_attr.count * sizeof(GenericMeshInstance) <= mm->instance_attr.staging.len);
|
||||
if (mm->instance_attr.count * sizeof(GenericMeshInstance) > mm->instance_attr.device_local.len) {
|
||||
@ -1113,7 +1065,7 @@ void AliceScene__another_frame(Alice* alice) {
|
||||
mm->instance_attr.count * sizeof(GenericMeshInstance));
|
||||
}
|
||||
}
|
||||
for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.hands.first; mm_node; mm_node = mm_node->next) {
|
||||
for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.first; mm_node; mm_node = mm_node->next) {
|
||||
AliceShinyMeshHand* mm = &mm_node->el;
|
||||
assert(mm->instance_attr.count * sizeof(ShinyMeshInstance) <= mm->instance_attr.staging.len);
|
||||
if (mm->instance_attr.count * sizeof(ShinyMeshInstance) > mm->instance_attr.device_local.len) {
|
||||
@ -1187,21 +1139,19 @@ void alice_reset_and_record_command_buffer_0(Alice* alice, mat4 proj_cam_t) {
|
||||
alice->rendering_command_buf_0, VK_PIPELINE_BIND_POINT_GRAPHICS, alice->pipeline_hands_0a.pipeline_layout,
|
||||
0, 1, &alice->descriptor_set_for_pipeline_0, 0, NULL);
|
||||
|
||||
for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.hands.first; mm_node; mm_node = mm_node->next) {
|
||||
for (ListNodeAliceGenericMeshHand* mm_node = alice->generic_models.first; mm_node; mm_node = mm_node->next) {
|
||||
AliceGenericMeshHand* model = &mm_node->el;
|
||||
VkDescriptorSet descriptor_set1_for_textures = model->mem_dependant_vk_obj.p_0a_set_1;
|
||||
|
||||
const MargaretSubbuf* dev_local_vbo = &model->vbo->device_buf;
|
||||
const MargaretSubbuf* dev_local_inst_attr = &model->instance_attr.device_local;
|
||||
const MargaretSubbuf* dev_local_ebo = &model->ebo->device_buf;
|
||||
// const
|
||||
|
||||
vkCmdBindVertexBuffers(alice->rendering_command_buf_0, 0,
|
||||
2, (VkBuffer[]){
|
||||
MargaretSubbuf_get_buffer(dev_local_vbo),
|
||||
MargaretSubbuf_get_buffer(&model->vbo),
|
||||
MargaretSubbuf_get_buffer(dev_local_inst_attr),
|
||||
}, (VkDeviceSize[]){ dev_local_vbo->start, dev_local_inst_attr->start });
|
||||
vkCmdBindIndexBuffer(alice->rendering_command_buf_0, MargaretSubbuf_get_buffer(dev_local_ebo), dev_local_ebo->start,
|
||||
VK_INDEX_TYPE_UINT32);
|
||||
}, (VkDeviceSize[]){ model->vbo.start, dev_local_inst_attr->start });
|
||||
vkCmdBindIndexBuffer(alice->rendering_command_buf_0,
|
||||
MargaretSubbuf_get_buffer(&model->ebo), model->ebo.start, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdBindDescriptorSets(
|
||||
alice->rendering_command_buf_0, VK_PIPELINE_BIND_POINT_GRAPHICS, alice->pipeline_hands_0a.pipeline_layout,
|
||||
1, 1, &descriptor_set1_for_textures, 0, NULL);
|
||||
@ -1218,16 +1168,14 @@ void alice_reset_and_record_command_buffer_0(Alice* alice, mat4 proj_cam_t) {
|
||||
alice->rendering_command_buf_0, VK_PIPELINE_BIND_POINT_GRAPHICS, alice->pipeline_hands_0b.pipeline_layout,
|
||||
0, 1, &alice->descriptor_set_for_pipeline_0, 0, NULL);
|
||||
|
||||
for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.hands.first; mm_node; mm_node = mm_node->next) {
|
||||
for (ListNodeAliceShinyMeshHand* mm_node = alice->shiny_models.first; mm_node; mm_node = mm_node->next) {
|
||||
const AliceShinyMeshHand* model = &mm_node->el;
|
||||
const MargaretSubbuf* dev_local_vbo = &model->vbo->device_buf;
|
||||
const MargaretSubbuf* dev_local_inst_attr = &model->instance_attr.device_local;
|
||||
const MargaretSubbuf* dev_local_ebo = &model->ebo->device_buf;
|
||||
vkCmdBindVertexBuffers(alice->rendering_command_buf_0, 0, 2, (VkBuffer[]){
|
||||
MargaretSubbuf_get_buffer(dev_local_vbo), MargaretSubbuf_get_buffer(dev_local_inst_attr)
|
||||
}, (VkDeviceSize[]){ dev_local_vbo->start, dev_local_inst_attr->start });
|
||||
vkCmdBindIndexBuffer(alice->rendering_command_buf_0, MargaretSubbuf_get_buffer(dev_local_ebo), dev_local_ebo->start,
|
||||
VK_INDEX_TYPE_UINT32);
|
||||
MargaretSubbuf_get_buffer(&model->vbo), MargaretSubbuf_get_buffer(dev_local_inst_attr)
|
||||
}, (VkDeviceSize[]){ model->vbo.start, dev_local_inst_attr->start });
|
||||
vkCmdBindIndexBuffer(alice->rendering_command_buf_0,
|
||||
MargaretSubbuf_get_buffer(&model->ebo), model->ebo.start, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(alice->rendering_command_buf_0, model->indexes, model->instance_attr.count, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ -1398,20 +1346,19 @@ void alice_frame_drawing(Alice* alice) {
|
||||
mat4 camera_translation_matrix = marie_translation_mat4(vec3_minus(alice->cam_info.cam.pos));
|
||||
mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix));
|
||||
|
||||
if (!alice->transfer_command_buf_already_reset) {
|
||||
Abigail_wipe_old_staging(&alice->abigail, alice->device, &alice->staging_buffers);
|
||||
margaret_reset_and_begin_command_buffer(alice->transfer_command_buf);
|
||||
} else {
|
||||
alice->transfer_command_buf_already_reset = false;
|
||||
}
|
||||
|
||||
alice->callbacks.on_another_frame(alice->guest, (float)(alice->wl.cur_frame_time - alice->wl.last_frame_time) / 1000);
|
||||
|
||||
margaret_reset_and_begin_command_buffer(alice->transfer_command_buf);
|
||||
|
||||
/* Literally everything, including lucy cache, depends on these two steps */
|
||||
AliceAllSingleUploadBuffers__resolve_on_another_frame(&alice->single_upload_buffers,
|
||||
&alice->staging_buffers, &alice->dev_local_buffers, alice->transfer_command_buf);
|
||||
AliceAllSingleUploadTextures__resolve_on_another_frame(&alice->single_upload_textures,
|
||||
&alice->staging_buffers, &alice->dev_local_images, alice->transfer_command_buf);
|
||||
|
||||
AliceScene__another_frame(alice);
|
||||
LucyGlyphCache_another_frame(&alice->lucy_cache);
|
||||
// LucyGlyphCache_another_frame(&alice->lucy_cache); lucy cache has no business here
|
||||
LucyRenderer_another_frame(&alice->lucy_renderer);
|
||||
margaret_end_command_buffer(alice->transfer_command_buf);
|
||||
|
||||
alice_reset_and_record_command_buffer_0(alice, t_mat);
|
||||
alice_reset_and_record_command_buffer_1(alice, *VecVkFramebuffer_at(&alice->swfb.framebuffers, ij));
|
||||
|
||||
@ -1906,11 +1853,10 @@ Alice* Alice_new(){
|
||||
alice->device, alice->queue_fam, swapchain_details_res.ok,
|
||||
alice->surface, alice->render_pass_1, NULL);
|
||||
|
||||
alice->single_upload_buffers = AliceAllSingleUploadBuffers_new();
|
||||
alice->single_upload_textures = AliceAllSingleUploadTextures_new();
|
||||
alice->abigail = (Abigail){ .to_del = VecMargaretSubbuf_new() };
|
||||
|
||||
alice->generic_models = AliceAllMeshesGeneric_new();
|
||||
alice->shiny_models = AliceAllMeshesShiny_new();
|
||||
alice->generic_models = ListAliceGenericMeshHand_new();
|
||||
alice->shiny_models = ListAliceShinyMeshHand_new();
|
||||
|
||||
alice->pipeline0_light_conf.num_ubo_staging = MargaretBufAllocator_alloc(&alice->staging_buffers, sizeof(Pipeline0UBO));
|
||||
alice->pipeline0_light_conf.num_ubo_dev_local = MargaretBufAllocator_alloc(&alice->dev_local_buffers, sizeof(Pipeline0UBO));
|
||||
@ -1939,7 +1885,7 @@ Alice* Alice_new(){
|
||||
if (ft_init_err)
|
||||
abortf("Can't init free type library\n");
|
||||
|
||||
alice->lucy_cache = LucyGlyphCache_new(engine_reference, &alice->single_upload_textures);
|
||||
alice->lucy_cache = LucyGlyphCache_new(engine_reference, &alice->abigail);
|
||||
|
||||
alice->lucy_renderer = LucyRenderer_new(engine_reference, &alice->lucy_cache, root_dir, alice->render_pass_1, 0);
|
||||
|
||||
@ -1947,6 +1893,9 @@ Alice* Alice_new(){
|
||||
// Creating descriptor set for pipeline 0b and for pipeline 1 (containing IT1 sampler)
|
||||
alice_create_mem_dependant_vk_obj(alice);
|
||||
|
||||
alice->transfer_command_buf_already_reset = true;
|
||||
margaret_reset_and_begin_command_buffer(alice->transfer_command_buf);
|
||||
|
||||
alice->wl.prev_key_frame_time = margaret_clock_gettime_monotonic_raw();
|
||||
alice->wl.frame_count_since_key = 0;
|
||||
/* Alice initialization complete */
|
||||
|
||||
@ -2,208 +2,72 @@
|
||||
|
||||
/* I sometimes call this sub-namespace of Alice namespace Abigail. Though I hadn't renamed it to Abigail yet.
|
||||
* Abigail does not depend on Alice Engine. It only depends on margaret. So systems like Lucy can use it
|
||||
* without creating any sus circular dependepncies.
|
||||
* without creating any sus circular dependencies.
|
||||
*/
|
||||
|
||||
#include "../margaret/vulkan_utils.h"
|
||||
#include "../../../gen/l1/margaret/VecMargaretSubbuf.h"
|
||||
|
||||
/* Handler of a read-only buffer that can be uploaded and deleted at any time with it's staging buffer automatically
|
||||
* deleted (Similar to what AliceTextureUploadedOnce does to textures) */
|
||||
typedef struct {
|
||||
U64 count;
|
||||
MargaretSubbuf staging;
|
||||
MargaretSubbuf device_buf;
|
||||
bool scheduled_for_deletion;
|
||||
} AliceBufferUplOnce;
|
||||
|
||||
typedef AliceBufferUplOnce* RefAliceBufferUplOnce;
|
||||
|
||||
#include "../../../gen/l1/eve/alice/VecRefAliceBufferUplOnce.h"
|
||||
|
||||
/* Handler of a texture that can be uploaded and deleted at any time with it's staging buffer automatically deleted.
|
||||
* Stores VkImageView as a bonus */
|
||||
typedef struct {
|
||||
MargaretSubbuf staging;
|
||||
MargaretImg img;
|
||||
VkImageView view;
|
||||
bool scheduled_for_deletion;
|
||||
} AliceTextureUplOnce;
|
||||
|
||||
typedef AliceTextureUplOnce* RefAliceTextureUplOnce;
|
||||
|
||||
#include "../../../gen/l1/eve/alice/VecRefAliceTextureUplOnce.h"
|
||||
MargaretSubbuf device_local;
|
||||
} PatriciaBuf;
|
||||
|
||||
typedef struct {
|
||||
VecRefAliceBufferUplOnce to_be_freed_of_old_staging_next_cycle;
|
||||
VecRefAliceBufferUplOnce to_be_copied_to_device_next_cycle;
|
||||
VecRefAliceBufferUplOnce to_be_deleted;
|
||||
} AliceAllSingleUploadBuffers;
|
||||
VecMargaretSubbuf to_del;
|
||||
} Abigail;
|
||||
|
||||
AliceAllSingleUploadBuffers AliceAllSingleUploadBuffers_new() {
|
||||
return (AliceAllSingleUploadBuffers){
|
||||
.to_be_freed_of_old_staging_next_cycle = VecRefAliceBufferUplOnce_new(),
|
||||
.to_be_copied_to_device_next_cycle = VecRefAliceBufferUplOnce_new(),
|
||||
.to_be_deleted = VecRefAliceBufferUplOnce_new(),
|
||||
};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
VecRefAliceTextureUplOnce to_be_freed_of_old_staging_next_cycle;
|
||||
VecRefAliceTextureUplOnce to_be_copied_to_device_next_cycle;
|
||||
VecRefAliceTextureUplOnce to_be_deleted;
|
||||
} AliceAllSingleUploadTextures;
|
||||
|
||||
AliceAllSingleUploadTextures AliceAllSingleUploadTextures_new(){
|
||||
return (AliceAllSingleUploadTextures){
|
||||
.to_be_freed_of_old_staging_next_cycle = VecRefAliceTextureUplOnce_new(),
|
||||
.to_be_copied_to_device_next_cycle = VecRefAliceTextureUplOnce_new(),
|
||||
.to_be_deleted = VecRefAliceTextureUplOnce_new(),
|
||||
};
|
||||
}
|
||||
|
||||
void AliceAllSingleUploadBuffers__resolve_on_another_frame(AliceAllSingleUploadBuffers* self,
|
||||
MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers, VkCommandBuffer transfer_cmd_buffer
|
||||
/* You know the deal, the buffer, returned in ret_dev_local_buf, cannot be deleted in the same `_another_frame`
|
||||
* callback as this function was called. And it should be obvious that this function can only be called when the
|
||||
* frame is not in flight. And ret_mapped_staging region is guaranteed to be len bytes long, also, it cannot be
|
||||
* used when current init/another_frame phase is over
|
||||
*/
|
||||
MargaretSubbuf /* ret_dev_local_buf */ Abigail_register_new_buffer(Abigail* self, U64 len,
|
||||
VkCommandBuffer transfer_cmd_buffer, MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers,
|
||||
void** ret_mapped_staging
|
||||
) {
|
||||
for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) {
|
||||
AliceBufferUplOnce* mm = self->to_be_freed_of_old_staging_next_cycle.buf[i];
|
||||
assert(mm->staging.len != 0);
|
||||
MargaretBufAllocator_free(staging_buffers, mm->staging);
|
||||
mm->staging.len = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) {
|
||||
AliceBufferUplOnce* mm = self->to_be_copied_to_device_next_cycle.buf[i];
|
||||
assert(mm->staging.len != 0);
|
||||
if (mm->scheduled_for_deletion)
|
||||
continue;
|
||||
margaret_rec_cmd_copy_buffer_one_to_one(transfer_cmd_buffer, &mm->staging, &mm->device_buf);
|
||||
VecRefAliceBufferUplOnce_append(&self->to_be_freed_of_old_staging_next_cycle, mm);
|
||||
}
|
||||
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
|
||||
AliceBufferUplOnce* mm = self->to_be_deleted.buf[i];
|
||||
assert(mm->scheduled_for_deletion);
|
||||
if (mm->staging.len != 0)
|
||||
MargaretBufAllocator_free(staging_buffers, mm->staging);
|
||||
MargaretBufAllocator_free(dev_local_buffers, mm->device_buf);
|
||||
free(mm);
|
||||
}
|
||||
|
||||
self->to_be_freed_of_old_staging_next_cycle.len = 0;
|
||||
self->to_be_copied_to_device_next_cycle.len = 0;
|
||||
self->to_be_deleted.len = 0;
|
||||
MargaretSubbuf staging = MargaretBufAllocator_alloc(staging_buffers, len);
|
||||
MargaretSubbuf dev_local = MargaretBufAllocator_alloc(dev_local_buffers, len);
|
||||
margaret_rec_cmd_copy_buffer_one_to_one(transfer_cmd_buffer, &staging, &dev_local);
|
||||
*ret_mapped_staging = MargaretSubbuf_get_mapped(&staging);
|
||||
VecMargaretSubbuf_append(&self->to_del, staging);
|
||||
return dev_local;
|
||||
}
|
||||
|
||||
void AliceAllSingleUploadTextures__resolve_on_another_frame(AliceAllSingleUploadTextures* self,
|
||||
MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images, VkCommandBuffer transfer_cmd_buffer
|
||||
/* Same deal as Abigail_register_new_buffer, but for textures. I say textures, because returned object also includes
|
||||
* VkImageView, created for this image.
|
||||
* Returned device localimage cannot be deleted in the same 'no-frame-in-flight' stage. We have to wait for it
|
||||
* to undergo copying, only then, on another frame, can you delete it. ret_mapped_staging points to staging buffer,
|
||||
* it is a memory region of width * height * pixed_sz bytes long. Here pixel_sz is a size of pixel in image of format
|
||||
* `foramt`. This memory can only be edited in the same `on-another-frame` phrase where it was given. But not later
|
||||
*/
|
||||
MargaretTexture /* ret_dev_local_texture */ Abigail_register_new_texture(Abigail* self, U64 width, U64 height, U64 pixel_sz,
|
||||
VkFormat format, VkImageUsageFlags usage,
|
||||
VkCommandBuffer transfer_cmd_buffer, MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images,
|
||||
void** ret_mapped_staging
|
||||
) {
|
||||
for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) {
|
||||
AliceTextureUplOnce* mm = self->to_be_freed_of_old_staging_next_cycle.buf[i];
|
||||
assert(mm->staging.len != 0);
|
||||
MargaretBufAllocator_free(staging_buffers, mm->staging);
|
||||
mm->staging.len = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) {
|
||||
AliceTextureUplOnce* mm = self->to_be_copied_to_device_next_cycle.buf[i];
|
||||
assert(mm->staging.len != 0);
|
||||
if (mm->scheduled_for_deletion)
|
||||
continue;
|
||||
margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(transfer_cmd_buffer,
|
||||
&mm->staging, &mm->img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
MargaretSubbuf staging = MargaretBufAllocator_alloc(staging_buffers, width * height * pixel_sz);
|
||||
MargaretImg dev_local = MargaretImgAllocator_alloc(dev_local_images, width, height, format, usage);
|
||||
margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(transfer_cmd_buffer,
|
||||
&staging, &dev_local, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
VecRefAliceTextureUplOnce_append(&self->to_be_freed_of_old_staging_next_cycle, mm);
|
||||
*ret_mapped_staging = MargaretSubbuf_get_mapped(&staging);
|
||||
VecMargaretSubbuf_append(&self->to_del, staging);
|
||||
return (MargaretTexture){.img = dev_local, .view = margaret_create_view_for_image(
|
||||
dev_local_images->device, dev_local.a.image, format, VK_IMAGE_ASPECT_COLOR_BIT)};
|
||||
}
|
||||
|
||||
void Abigail_wipe_old_staging(Abigail* self, VkDevice device, MargaretBufAllocator* staging_buffers) {
|
||||
for (U64 i = 0; i < self->to_del.len; i++) {
|
||||
MargaretSubbuf staging = self->to_del.buf[i];
|
||||
MargaretBufAllocator_free(staging_buffers, staging);
|
||||
}
|
||||
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
|
||||
AliceTextureUplOnce* mm = self->to_be_deleted.buf[i];
|
||||
assert(mm->scheduled_for_deletion);
|
||||
if (mm->staging.len != 0)
|
||||
MargaretBufAllocator_free(staging_buffers, mm->staging);
|
||||
|
||||
MargaretImgAllocator_free(dev_local_images, mm->img.a);
|
||||
vkDestroyImageView(dev_local_images->device, mm->view, NULL);
|
||||
free(mm);
|
||||
}
|
||||
|
||||
self->to_be_freed_of_old_staging_next_cycle.len = 0;
|
||||
self->to_be_copied_to_device_next_cycle.len = 0;
|
||||
self->to_be_deleted.len = 0;
|
||||
self->to_del.len = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Doesn't get automatically added to `to_be_copied_to_device_next_cycle` */
|
||||
AliceBufferUplOnce* AliceBufferUplOnce_new(size_t len,
|
||||
MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers
|
||||
) {
|
||||
AliceBufferUplOnce* res = (AliceBufferUplOnce*)safe_malloc(sizeof(AliceBufferUplOnce));
|
||||
res->staging = MargaretBufAllocator_alloc(staging_buffers, len);
|
||||
res->device_buf = MargaretBufAllocator_alloc(dev_local_buffers, len);
|
||||
res->scheduled_for_deletion = false;
|
||||
return res;
|
||||
void Abigail_drop(Abigail self) {
|
||||
assert(self.to_del.len == 0);
|
||||
VecMargaretSubbuf_drop(self.to_del);
|
||||
}
|
||||
|
||||
void* AliceBufferUplOnce_get_mapped_staging(AliceBufferUplOnce* self) {
|
||||
return MargaretSubbuf_get_mapped(&self->staging);
|
||||
}
|
||||
|
||||
void AliceAllSingleUploadBuffers_register(AliceAllSingleUploadBuffers* self, AliceBufferUplOnce* obj) {
|
||||
assert(obj->staging.len > 0);
|
||||
assert(!obj->scheduled_for_deletion);
|
||||
VecRefAliceBufferUplOnce_append(&self->to_be_copied_to_device_next_cycle, obj);
|
||||
}
|
||||
|
||||
AliceBufferUplOnce* AliceAllSingleUploadBuffers_register_new(AliceAllSingleUploadBuffers* self, size_t len,
|
||||
MargaretBufAllocator* staging_buffers, MargaretBufAllocator* dev_local_buffers
|
||||
) {
|
||||
AliceBufferUplOnce* res = AliceBufferUplOnce_new(len, staging_buffers, dev_local_buffers);
|
||||
AliceAllSingleUploadBuffers_register(self, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void AliceAllSingleUploadBuffers_delete(AliceAllSingleUploadBuffers* self, AliceBufferUplOnce* obj) {
|
||||
assert(obj);
|
||||
obj->scheduled_for_deletion = true;
|
||||
VecRefAliceBufferUplOnce_append(&self->to_be_deleted, obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Doesn't get automatically added to `to_be_copied_to_device_next_cycle`
|
||||
* Only works for VK_IMAGE_ASPECT_COLOR_BIT images */
|
||||
AliceTextureUplOnce* AliceTextureUplOnce_new(U64 width, U64 height, U64 pixel_sz, VkFormat format,
|
||||
VkImageUsageFlags usage, MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images
|
||||
) {
|
||||
assert(pixel_sz == margaret_singleplane_format_to_sizeof_type(format));
|
||||
AliceTextureUplOnce* res = (AliceTextureUplOnce*)safe_malloc(sizeof(AliceTextureUplOnce));
|
||||
res->staging = MargaretBufAllocator_alloc(staging_buffers, width * height * pixel_sz);
|
||||
res->img = MargaretImgAllocator_alloc(dev_local_images, width, height, format, usage);
|
||||
res->view = margaret_create_view_for_image(dev_local_images->device, res->img.a.image,
|
||||
format, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
res->scheduled_for_deletion = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
void* AliceTextureUplOnce_get_mapped_staging(AliceTextureUplOnce* self) {
|
||||
return MargaretSubbuf_get_mapped(&self->staging);
|
||||
}
|
||||
|
||||
void AliceAllSingleUploadTextures_register(AliceAllSingleUploadTextures* self, AliceTextureUplOnce* obj) {
|
||||
assert(obj->staging.len > 0);
|
||||
assert(!obj->scheduled_for_deletion);
|
||||
VecRefAliceTextureUplOnce_append(&self->to_be_copied_to_device_next_cycle, obj);
|
||||
}
|
||||
|
||||
AliceTextureUplOnce* AliceAllSingleUploadTextures_register_new(AliceAllSingleUploadTextures* self,
|
||||
U64 width, U64 height, U64 pixel_sz, VkFormat format,
|
||||
VkImageUsageFlags usage, MargaretBufAllocator* staging_buffers, MargaretImgAllocator* dev_local_images
|
||||
) {
|
||||
AliceTextureUplOnce* res = AliceTextureUplOnce_new(width, height, pixel_sz, format, usage,
|
||||
staging_buffers, dev_local_images);
|
||||
AliceAllSingleUploadTextures_register(self, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void AliceAllSingleUploadTextures_delete(AliceAllSingleUploadTextures* self, AliceTextureUplOnce* obj) {
|
||||
assert(obj);
|
||||
obj->scheduled_for_deletion = true;
|
||||
VecRefAliceTextureUplOnce_append(&self->to_be_deleted, obj);
|
||||
}
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
#define LUCY_MAX_DESCRIPTOR_COUNT 100
|
||||
|
||||
typedef struct {
|
||||
AliceTextureUplOnce* tex;
|
||||
MargaretTexture tex;
|
||||
U64 usage;
|
||||
/* Is this image scheduled for deletion on th next cycle. */
|
||||
bool scheduled_for_deletion;
|
||||
/* I just could not avoid storing this here. But yeah, after the copying is done, this field stops being used */
|
||||
void* staging;
|
||||
} LucyImage;
|
||||
|
||||
#include "../../../gen/l1/eve/lucy/OptionLucyImage.h"
|
||||
@ -64,7 +64,7 @@ struct LucyFace {
|
||||
|
||||
struct LucyGlyphCache {
|
||||
MargaretEngineReference ve;
|
||||
AliceAllSingleUploadTextures* single_upload_textures;
|
||||
Abigail* abigail;
|
||||
|
||||
VecOptionLucyImage image_slots;
|
||||
VkDescriptorSetLayout descriptor_set_layout;
|
||||
@ -76,7 +76,7 @@ struct LucyGlyphCache {
|
||||
};
|
||||
|
||||
|
||||
LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, AliceAllSingleUploadTextures* single_upload_textures){
|
||||
LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, Abigail* abigail){
|
||||
VkDescriptorSetLayout my_desc_set_layout;
|
||||
VkDescriptorSetLayoutBindingFlagsCreateInfo set_layout_crinfo_flags = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
|
||||
@ -101,7 +101,7 @@ LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve, AliceAllSingleUplo
|
||||
image_slots.buf[i].variant = Option_None;
|
||||
}
|
||||
return (LucyGlyphCache){
|
||||
.ve = ve, .single_upload_textures = single_upload_textures, .image_slots = image_slots,
|
||||
.ve = ve, .abigail = abigail, .image_slots = image_slots,
|
||||
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set,
|
||||
.to_be_written_to_descriptor_set = VecU32_new(),
|
||||
.to_be_deleted = VecU32_new()};
|
||||
@ -117,11 +117,8 @@ void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->usage > 0);
|
||||
if (--img->usage) {
|
||||
assert(!img->scheduled_for_deletion);
|
||||
img->scheduled_for_deletion = true;
|
||||
AliceAllSingleUploadTextures_delete(cache->single_upload_textures, img->tex);
|
||||
img->tex = NULL;
|
||||
VecU32_append(&cache->to_be_deleted, slot_id);
|
||||
/* Nothing is written to descriptor set. And luckily, we don't have to */
|
||||
img_slot->variant = Option_None;
|
||||
}
|
||||
}
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs);
|
||||
@ -166,7 +163,6 @@ U32 LucyGlyphCache_add_glyphs__find_image_slot(LucyGlyphCache* cache){
|
||||
OptionLucyImage* slot = &cache->image_slots.buf[i];
|
||||
if (slot->variant == Option_None) {
|
||||
slot->variant = Option_Some;
|
||||
slot->some.scheduled_for_deletion = 0;
|
||||
slot->some.usage = 0;
|
||||
return i;
|
||||
}
|
||||
@ -183,15 +179,27 @@ void LucyGlyphCache_add_glyphs__close_img(
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->usage > 0);
|
||||
assert(!img->scheduled_for_deletion);
|
||||
img_width = MAX_U32(img_width, 10); // Just a precaution. empty buffers aren't supported by Margaret
|
||||
img_height = MAX_U32(img_height, 10);
|
||||
|
||||
img->tex = AliceAllSingleUploadTextures_register_new(cache->single_upload_textures,
|
||||
img->tex = Abigail_register_new_texture(cache->abigail,
|
||||
img_width, img_height, sizeof(U8), VK_FORMAT_R8_UNORM,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
cache->ve.staging_buffers, cache->ve.dev_local_images);
|
||||
VecU32_append(&cache->to_be_written_to_descriptor_set, img_slot_id);
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, cache->ve.transfer_cmd_buffer,
|
||||
cache->ve.staging_buffers, cache->ve.dev_local_images, &(img->staging));
|
||||
assert(img->staging);
|
||||
/* We are writing to descriptor set RIGHT NOW. That is why this function, and as such
|
||||
* LucyGlyphCache_add_glyphs too, must be called when no frame is in flight */
|
||||
|
||||
vkUpdateDescriptorSets(cache->ve.device, 1, &(VkWriteDescriptorSet){
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = cache->descriptor_set, .dstBinding = 0, .dstArrayElement = img_slot_id,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = cache->ve.nearest_sampler, .imageView = img->tex.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
}
|
||||
}, 0, NULL);
|
||||
}
|
||||
|
||||
void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
|
||||
@ -312,8 +320,8 @@ void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
|
||||
for (size_t j = 0; j < ready.len; j++) {
|
||||
LucyPositionedStagingGlyph* p_glyph = &ready.buf[j];
|
||||
LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, p_glyph->img_slot_id)->some;
|
||||
U64 staging_width = image->tex->img.width;
|
||||
U8* staging = (U8*)AliceTextureUplOnce_get_mapped_staging(image->tex);
|
||||
U64 staging_width = image->tex.img.width;
|
||||
U8* staging = (U8*)image->staging;
|
||||
for (U64 y = 0; y < p_glyph->bitmap.height; y++) {
|
||||
U64 Y = y + p_glyph->pos.y;
|
||||
for (U64 x = 0; x < p_glyph->bitmap.width; x++) {
|
||||
@ -336,42 +344,6 @@ void LucyGlyphCache_drop(LucyGlyphCache self){
|
||||
VecU32_drop(self.to_be_deleted);
|
||||
}
|
||||
|
||||
void LucyGlyphCache_another_frame(LucyGlyphCache* self){
|
||||
for (size_t i = 0; i < self->to_be_written_to_descriptor_set.len; i++) {
|
||||
U32 slot_id = self->to_be_written_to_descriptor_set.buf[i];
|
||||
OptionLucyImage* img_slot = &self->image_slots.buf[slot_id];
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
if (img->scheduled_for_deletion)
|
||||
continue;
|
||||
|
||||
vkUpdateDescriptorSets(self->ve.device, 1, &(VkWriteDescriptorSet){
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = self->descriptor_set, .dstBinding = 0, .dstArrayElement = slot_id,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = self->ve.nearest_sampler, .imageView = img->tex->view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
}
|
||||
}, 0, NULL);
|
||||
}
|
||||
/* We technically could carry out each deletion request in O(1) and each img creation request in O(1),
|
||||
* but who cares, it's no problem going over the entire descriptor set when something get's added or deleted */
|
||||
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
|
||||
U32 slot_id = self->to_be_deleted.buf[i];
|
||||
OptionLucyImage* img_slot = &self->image_slots.buf[slot_id];
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->scheduled_for_deletion);
|
||||
assert(img->usage == 0);
|
||||
assert(img->tex == NULL);
|
||||
img_slot->variant = Option_None;
|
||||
}
|
||||
self->to_be_written_to_descriptor_set.len = 0;
|
||||
self->to_be_deleted.len = 0;
|
||||
}
|
||||
|
||||
/* This function does not check font file for correctness, use only with trusted fonts */
|
||||
LucyFace* LucyFace_new(FT_Library lib, LucyGlyphCache* cache, VecU8 path){
|
||||
VecU8_append(&path, 0); // Making it null-terminated
|
||||
|
||||
@ -97,8 +97,8 @@ void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, Luc
|
||||
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&self->cache->image_slots, glyph->img_slot_id);
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
float atlas_w = (float)img->tex->img.width;
|
||||
float atlas_h = (float)img->tex->img.height;
|
||||
float atlas_w = (float)img->tex.img.width;
|
||||
float atlas_h = (float)img->tex.img.height;
|
||||
ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing);
|
||||
|
||||
U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance);
|
||||
|
||||
@ -361,4 +361,4 @@ void MargaretBufAllocator_expand_or_free_old(
|
||||
MargaretBufAllocator_free(self, *allocation);
|
||||
*allocation = maybe_bigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1287,3 +1287,8 @@ U64 margaret_singleplane_format_to_sizeof_type(VkFormat type){
|
||||
abortf("Jokes on you\n");
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MargaretImg img;
|
||||
VkImageView view;
|
||||
} MargaretTexture;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user