From d4d97ed8c60d944fbd92dbea8aaf7b7c48d53f04 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Fri, 29 Aug 2025 15:05:06 +0300 Subject: [PATCH] Now my vulkan program works on wayland (r3) --- src/l1/codegen/util_template_inst.h | 6 +- src/l2/codegen/codegen.c | 1 + src/l2/margaret/vulkan.h | 39 +++- src/l2/tests/r0/r0.c | 47 +++-- src/l2/tests/r1/r1.c | 8 +- src/l2/tests/r3/r3.c | 298 ++++++++++++++-------------- 6 files changed, 215 insertions(+), 184 deletions(-) diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index 0c327e7..d4f5d1b 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -398,9 +398,9 @@ NODISCARD VecU8 generate_OptionT_struct_and_methods(SpanU8 T, bool primitive, bo "} %s;\n\n", T, OptionT); VecU8_append_vec(&res, VecU8_fmt("#define None_%s() (%s){ .variant = Option_None }\n\n", T, OptionT)); - VecU8_append_vec(&res, VecU8_fmt("%s Some_%s(obj) {\n" - SPACE4 "(%s){ .variant = Option_Some, .some = obj };\n" - "}\n\n", OptionT, T, OptionT)); + VecU8_append_vec(&res, VecU8_fmt("%s Some_%s(%s obj) {\n" + SPACE4 "return (%s){ .variant = Option_Some, .some = obj };\n" + "}\n\n", OptionT, T, T, OptionT)); VecU8_append_vec(&res, VecU8_fmt( "const %s* %s_expect_ref(const %s* self){\n" diff --git a/src/l2/codegen/codegen.c b/src/l2/codegen/codegen.c index ec2537b..ce77f49 100644 --- a/src/l2/codegen/codegen.c +++ b/src/l2/codegen/codegen.c @@ -48,6 +48,7 @@ void eve_of_l2() { generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkImage"), true, false); generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkImageView"), true, false); generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkFramebuffer"), true, false); + generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkSemaphore"), true, false); generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("MargaretBufferInMemoryInfo"), true, false); generate_eve_header(cstr("l2"), cstr(""), cstr("PtrMargaretBufferInMemoryInfo"), (util_templates_instantiation_options){ .t_primitive = true, .vec = true, .span = true, .mut_span = true, diff --git a/src/l2/margaret/vulkan.h b/src/l2/margaret/vulkan.h index 1c9c9e0..70599e1 100644 --- a/src/l2/margaret/vulkan.h +++ b/src/l2/margaret/vulkan.h @@ -291,11 +291,11 @@ OptionVkExtent2D margaret_choose_image_extent(const VkSurfaceCapabilitiesKHR* ca if (capabilities->minImageExtent.width > sane_limits.width || capabilities->minImageExtent.height > sane_limits.height) return None_VkExtent2D(); - return Some_VkExtent2D ((VkExtent2D) { MIN_U32(sane_limits.width, sane_limits.width), + return Some_VkExtent2D((VkExtent2D) { MIN_U32(sane_limits.width, sane_limits.width), MIN_U32(sane_limits.height, sane_limits.height) }); } /* May be bigger, than a sane limit */ - return capabilities->currentExtent; + return Some_VkExtent2D(capabilities->currentExtent); } uint32_t margaret_choose_swapchain_image_count(const VkSurfaceCapabilitiesKHR* capabilities) { @@ -313,7 +313,9 @@ typedef struct { } ResultMargaretChosenSwapchainDetailsOrSpanU8; // Both queries swapchain support details and selects needed formats and presentation modes -ResultMargaretChosenSwapchainDetailsOrSpanU8 margaret_choose_swapchain_details(VkPhysicalDevice physical_device, VkSurfaceKHR surface) { +ResultMargaretChosenSwapchainDetailsOrSpanU8 margaret_choose_swapchain_details( + VkPhysicalDevice physical_device, VkSurfaceKHR surface, VkExtent2D sane_image_extent_limit + ) { /* 1. Getting surface capabilities + formats + presentation modes */ VkSurfaceCapabilitiesKHR surface_capabilities; if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities) != VK_SUCCESS) @@ -343,7 +345,11 @@ ResultMargaretChosenSwapchainDetailsOrSpanU8 margaret_choose_swapchain_details(V return (ResultMargaretChosenSwapchainDetailsOrSpanU8){ .variant = Result_Err, .err = cstr("No suitable swapchain presentation mode") }; - VkExtent2D image_extent = margaret_choose_image_extent(&surface_capabilities); + OptionVkExtent2D image_extent = margaret_choose_image_extent(&surface_capabilities, sane_image_extent_limit); + if (image_extent.variant == Option_None) + return (ResultMargaretChosenSwapchainDetailsOrSpanU8){ .variant = Result_Err, + .err = cstr("Can't choose sane image extent")}; + uint32_t image_count = margaret_choose_swapchain_image_count(&surface_capabilities); OptionVkCompositeAlphaFlagBitsKHR chosen_composite_alpha = margaret_choose_composite_alpha( @@ -357,7 +363,7 @@ ResultMargaretChosenSwapchainDetailsOrSpanU8 margaret_choose_swapchain_details(V return (ResultMargaretChosenSwapchainDetailsOrSpanU8){ .variant = Result_Ok,\ .ok = (MargaretChosenSwapchainDetails){ .surface_format = chosen_surface_format.some, .presentation_mode = chosen_present_mode.some, - .image_extent = image_extent, .image_count = image_count, + .image_extent = image_extent.some, .image_count = image_count, .surface_pre_transform = surface_capabilities.currentTransform, .composite_alpha = chosen_composite_alpha.some } @@ -421,7 +427,8 @@ typedef struct { } MargaretScoredPhysicalDevice; MargaretScoredPhysicalDevice margaret_score_physical_device( - VkPhysicalDevice dev, VkSurfaceKHR surface, SpanU8 favourite_word, SpanU8 forbidden_word + VkPhysicalDevice dev, VkSurfaceKHR surface, SpanU8 favourite_word, SpanU8 forbidden_word, + VkExtent2D sane_image_extent_limit ) { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(dev, &properties); @@ -463,7 +470,7 @@ MargaretScoredPhysicalDevice margaret_score_physical_device( } VecVecU8_drop(dev_extensions); // Extension VK_KHR_swapchain is present, now we can call query_swap_chain_support - ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details = margaret_choose_swapchain_details(dev, surface); + ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details = margaret_choose_swapchain_details(dev, surface, sane_image_extent_limit); if (swapchain_details.variant == Result_Err) { return (MargaretScoredPhysicalDevice){dev, -1, cstr("Physical device lacks nice swapchain support")}; } @@ -485,7 +492,7 @@ MargaretScoredPhysicalDevice margaret_score_physical_device( VecMargaretScoredPhysicalDevice margaret_get_physical_devices_scored( VkInstance instance, VkSurfaceKHR surface, - SpanU8 favourite_word, SpanU8 forbidden_word + SpanU8 favourite_word, SpanU8 forbidden_word, VkExtent2D sane_image_extent_limit ) { uint32_t physical_device_count = 0; if (vkEnumeratePhysicalDevices(instance, &physical_device_count, NULL) != VK_SUCCESS) @@ -496,7 +503,8 @@ VecMargaretScoredPhysicalDevice margaret_get_physical_devices_scored( VecMargaretScoredPhysicalDevice scored_devices = VecMargaretScoredPhysicalDevice_new_zeroinit(physical_device_count); for (uint32_t i = 0; i < physical_device_count; i++) { *VecMargaretScoredPhysicalDevice_mat(&scored_devices, i) = margaret_score_physical_device( - *VecVkPhysicalDevice_at(&physical_devices, i), surface, favourite_word, forbidden_word + *VecVkPhysicalDevice_at(&physical_devices, i), surface, + favourite_word, forbidden_word, sane_image_extent_limit ); } MutSpanMargaretScoredPhysicalDevice_sort(VecMargaretScoredPhysicalDevice_to_mspan(&scored_devices)); @@ -505,9 +513,10 @@ VecMargaretScoredPhysicalDevice margaret_get_physical_devices_scored( VkPhysicalDevice margaret_select_one_physical_device( VkInstance instance, VkSurfaceKHR surface, - SpanU8 favourite_word, SpanU8 forbidden_word + SpanU8 favourite_word, SpanU8 forbidden_word, VkExtent2D sane_image_extent_limit ) { - VecMargaretScoredPhysicalDevice scored_devices = margaret_get_physical_devices_scored(instance, surface, favourite_word, forbidden_word); + VecMargaretScoredPhysicalDevice scored_devices = margaret_get_physical_devices_scored(instance, surface, + favourite_word, forbidden_word, sane_image_extent_limit); printf("Physical devices (with scores):\n"); for (size_t i = 0; i < scored_devices.len; i++) { const MargaretScoredPhysicalDevice* dev = VecMargaretScoredPhysicalDevice_at(&scored_devices, i); @@ -571,6 +580,7 @@ VkSwapchainKHR margaret_create_swapchain ( #include "../../../gen/l2/eve/VecVkImage.h" #include "../../../gen/l2/eve/VecVkImageView.h" #include "../../../gen/l2/eve/VecVkFramebuffer.h" +#include "../../../gen/l2/eve/VecVkSemaphore.h" VecVkImageView margaret_create_swapchain_image_views( VkDevice device, VkSwapchainKHR swapchain, @@ -653,6 +663,7 @@ typedef struct { VecVkImageView image_views; VecVkFramebuffer framebuffers; VkExtent2D extent; + VecVkSemaphore rendering_finished_here_semaphores; } MargaretSwapchainBundle; MargaretSwapchainBundle MargaretSwapchainBundle_new( @@ -662,12 +673,18 @@ MargaretSwapchainBundle MargaretSwapchainBundle_new( VkSwapchainKHR swapchain = margaret_create_swapchain(device, queue_families, swapchain_details, surface, old_swapchain); VecVkImageView image_views = margaret_create_swapchain_image_views(device, swapchain, swapchain_details.surface_format.format); VecVkFramebuffer framebuffers = margaret_create_swapchain_framebuffers(device, &image_views, render_pass, swapchain_details.image_extent); + VecVkSemaphore rendering_finished_semaphores = VecVkSemaphore_new_zeroinit(framebuffers.len); + for (size_t i = 0; i < framebuffers.len; i++) + *VecVkSemaphore_mat(&rendering_finished_semaphores, i) = margaret_create_semaphore(device); return (MargaretSwapchainBundle){ .swapchain = swapchain, .image_views = image_views, .framebuffers = framebuffers, .extent = swapchain_details.image_extent, + .rendering_finished_here_semaphores = rendering_finished_semaphores }; } VkSwapchainKHR MargaretSwapchainBundle_pop_swapchain_drop_rest(VkDevice device, MargaretSwapchainBundle swfb) { + for (size_t i = 0; i < swfb.rendering_finished_here_semaphores.len; i++) + vkDestroySemaphore(device, *VecVkSemaphore_at(&swfb.rendering_finished_here_semaphores, i), NULL); for (size_t i = 0; i < swfb.framebuffers.len; i++) { vkDestroyFramebuffer(device, *VecVkFramebuffer_at(&swfb.framebuffers, i), NULL); } diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index a5d9b7a..4f9a807 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -936,23 +936,20 @@ typedef struct { VkSemaphore in_frame_transfer_complete; VkSemaphore image_available_semaphore; VkSemaphore rendered_to_IT1_semaphore; - VkSemaphore render_finished_semaphore; VkFence in_flight_fence; -} Jane; +} Jane_r0; -NODISCARD Jane Jane_create(VkDevice device) { - return (Jane){ +NODISCARD Jane_r0 Jane_r0_create(VkDevice device) { + return (Jane_r0){ .in_frame_transfer_complete = margaret_create_semaphore(device), .image_available_semaphore = margaret_create_semaphore(device), .rendered_to_IT1_semaphore = margaret_create_semaphore(device), - .render_finished_semaphore = margaret_create_semaphore(device), .in_flight_fence = margaret_create_fence(device, true) }; } -void Jane_destroy(VkDevice device, Jane jane) { +void Jane_r0_destroy(VkDevice device, Jane_r0 jane) { vkDestroyFence(device, jane.in_flight_fence, NULL); - vkDestroySemaphore(device, jane.render_finished_semaphore, NULL); vkDestroySemaphore(device, jane.rendered_to_IT1_semaphore, NULL); vkDestroySemaphore(device, jane.image_available_semaphore, NULL); vkDestroySemaphore(device, jane.in_frame_transfer_complete, NULL); @@ -960,14 +957,15 @@ void Jane_destroy(VkDevice device, Jane jane) { void recreate_swapchain( VkPhysicalDevice physical_device, VkDevice device, MargaretChosenQueueFamilies queue_fam, VkSurfaceKHR surface, - VkRenderPass render_pass, MargaretSwapchainBundle* swfb, Jane* jane) { + VkRenderPass render_pass, MargaretSwapchainBundle* swfb, Jane_r0* jane, VkExtent2D sane_image_extent_limit) { // We are about stop program and rebuild our sem+sem+fence synchronization mechanism vkDeviceWaitIdle(device); - Jane_destroy(device, *jane); - *jane = Jane_create(device); + Jane_r0_destroy(device, *jane); + *jane = Jane_r0_create(device); VkSwapchainKHR old_swapchain = MargaretSwapchainBundle_pop_swapchain_drop_rest(device, *swfb); // old swfb is 83% dropped - ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(physical_device, surface); + ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( + physical_device, surface, sane_image_extent_limit); if (swapchain_details_res.variant != Result_Ok) abortf("swapchain_details_res.variant != Result_Ok"); MargaretChosenSwapchainDetails swapchain_details = swapchain_details_res.ok; @@ -1002,6 +1000,7 @@ int main() { bool ENABLE_VALIDATION_LAYERS = true; const U32 MAX_WIN_WIDTH = 1920; const U32 MAX_WIN_HEIGHT = 1080; + VkExtent2D sane_image_extent_limit = {MAX_WIN_WIDTH, MAX_WIN_HEIGHT}; MargaretSingleWindowSetup_XlibFlavour x = MargaretSingleWindowSetup_XlibFlavour_new(); Margaret_WEP wep = Margaret_WEP_new(x.dpy, x.win); @@ -1015,7 +1014,8 @@ int main() { VkSurfaceKHR surface = margaret_create_surface_x_dunk(instance, &x); - VkPhysicalDevice physical_device = margaret_select_one_physical_device(instance, surface, GPU, bugged_GPU); + VkPhysicalDevice physical_device = margaret_select_one_physical_device( + instance, surface, GPU, bugged_GPU, sane_image_extent_limit); // print_physical_device_available_extensions(physical_device); @@ -1031,7 +1031,8 @@ int main() { VkQueue presentation_queue; vkGetDeviceQueue(device, queue_fam.for_presentation, 0, &presentation_queue); - ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(physical_device, surface); + ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( + physical_device, surface, sane_image_extent_limit); if (swapchain_details_res.variant != Result_Ok) abortf("swapchain_details_res.variant != Result_Ok"); @@ -1283,7 +1284,7 @@ int main() { CamControlInfo my_cam_control_info = CamControlInfo_new(); vec3 Buba_control_info = {0}; - Jane jane = Jane_create(device); + Jane_r0 jane = Jane_r0_create(device); // Mainloop margaret_ns_time start = margaret_clock_gettime_monotonic_raw(); @@ -1383,11 +1384,11 @@ int main() { ); if (aq_ret == VK_ERROR_OUT_OF_DATE_KHR) { fprintf(stderr, "vkAcquireNextImageKHR: VK_ERROR_OUT_OF_DATE_KHR\n"); - recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane); + recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane, sane_image_extent_limit); continue; } else if (aq_ret == VK_SUBOPTIMAL_KHR) { fprintf(stderr, "vkAcquireNextImageKHR: VK_SUBOPTIMAL_KHR\n"); - recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane); + recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane, sane_image_extent_limit); continue; } else if (aq_ret != VK_SUCCESS) { abortf("vkAcquireNextImageKHR"); @@ -1475,7 +1476,9 @@ int main() { }; assert(ARRAY_SIZE(waiting_for_semaphores) == ARRAY_SIZE(waiting_stages)); VkCommandBuffer command_buffers[1] = { rendering_command_buffer_1 }; - VkSemaphore signaling_semaphores[1] = { jane.render_finished_semaphore }; + VkSemaphore signaling_semaphores[1] = { + *VecVkSemaphore_at(&swfb.rendering_finished_here_semaphores, ij) + }; VkSubmitInfo cmd_submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, @@ -1495,7 +1498,9 @@ int main() { } { - VkSemaphore waiting_for_semaphores[] = { jane.render_finished_semaphore }; + VkSemaphore waiting_for_semaphores[] = { + *VecVkSemaphore_at(&swfb.rendering_finished_here_semaphores, ij) + }; VkSwapchainKHR swapchains[] = { swfb.swapchain }; uint32_t image_indices[] = { ij }; assert( ARRAY_SIZE(swapchains) == ARRAY_SIZE(image_indices) ); @@ -1515,11 +1520,11 @@ int main() { // todo: ponder more over this if (pres_ret == VK_ERROR_OUT_OF_DATE_KHR) { fprintf(stderr, "vkQueuePresentKHR: VK_ERROR_OUT_OF_DATE_KHR\n"); - recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane); + recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane, sane_image_extent_limit); continue; } else if (pres_ret == VK_SUBOPTIMAL_KHR) { fprintf(stderr, "vkQueuePresentKHR: VK_SUBOPTIMAL_KHR\n"); - recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane); + recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane, sane_image_extent_limit); continue; } else if (pres_ret != VK_SUCCESS) { abortf("vkQueuePresentKHR"); @@ -1567,7 +1572,7 @@ int main() { vkFreeMemory(device, host_mem, NULL); vkDestroyCommandPool(device, command_pool, NULL); MargaretSwapchainBundle_drop_with_device(device, swfb); - Jane_destroy(device, jane); + Jane_r0_destroy(device, jane); destroy_graphics_pipeline_hands(device, pipeline_hands_1); vkDestroyRenderPass(device, render_pass_1, NULL); destroy_graphics_pipeline_hands(device, pipeline_hands_0); diff --git a/src/l2/tests/r1/r1.c b/src/l2/tests/r1/r1.c index 688d6e6..dffa600 100644 --- a/src/l2/tests/r1/r1.c +++ b/src/l2/tests/r1/r1.c @@ -217,16 +217,19 @@ void try_drawing_frame(state_t *state){ /* Draw checkerboxed background */ uint32_t* data = state->swapchain.data + ij * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT; draw_frame(state, data, width, height); + printf("Attached\n"); wl_surface_attach(state->wl_surface, state->swapchain.used_buffers[ij], 0, 0); + printf("Damaged\n"); wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX); + printf("Commited\n"); wl_surface_commit(state->wl_surface); } static void main_h_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial){ state_t *state = data; printf("XDG surface configured!\n"); + printf("Acknowledged surface configure\n"); xdg_surface_ack_configure(xdg_surface, serial); - // todo: synchronize with frame event state->swapchain.want_to_draw = true; try_drawing_frame(state); } @@ -476,7 +479,7 @@ static const struct wl_callback_listener main_h_wl_surface_frame_listener; static void main_h_wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time){ state_t *state = data; wl_callback_destroy(cb); - // todo: when I add multiple surfaces, gonna need to think of something smarter + printf("AAA!!! CALLBACK!!!\n"); state->wl_callback = wl_surface_frame(state->wl_surface); if (!state->wl_callback) abortf("wl_surface_frame\n"); @@ -551,6 +554,7 @@ int main() { abortf("xdg_surface_get_toplevel\n"); xdg_toplevel_add_listener(state.xdg_toplevel, &main_h_xdg_toplevel_listener, &state); xdg_toplevel_set_title(state.xdg_toplevel, "r1"); + printf("Commited\n"); wl_surface_commit(state.wl_surface); state.wl_callback = wl_surface_frame(state.wl_surface); diff --git a/src/l2/tests/r3/r3.c b/src/l2/tests/r3/r3.c index 16ba177..4e4e8b9 100644 --- a/src/l2/tests/r3/r3.c +++ b/src/l2/tests/r3/r3.c @@ -11,9 +11,6 @@ #include "../../margaret/vulkan.h" #include -#define MAX_BUFFER_WIDTH 1000 -#define MAX_BUFFER_HEIGHT 800 - // todo: generate this function in l2 VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat colorbuffer_format) { @@ -26,7 +23,7 @@ VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat colorbuffer_ .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .finalLayout = VK_IMAGE_L AYOUT_PRESENT_SRC_KHR, } }; @@ -99,26 +96,25 @@ void reset_and_record_command_buffer_0( typedef struct { VkSemaphore image_available_semaphore; - VkSemaphore render_finished_semaphore; VkFence in_flight_fence; } Jane_r3; NODISCARD Jane_r3 Jane_r3_create(VkDevice device) { return (Jane_r3){ .image_available_semaphore = margaret_create_semaphore(device), - .render_finished_semaphore = margaret_create_semaphore(device), .in_flight_fence = margaret_create_fence(device, true) }; } void Jane_r3_destroy(VkDevice device, Jane_r3 jane) { vkDestroyFence(device, jane.in_flight_fence, NULL); - vkDestroySemaphore(device, jane.render_finished_semaphore, NULL); vkDestroySemaphore(device, jane.image_available_semaphore, NULL); } typedef struct { + /* Memory settings */ + VkExtent2D sane_image_extent_limit; /* Globals */ struct wl_display *wl_display; struct wl_registry *wl_registry; @@ -162,36 +158,140 @@ typedef struct { margaret_ns_time prev_key_frame_time; } state_t; -void draw_frame(state_t* state, uint32_t* data, int32_t width, int32_t height) { -} - void update_state(state_t* state, uint32_t fl) { - const float width = (float)(state->width < MAX_BUFFER_WIDTH ? state->width : MAX_BUFFER_WIDTH); - const float height = (float)(state->height < MAX_BUFFER_HEIGHT ? state->height : MAX_BUFFER_HEIGHT); float dur = (float)fl / 1000; state->ht += dur; } -// void try_drawing_frame(state_t *state){ - // if (!state->swapchain.want_to_draw) - // return; - // const int32_t width = state->width < MAX_BUFFER_WIDTH ? state->width : MAX_BUFFER_WIDTH; - // const int32_t height = state->height < MAX_BUFFER_HEIGHT ? state->height : MAX_BUFFER_HEIGHT; - /* Draw checkerboxed background */ - // uint32_t* data = state->swapchain.data + ij * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT; - // draw_frame(state, data, width, height); - // wl_surface_attach(state->wl_surface, state->swapchain.used_buffers[ij], 0, 0); - // wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX); - // wl_surface_commit(state->wl_surface); -// } +void recreate_swapchain(state_t* state) { + // We are about stop program and rebuild our sem+sem+fence synchronization mechanism + vkDeviceWaitIdle(state->device); + Jane_r3_destroy(state->device, state->jane); + state->jane = Jane_r3_create(state->device); + VkSwapchainKHR old_swapchain = MargaretSwapchainBundle_pop_swapchain_drop_rest(state->device, state->swfb); + // old swfb is 83% dropped + ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( + state->physical_device, state->vk_surface, state->sane_image_extent_limit); + if (swapchain_details_res.variant != Result_Ok) + abortf("swapchain_details_res.variant != Result_Ok"); + MargaretChosenSwapchainDetails swapchain_details = swapchain_details_res.ok; + MargaretSwapchainBundle new_swfb = MargaretSwapchainBundle_new( + state->device, state->queue_fam, swapchain_details, state->vk_surface, + state->render_pass_0, state->swfb.swapchain); + vkDestroySwapchainKHR(state->device, old_swapchain, NULL); + // Now old swfb is 100% dropped + state->swfb = new_swfb; +} + + +void vulkano_frame_drawing(state_t* state) { + // Rendering + and_try_again: + vkWaitForFences(state->device, 1, &state->jane.in_flight_fence, VK_TRUE, UINT64_MAX); + // printf("Dozhdalisya!\n"); + uint32_t ij; + VkResult aq_ret = vkAcquireNextImageKHR( + state->device, state->swfb.swapchain, + UINT64_MAX, state->jane.image_available_semaphore, VK_NULL_HANDLE, &ij + ); + if (aq_ret == VK_ERROR_OUT_OF_DATE_KHR) { + fprintf(stderr, "vkAcquireNextImageKHR: VK_ERROR_OUT_OF_DATE_KHR\n"); + recreate_swapchain(state); + goto and_try_again; + } else if (aq_ret == VK_SUBOPTIMAL_KHR) { + fprintf(stderr, "vkAcquireNextImageKHR: VK_SUBOPTIMAL_KHR\n"); + recreate_swapchain(state); + goto and_try_again; + } else if (aq_ret != VK_SUCCESS) { + abortf("vkAcquireNextImageKHR"); + } + // printf("Image acquired\n"); + vkResetFences(state->device, 1, &state->jane.in_flight_fence); + + reset_and_record_command_buffer_0(state->rendering_command_buffer_0, state->render_pass_0, + *VecVkFramebuffer_at(&state->swfb.framebuffers, ij), state->swfb.extent, state->ht); + + { + VkSemaphore waiting_for_semaphores[1] = {state->jane.image_available_semaphore}; + VkPipelineStageFlags waiting_stages[1] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + VkCommandBuffer command_buffers[1] = {state->rendering_command_buffer_0}; + VkSemaphore signaling_semaphores[1] = { + *VecVkSemaphore_at(&state->swfb.rendering_finished_here_semaphores, ij) + }; + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + + .waitSemaphoreCount = 1, + .pWaitSemaphores = waiting_for_semaphores, + .pWaitDstStageMask = waiting_stages, + + .commandBufferCount = ARRAY_SIZE(command_buffers), + .pCommandBuffers = command_buffers, + + .signalSemaphoreCount = ARRAY_SIZE(signaling_semaphores), + .pSignalSemaphores = signaling_semaphores, + }; + if (vkQueueSubmit(state->graphics_queue, 1, &submit_info, state->jane.in_flight_fence) != VK_SUCCESS) + abortf("vkQueueSubmit"); + } + + { + VkSemaphore waiting_for_semaphores[] = { + *VecVkSemaphore_at(&state->swfb.rendering_finished_here_semaphores, ij) + }; + VkSwapchainKHR swapchains[] = { state->swfb.swapchain }; + uint32_t image_indices[] = { ij }; + assert( ARRAY_SIZE(swapchains) == ARRAY_SIZE(image_indices) ); + + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = ARRAY_SIZE(waiting_for_semaphores), + .pWaitSemaphores = waiting_for_semaphores, + + .swapchainCount = ARRAY_SIZE(swapchains), + .pSwapchains = swapchains, + .pImageIndices = image_indices, + .pResults = NULL, + }; + + // printf("Now I will present it\n"); + VkResult pres_ret = vkQueuePresentKHR(state->presentation_queue, &present_info); + // todo: ponder more over this + if (pres_ret == VK_ERROR_OUT_OF_DATE_KHR) { + fprintf(stderr, "vkQueuePresentKHR: VK_ERROR_OUT_OF_DATE_KHR\n"); + recreate_swapchain(state); + goto and_try_again; + } else if (pres_ret == VK_SUBOPTIMAL_KHR) { + fprintf(stderr, "vkQueuePresentKHR: VK_SUBOPTIMAL_KHR\n"); + recreate_swapchain(state); + goto and_try_again; + } else if (pres_ret != VK_SUCCESS) { + abortf("vkQueuePresentKHR"); + } + } + margaret_ns_time frame_B0 = margaret_clock_gettime_monotonic_raw(); + state->frame_count_since_key++; + if (margaret_ns_time_sec_diff(state->prev_key_frame_time, frame_B0) > 1.0) { + float fps = (float)state->frame_count_since_key / margaret_ns_time_sec_diff(state->prev_key_frame_time, frame_B0); + printf("FPS: %0.1f\n", fps); + state->frame_count_since_key = 0; + state->prev_key_frame_time = frame_B0; + } +} + static void main_h_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial){ state_t *state = data; - printf("XDG surface configured!\n"); + printf("XDG surface configured! (%d %d)\n", state->width, state->height); + printf("Acknowledged surface configure\n"); xdg_surface_ack_configure(xdg_surface, serial); - // state->swapchain.want_to_draw = true; - // try_drawing_frame(state); + + vulkano_frame_drawing(state); + // printf("Damaged\n"); + // wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX); + // printf("Commited\n"); + // wl_surface_commit(state->wl_surface); } static const struct xdg_surface_listener xdg_surface_listener = { @@ -202,8 +302,12 @@ static void main_h_xdg_toplevel_configure( void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states ){ state_t *state = data; + uint32_t *conf_state; + wl_array_for_each(conf_state, states) { + printf("A state of xdg toplevel: %u\n", *conf_state); + } printf("XDG toplevel configured to (%d %d)\n", width, height); - if (width <= 0 || height < 0) + if (width <= 0 || height <= 0) return; state->width = width; state->height = height; @@ -412,118 +516,9 @@ static const struct wl_registry_listener main_h_wl_registry_listener = { static const struct wl_callback_listener main_h_wl_surface_frame_listener; -void recreate_swapchain(state_t* state) { - // We are about stop program and rebuild our sem+sem+fence synchronization mechanism - vkDeviceWaitIdle(state->device); - Jane_r3_destroy(state->device, state->jane); - state->jane = Jane_r3_create(state->device); - VkSwapchainKHR old_swapchain = MargaretSwapchainBundle_pop_swapchain_drop_rest(state->device, state->swfb); - // old swfb is 83% dropped - ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( - state->physical_device, state->vk_surface); - if (swapchain_details_res.variant != Result_Ok) - abortf("swapchain_details_res.variant != Result_Ok"); - MargaretChosenSwapchainDetails swapchain_details = swapchain_details_res.ok; - MargaretSwapchainBundle new_swfb = MargaretSwapchainBundle_new( - state->device, state->queue_fam, swapchain_details, state->vk_surface, - state->render_pass_0, state->swfb.swapchain); - vkDestroySwapchainKHR(state->device, old_swapchain, NULL); - // Now old swfb is 100% dropped - state->swfb = new_swfb; -} - - -void vulkano_frame_drawing(state_t* state) { - // Rendering - and_try_again: - vkWaitForFences(state->device, 1, &state->jane.in_flight_fence, VK_TRUE, UINT64_MAX); - uint32_t ij; - VkResult aq_ret = vkAcquireNextImageKHR( - state->device, state->swfb.swapchain, - UINT64_MAX, state->jane.image_available_semaphore, VK_NULL_HANDLE, &ij - ); - if (aq_ret == VK_ERROR_OUT_OF_DATE_KHR) { - fprintf(stderr, "vkAcquireNextImageKHR: VK_ERROR_OUT_OF_DATE_KHR\n"); - recreate_swapchain(state); - goto and_try_again; - } else if (aq_ret == VK_SUBOPTIMAL_KHR) { - fprintf(stderr, "vkAcquireNextImageKHR: VK_SUBOPTIMAL_KHR\n"); - recreate_swapchain(state); - goto and_try_again; - } else if (aq_ret != VK_SUCCESS) { - abortf("vkAcquireNextImageKHR"); - } - - vkResetFences(state->device, 1, &state->jane.in_flight_fence); - - reset_and_record_command_buffer_0(state->rendering_command_buffer_0, state->render_pass_0, - *VecVkFramebuffer_at(&state->swfb.framebuffers, ij), state->swfb.extent, state->ht); - - { - VkCommandBuffer command_buffers[1] = {state->rendering_command_buffer_0}; - VkSemaphore signaling_semaphores[1] = { state->jane.render_finished_semaphore }; - VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - - .waitSemaphoreCount = 0, - .pWaitSemaphores = NULL, - .pWaitDstStageMask = NULL, - - .commandBufferCount = ARRAY_SIZE(command_buffers), - .pCommandBuffers = command_buffers, - - .signalSemaphoreCount = ARRAY_SIZE(signaling_semaphores), - .pSignalSemaphores = signaling_semaphores, - }; - if (vkQueueSubmit(state->graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) - abortf("vkQueueSubmit"); - } - - { - VkSemaphore waiting_for_semaphores[] = { state->jane.render_finished_semaphore }; - VkSwapchainKHR swapchains[] = { state->swfb.swapchain }; - uint32_t image_indices[] = { ij }; - assert( ARRAY_SIZE(swapchains) == ARRAY_SIZE(image_indices) ); - - VkPresentInfoKHR present_info = { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .waitSemaphoreCount = ARRAY_SIZE(waiting_for_semaphores), - .pWaitSemaphores = waiting_for_semaphores, - - .swapchainCount = ARRAY_SIZE(swapchains), - .pSwapchains = swapchains, - .pImageIndices = image_indices, - .pResults = NULL, - }; - - VkResult pres_ret = vkQueuePresentKHR(state->presentation_queue, &present_info); - // todo: ponder more over this - if (pres_ret == VK_ERROR_OUT_OF_DATE_KHR) { - fprintf(stderr, "vkQueuePresentKHR: VK_ERROR_OUT_OF_DATE_KHR\n"); - recreate_swapchain(state); - goto and_try_again; - } else if (pres_ret == VK_SUBOPTIMAL_KHR) { - fprintf(stderr, "vkQueuePresentKHR: VK_SUBOPTIMAL_KHR\n"); - recreate_swapchain(state); - goto and_try_again; - } else if (pres_ret != VK_SUCCESS) { - abortf("vkQueuePresentKHR"); - } - } - margaret_ns_time frame_B0 = margaret_clock_gettime_monotonic_raw(); - state->frame_count_since_key++; - if (margaret_ns_time_sec_diff(state->prev_key_frame_time, frame_B0) > 1.0) { - float fps = (float)state->frame_count_since_key / margaret_ns_time_sec_diff(state->prev_key_frame_time, frame_B0); - printf("FPS: %0.1f\n", fps); - state->frame_count_since_key = 0; - state->prev_key_frame_time = frame_B0; - } -} - static void main_h_wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time){ state_t *state = data; wl_callback_destroy(cb); - // todo: when I add multiple surfaces, gonna need to think of something smarter state->wl_callback = wl_surface_frame(state->wl_surface); if (!state->wl_callback) abortf("wl_surface_frame\n"); @@ -533,6 +528,10 @@ static void main_h_wl_surface_frame_done(void *data, struct wl_callback *cb, uin update_state(state, time - state->last_frame_time); } vulkano_frame_drawing(state); + // printf("Damaged\n"); + // wl_surface_damage(state->wl_surface, 0, 0, state->width, state->height); + // printf("Commited\n"); + // wl_surface_commit(state->wl_surface); state->last_frame_time = time; } @@ -542,7 +541,7 @@ static const struct wl_callback_listener main_h_wl_surface_frame_listener = { int main() { - state_t state = { .width = 800, .height = 480 }; + state_t state = { .sane_image_extent_limit = {1000, 700}, .width = 800, .height = 480 }; state.wl_display = wl_display_connect(NULL); if (!state.wl_display) @@ -572,18 +571,23 @@ int main() { abortf("xdg_surface_get_toplevel\n"); xdg_toplevel_add_listener(state.xdg_toplevel, &main_h_xdg_toplevel_listener, &state); xdg_toplevel_set_title(state.xdg_toplevel, "r3"); + xdg_toplevel_set_app_id(state.xdg_toplevel, "r3"); wl_surface_commit(state.wl_surface); - // state.wl_callback = wl_surface_frame(state.wl_surface); - // if (!state.wl_callback) - // abortf("wl_surface_frame\n"); - // wl_callback_add_listener(state.wl_callback, &main_h_wl_surface_frame_listener, &state); + state.wl_callback = wl_surface_frame(state.wl_surface); + if (!state.wl_callback) + abortf("wl_surface_frame\n"); + wl_callback_add_listener(state.wl_callback, &main_h_wl_surface_frame_listener, &state); + + // wl_surface_commit(state.wl_surface); + // wl_display_roundtrip(state.wl_display); + // wl_surface_commit(state.wl_surface); state.vk_instance_and_debug = MargaretInstanceAndItsDebug_new(true); VkInstance vk_instance = state.vk_instance_and_debug.instance; state.vk_surface = margaret_create_surface(vk_instance, state.wl_display, state.wl_surface); state.physical_device = margaret_select_one_physical_device(vk_instance, state.vk_surface, - cstr("nvidia"), cstr("NOT SPECIFIED")); + cstr("nvidia"), cstr("NOT SPECIFIED"), state.sane_image_extent_limit); ResultMargaretChosenQueueFamiliesOrSpanU8 queue_fam_res = margaret_choose_good_queue_families( state.physical_device, state.vk_surface); if (queue_fam_res.variant != Result_Ok) @@ -591,10 +595,9 @@ int main() { state.queue_fam = queue_fam_res.ok; state.device = margaret_create_logical_device(state.physical_device, state.queue_fam); vkGetDeviceQueue(state.device, state.queue_fam.for_graphics, 0, &state.graphics_queue); - VkQueue presentation_queue; - vkGetDeviceQueue(state.device, state.queue_fam.for_presentation, 0, &presentation_queue); + vkGetDeviceQueue(state.device, state.queue_fam.for_presentation, 0, &state.presentation_queue); ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( - state.physical_device, state.vk_surface); + state.physical_device, state.vk_surface, state.sane_image_extent_limit); if (swapchain_details_res.variant != Result_Ok) abortf("swapchain_details_res.variant != Result_Ok"); MargaretChosenSwapchainDetails swapchain_details = swapchain_details_res.ok; @@ -610,10 +613,11 @@ int main() { // int wl_display_loop_fd = wl_display_get_fd(state.wl_display); // struct pollfd mainloop_fds[1] = {(struct pollfd){}}; - while (wl_display_dispatch(state.wl_display)) { + while (wl_display_dispatch(state.wl_display) >= 0) { if (state.closed) break; } + printf("Finished!\n"); vkDeviceWaitIdle(state.device); // todo: destroy instance and all the shit