From a1807a4dfa008079da09d88bc65b9dad2ff711d8 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Thu, 28 Aug 2025 18:10:27 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=A3=D0=A3=D0=9F=D0=A1=20X)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/l1/codegen/util_template_inst.h | 8 +- src/l2/codegen/codegen.c | 6 +- src/l2/margaret/vulkan.h | 229 ++++------------------------ src/l2/tests/r0/r0.c | 201 ++++++++++++++++++++++++ src/l2/tests/r3/r3.c | 189 ++++++++++++++++++----- 5 files changed, 391 insertions(+), 242 deletions(-) diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index b7ce591..0c327e7 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -397,10 +397,10 @@ NODISCARD VecU8 generate_OptionT_struct_and_methods(SpanU8 T, bool primitive, bo SPACE4 "%s some;\n" "} %s;\n\n", T, OptionT); - VecU8_append_vec(&res, VecU8_fmt( - "#define None_%s() (%s){ .variant = Option_None }\n" - "#define Some_%s(expr) (%s){ .variant = Option_Some, .some = (expr) }\n\n", - T, OptionT, 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( "const %s* %s_expect_ref(const %s* self){\n" diff --git a/src/l2/codegen/codegen.c b/src/l2/codegen/codegen.c index 613cdc7..ec2537b 100644 --- a/src/l2/codegen/codegen.c +++ b/src/l2/codegen/codegen.c @@ -26,7 +26,7 @@ void eve_of_l2() { generate_eve_span_garden_for_primitive(cstr("l2"), cstr("r0"), cstr("ModelOnScene"), true, false); generate_eve_span_garden_for_primitive(cstr("l2"), cstr("r0"), cstr("UsedModelOnScene"), true, false); /* Needed in margaret/vulkan.h */ - generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("Xlib_Event"), true, false); + generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("Xlib_Event"), true, false); // todo: get rid of this crap generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("CSTR"), true, false); // generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("MargaretChosenQueueFamilies"), true, false); generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkQueueFamilyProperties"), true, false); @@ -35,6 +35,10 @@ void eve_of_l2() { (util_templates_instantiation_options){ .t_primitive = true, .vec = true, .option = true }); generate_eve_header(cstr("l2"), cstr(""), cstr("VkPresentModeKHR"), (util_templates_instantiation_options){ .t_primitive = true, .vec = true, .option = true }); + generate_eve_header(cstr("l2"), cstr(""), cstr("VkCompositeAlphaFlagBitsKHR"), + (util_templates_instantiation_options){ .t_primitive = true, .option = true }); + generate_eve_header(cstr("l2"), cstr(""), cstr("VkExtent2D"), + (util_templates_instantiation_options){ .t_primitive = true, .option = true }); generate_eve_header(cstr("l2"), cstr(""), cstr("VkFormat"), (util_templates_instantiation_options){ .t_primitive = true, .span = true, .option = true }); generate_eve_header(cstr("l2"), cstr(""), cstr("MargaretScoredPhysicalDevice"), diff --git a/src/l2/margaret/vulkan.h b/src/l2/margaret/vulkan.h index be92390..1c9c9e0 100644 --- a/src/l2/margaret/vulkan.h +++ b/src/l2/margaret/vulkan.h @@ -3,94 +3,13 @@ #include "../../../gen/l1/Option_int_primitives.h" #include "../../../gen/l1/VecAndSpan_Vec_int_primitives.h" -// todo: rewrite this crap to wayland (fom now on wayland is my best friend in all situations) -#include -#include #include -#include #include #include "../core/stringop.h" #include "../../l1/system/fileio.h" #include "time.h" #include -// todo: rewrite margaret to use libwayland-client, and get rid of this fucking crap -typedef XEvent Xlib_Event; - -#include "../../../gen/l2/eve/VecXlib_Event.h" - -// todo: AAAAAAAAAAAAA I HATE XLIB SO FUCKINGG MNJUHC AAAASAAAAA AAAAAAA -typedef Display Xlib_Display; -typedef Window Xlib_Window; -typedef Atom Xlib_Atom; - -// todo: AAAAAAAAAAAAAAAA AAASASDASDASDASDAGAHGFKJG AAAAAAAAAAA FUCK XLIB FUCK XORG FUCK THIS SHIT -NODISCARD VecXlib_Event margaret_read_x_events(Xlib_Display* dpy) { - int evh = XEventsQueued(dpy, QueuedAfterReading); - VecXlib_Event result = VecXlib_Event_new_zeroinit(evh); - for (int i = 0; i < evh; i++) { - XNextEvent(dpy, VecXlib_Event_mat(&result, i)); - } - return result; -} - -void margaret_win_init_set_properties(Xlib_Display* dpy, Xlib_Window win) { - const char* strings[] = { - "WM_PROTOCOLS", - "ATOM", - "WM_DELETE_WINDOW" - }; - Atom atoms[3]; - int status; - status = XInternAtoms(dpy, (char**)(strings), 3, False, atoms); - if (status == 0) - abortf("XInternAtoms"); - status = XChangeProperty(dpy, win, atoms[0], atoms[1], 32, PropModeReplace, (unsigned char *)&atoms[2], 1); - if (status == 0) - abortf("XChangeProperty"); -} - -// todo: delete this crap -typedef struct { - Xlib_Atom A_WM_windel; - Xlib_Atom A_WM_protocols; - int width; - int height; - bool should_stop; - Xlib_Window win; -} Margaret_WEP; - -// todo: delete this crap -Margaret_WEP Margaret_WEP_new(Xlib_Display* dpy, Xlib_Window win) { - return (Margaret_WEP){ - .A_WM_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False), - .A_WM_windel = XInternAtom(dpy, "WM_DELETE_WINDOW", False), - .should_stop = false, - .win = win, - }; -} - -// todo: delete this crap -void Margaret_WEP_update_with_new_event(Margaret_WEP* self, const Xlib_Event* ev) { - if (ev->xany.window != self->win) - return; - if (ev->type == ConfigureNotify) { - printf("That was ConfigureNotify\n"); - self->width = ev->xconfigure.width; - self->height = ev->xconfigure.height; - } else if (ev->type == ClientMessage) { - printf("That was ClientMessage\n"); - if (ev->xclient.message_type == self->A_WM_protocols && - ev->xclient.format == 32 && ev->xclient.data.l[0] == self->A_WM_windel - ){ - printf("WM_DELETE_WINDOW\n"); - self->should_stop = true; - } - } else if (ev->type == DestroyNotify) { - printf("That was DestroyNotify\n"); - self->should_stop = true; - } -} void margaret_create_debug_utils_messenger_EXT( VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, @@ -134,73 +53,6 @@ typedef struct { VkDebugUtilsMessengerEXT debug_messenger; } MargaretInstanceAndItsDebug; -// todo: delete this crap -MargaretInstanceAndItsDebug MargaretInstanceAndItsDebug_new_xlib_flavour(bool enable_validation_layers) { - // InstanceAndDebugHands res{}; - VkApplicationInfo app_info = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = "Kto prochital tot zdohnet", - .applicationVersion = VK_MAKE_VERSION(1, 0, 0), - .pEngineName = "Margaret", - .engineVersion = VK_MAKE_VERSION(1, 0, 0), - .apiVersion = VK_API_VERSION_1_2, - }; - - VecCSTR needed_extensions = VecCSTR_new(); - VecCSTR_append(&needed_extensions, "VK_KHR_xlib_surface"); - VecCSTR_append(&needed_extensions, "VK_KHR_surface"); - VecCSTR needed_layers = VecCSTR_new(); - if (enable_validation_layers) { - VecCSTR_append(&needed_extensions, "VK_EXT_debug_utils"); - VecCSTR_append(&needed_layers, "VK_LAYER_KHRONOS_validation"); - } - - VkInstanceCreateInfo instance_crinfo = { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - // .pNext may be set to `for-instance-creation-only` Debug Messanger crinfo later - .pApplicationInfo = &app_info, - .enabledLayerCount = needed_layers.len, - .ppEnabledLayerNames = needed_layers.buf, - .enabledExtensionCount = needed_extensions.len, - .ppEnabledExtensionNames = needed_extensions.buf, - }; - - if (enable_validation_layers) { - VkDebugUtilsMessengerCreateInfoEXT debug_messenger_2_crinfo = { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, - .pfnUserCallback = margaret_static_debug_callback, - .pUserData = NULL, - }; - instance_crinfo.pNext = &debug_messenger_2_crinfo; - } - VkInstance instance; - if (vkCreateInstance(&instance_crinfo, NULL, &instance) != VK_SUCCESS) - abortf("Failed to create Vulkan instance"); - VkDebugUtilsMessengerEXT debug_messenger = NULL; - if (enable_validation_layers) { - VkDebugUtilsMessengerCreateInfoEXT debug_messenger_crinfo = { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, - .pfnUserCallback = margaret_static_debug_callback, - .pUserData = NULL, - }; - margaret_create_debug_utils_messenger_EXT(instance, &debug_messenger_crinfo, NULL, &debug_messenger); - } - - return (MargaretInstanceAndItsDebug){.instance = instance, .debug_messenger = debug_messenger}; -} - NODISCARD MargaretInstanceAndItsDebug MargaretInstanceAndItsDebug_new(bool enable_validation_layers) { VkApplicationInfo app_info = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, @@ -387,8 +239,10 @@ VkDevice margaret_create_logical_device(VkPhysicalDevice physical_device, Margar return device; } +#include "../../../gen/l2/eve/OptionVkExtent2D.h" #include "../../../gen/l2/eve/VecAndOption_VkSurfaceFormatKHR.h" #include "../../../gen/l2/eve/VecAndOption_VkPresentModeKHR.h" +#include "../../../gen/l2/eve/OptionVkCompositeAlphaFlagBitsKHR.h" /* These variables are in some way enforced by VkSurfaceCapabilitiesKHR (but not completely determined) */ typedef struct { @@ -397,6 +251,7 @@ typedef struct { VkExtent2D image_extent; uint32_t image_count; VkSurfaceTransformFlagBitsKHR surface_pre_transform; + VkCompositeAlphaFlagBitsKHR composite_alpha; } MargaretChosenSwapchainDetails; OptionVkSurfaceFormatKHR margaret_choose_surface_format(const VecVkSurfaceFormatKHR* surface_formats) { @@ -423,11 +278,24 @@ OptionVkPresentModeKHR margaret_choose_presentation_mode(const VecVkPresentModeK return res; } -VkExtent2D margaret_choose_image_extent(const VkSurfaceCapabilitiesKHR* capabilities) { +OptionVkCompositeAlphaFlagBitsKHR margaret_choose_composite_alpha(VkCompositeAlphaFlagBitsKHR bits) { + if (bits & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) + return Some_VkCompositeAlphaFlagBitsKHR(VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR); + if (bits & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) + return Some_VkCompositeAlphaFlagBitsKHR(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR); + return None_VkCompositeAlphaFlagBitsKHR(); +} + +OptionVkExtent2D margaret_choose_image_extent(const VkSurfaceCapabilitiesKHR* capabilities, VkExtent2D sane_limits) { if (capabilities->currentExtent.width == UINT32_MAX) { - return (VkExtent2D){ capabilities->maxImageExtent.width, capabilities->maxImageExtent.height,}; - } else - return capabilities->currentExtent; + 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), + MIN_U32(sane_limits.height, sane_limits.height) }); + } + /* May be bigger, than a sane limit */ + return capabilities->currentExtent; } uint32_t margaret_choose_swapchain_image_count(const VkSurfaceCapabilitiesKHR* capabilities) { @@ -478,6 +346,11 @@ ResultMargaretChosenSwapchainDetailsOrSpanU8 margaret_choose_swapchain_details(V VkExtent2D image_extent = margaret_choose_image_extent(&surface_capabilities); uint32_t image_count = margaret_choose_swapchain_image_count(&surface_capabilities); + OptionVkCompositeAlphaFlagBitsKHR chosen_composite_alpha = margaret_choose_composite_alpha( + surface_capabilities.supportedCompositeAlpha); + if (chosen_composite_alpha.variant == Option_None) + return (ResultMargaretChosenSwapchainDetailsOrSpanU8){.variant = Result_Err, .err = cstr("No composite alpha")}; + VecVkSurfaceFormatKHR_drop(surface_formats); VecVkPresentModeKHR_drop(pres_modes); @@ -485,7 +358,8 @@ ResultMargaretChosenSwapchainDetailsOrSpanU8 margaret_choose_swapchain_details(V .ok = (MargaretChosenSwapchainDetails){ .surface_format = chosen_surface_format.some, .presentation_mode = chosen_present_mode.some, .image_extent = image_extent, .image_count = image_count, - .surface_pre_transform = surface_capabilities.currentTransform + .surface_pre_transform = surface_capabilities.currentTransform, + .composite_alpha = chosen_composite_alpha.some } }; } @@ -673,7 +547,7 @@ VkSwapchainKHR margaret_create_swapchain ( .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // Filling imageSharingMode and queueFamilyIndexes later .preTransform = swapchain_details.surface_pre_transform, - .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + .compositeAlpha = swapchain_details.composite_alpha, .presentMode = swapchain_details.presentation_mode, .clipped = VK_TRUE, .oldSwapchain = old_swapchain, @@ -867,53 +741,6 @@ VkCommandBuffer margaret_allocate_command_buffer(VkDevice device, VkCommandPool return res; } -// todo: remove this dumb crap -typedef struct { - Xlib_Display* dpy; - Xlib_Window win; -} MargaretSingleWindowSetup_XlibFlavour; - -// todo: delte this garbage -MargaretSingleWindowSetup_XlibFlavour MargaretSingleWindowSetup_XlibFlavour_new() { - Display *dpy = XOpenDisplay(NULL); - if (!dpy) - abortf("Unable to open X display"); - - int screen = DefaultScreen(dpy); - Window root = RootWindow(dpy, screen); - - unsigned long black = BlackPixel(dpy, screen); - unsigned long white = WhitePixel(dpy, screen); - int win_x = 50, win_y = 50; - unsigned int win_w = 400, win_h = 300; - Window win = XCreateSimpleWindow( - dpy, root, - win_x, win_y, win_w, win_h, - 1, black, white - ); - margaret_win_init_set_properties(dpy, win); - - /* 3) Select for ConfigureNotify and Expose events */ - XSelectInput(dpy, win, StructureNotifyMask | ExposureMask | PointerMotionMask | KeyPressMask | KeyReleaseMask); - return (MargaretSingleWindowSetup_XlibFlavour){ .dpy = dpy, .win = win }; -} - -// todo: ahfadlhja kjdelete this crap -void MargaretSingleWindowSetup_XlibFlavour_drop(MargaretSingleWindowSetup_XlibFlavour x) { - XDestroyWindow(x.dpy, x.win); - XCloseDisplay(x.dpy); -} - -// todo: delete this crap. We are gonna use libwayland -VkSurfaceKHR margaret_create_surface_x_dunk(VkInstance instance, const MargaretSingleWindowSetup_XlibFlavour* x) { - VkXlibSurfaceCreateInfoKHR surface_crinfo = { - .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, .dpy = x->dpy, .window = x->win, - }; - VkSurfaceKHR surface; - if (vkCreateXlibSurfaceKHR(instance, &surface_crinfo, NULL, &surface) != VK_SUCCESS) - abortf("Failed to create Vulkan surface"); - return surface; -} VkSurfaceKHR margaret_create_surface(VkInstance instance, struct wl_display* wl_display, struct wl_surface* wl_surface) { VkWaylandSurfaceCreateInfoKHR crinfo = { diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index 97936af..a5d9b7a 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -6,6 +6,207 @@ #include "r0_scene.h" #include // Only for linux +/* I temporarily moved all the Xlib crap here, away from margaret. todo: remove crap from here too */ +// todo: rewrite this crap to wayland (fom now on wayland is my best friend in all situations) +#include +#include +#include +// todo: rewrite margaret to use libwayland-client, and get rid of this fucking crap +typedef XEvent Xlib_Event; + +#include "../../../../gen/l2/eve/VecXlib_Event.h" + +// todo: AAAAAAAAAAAAA I HATE XLIB SO FUCKINGG MNJUHC AAAASAAAAA AAAAAAA +typedef Display Xlib_Display; +typedef Window Xlib_Window; +typedef Atom Xlib_Atom; + +// todo: AAAAAAAAAAAAAAAA AAASASDASDASDASDAGAHGFKJG AAAAAAAAAAA FUCK XLIB FUCK XORG FUCK THIS SHIT +NODISCARD VecXlib_Event margaret_read_x_events(Xlib_Display* dpy) { + int evh = XEventsQueued(dpy, QueuedAfterReading); + VecXlib_Event result = VecXlib_Event_new_zeroinit(evh); + for (int i = 0; i < evh; i++) { + XNextEvent(dpy, VecXlib_Event_mat(&result, i)); + } + return result; +} + +void margaret_win_init_set_properties(Xlib_Display* dpy, Xlib_Window win) { + const char* strings[] = { + "WM_PROTOCOLS", + "ATOM", + "WM_DELETE_WINDOW" + }; + Atom atoms[3]; + int status; + status = XInternAtoms(dpy, (char**)(strings), 3, False, atoms); + if (status == 0) + abortf("XInternAtoms"); + status = XChangeProperty(dpy, win, atoms[0], atoms[1], 32, PropModeReplace, (unsigned char *)&atoms[2], 1); + if (status == 0) + abortf("XChangeProperty"); +} + +// todo: delete this crap +typedef struct { + Xlib_Atom A_WM_windel; + Xlib_Atom A_WM_protocols; + int width; + int height; + bool should_stop; + Xlib_Window win; +} Margaret_WEP; + +// todo: delete this crap +Margaret_WEP Margaret_WEP_new(Xlib_Display* dpy, Xlib_Window win) { + return (Margaret_WEP){ + .A_WM_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False), + .A_WM_windel = XInternAtom(dpy, "WM_DELETE_WINDOW", False), + .should_stop = false, + .win = win, + }; +} + +// todo: delete this crap +void Margaret_WEP_update_with_new_event(Margaret_WEP* self, const Xlib_Event* ev) { + if (ev->xany.window != self->win) + return; + if (ev->type == ConfigureNotify) { + printf("That was ConfigureNotify\n"); + self->width = ev->xconfigure.width; + self->height = ev->xconfigure.height; + } else if (ev->type == ClientMessage) { + printf("That was ClientMessage\n"); + if (ev->xclient.message_type == self->A_WM_protocols && + ev->xclient.format == 32 && ev->xclient.data.l[0] == self->A_WM_windel + ){ + printf("WM_DELETE_WINDOW\n"); + self->should_stop = true; + } + } else if (ev->type == DestroyNotify) { + printf("That was DestroyNotify\n"); + self->should_stop = true; + } +} + + +// todo: delete this crap +MargaretInstanceAndItsDebug MargaretInstanceAndItsDebug_new_xlib_flavour(bool enable_validation_layers) { + // InstanceAndDebugHands res{}; + VkApplicationInfo app_info = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "Kto prochital tot zdohnet", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "Margaret", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_2, + }; + + VecCSTR needed_extensions = VecCSTR_new(); + VecCSTR_append(&needed_extensions, "VK_KHR_xlib_surface"); + VecCSTR_append(&needed_extensions, "VK_KHR_surface"); + VecCSTR needed_layers = VecCSTR_new(); + if (enable_validation_layers) { + VecCSTR_append(&needed_extensions, "VK_EXT_debug_utils"); + VecCSTR_append(&needed_layers, "VK_LAYER_KHRONOS_validation"); + } + + VkInstanceCreateInfo instance_crinfo = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + // .pNext may be set to `for-instance-creation-only` Debug Messanger crinfo later + .pApplicationInfo = &app_info, + .enabledLayerCount = needed_layers.len, + .ppEnabledLayerNames = needed_layers.buf, + .enabledExtensionCount = needed_extensions.len, + .ppEnabledExtensionNames = needed_extensions.buf, + }; + + if (enable_validation_layers) { + VkDebugUtilsMessengerCreateInfoEXT debug_messenger_2_crinfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = margaret_static_debug_callback, + .pUserData = NULL, + }; + instance_crinfo.pNext = &debug_messenger_2_crinfo; + } + VkInstance instance; + if (vkCreateInstance(&instance_crinfo, NULL, &instance) != VK_SUCCESS) + abortf("Failed to create Vulkan instance"); + VkDebugUtilsMessengerEXT debug_messenger = NULL; + if (enable_validation_layers) { + VkDebugUtilsMessengerCreateInfoEXT debug_messenger_crinfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = margaret_static_debug_callback, + .pUserData = NULL, + }; + margaret_create_debug_utils_messenger_EXT(instance, &debug_messenger_crinfo, NULL, &debug_messenger); + } + + return (MargaretInstanceAndItsDebug){.instance = instance, .debug_messenger = debug_messenger}; +} + +// todo: remove this dumb crap +typedef struct { + Xlib_Display* dpy; + Xlib_Window win; +} MargaretSingleWindowSetup_XlibFlavour; + +// todo: delte this garbage +MargaretSingleWindowSetup_XlibFlavour MargaretSingleWindowSetup_XlibFlavour_new() { + Display *dpy = XOpenDisplay(NULL); + if (!dpy) + abortf("Unable to open X display"); + + int screen = DefaultScreen(dpy); + Window root = RootWindow(dpy, screen); + + unsigned long black = BlackPixel(dpy, screen); + unsigned long white = WhitePixel(dpy, screen); + int win_x = 50, win_y = 50; + unsigned int win_w = 400, win_h = 300; + Window win = XCreateSimpleWindow( + dpy, root, + win_x, win_y, win_w, win_h, + 1, black, white + ); + margaret_win_init_set_properties(dpy, win); + + /* 3) Select for ConfigureNotify and Expose events */ + XSelectInput(dpy, win, StructureNotifyMask | ExposureMask | PointerMotionMask | KeyPressMask | KeyReleaseMask); + return (MargaretSingleWindowSetup_XlibFlavour){ .dpy = dpy, .win = win }; +} + +// todo: ahfadlhja kjdelete this crap +void MargaretSingleWindowSetup_XlibFlavour_drop(MargaretSingleWindowSetup_XlibFlavour x) { + XDestroyWindow(x.dpy, x.win); + XCloseDisplay(x.dpy); +} + +// todo: delete this crap. We are gonna use libwayland +VkSurfaceKHR margaret_create_surface_x_dunk(VkInstance instance, const MargaretSingleWindowSetup_XlibFlavour* x) { + VkXlibSurfaceCreateInfoKHR surface_crinfo = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, .dpy = x->dpy, .window = x->win, + }; + VkSurfaceKHR surface; + if (vkCreateXlibSurfaceKHR(instance, &surface_crinfo, NULL, &surface) != VK_SUCCESS) + abortf("Failed to create Vulkan surface"); + return surface; +} + + + // todo: generate this class in l2 typedef struct { VkPipelineLayout pipeline_layout; diff --git a/src/l2/tests/r3/r3.c b/src/l2/tests/r3/r3.c index b0e3c1f..16ba177 100644 --- a/src/l2/tests/r3/r3.c +++ b/src/l2/tests/r3/r3.c @@ -80,7 +80,7 @@ void reset_and_record_command_buffer_0( if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS) abortf("vkBeginCommandBuffer"); - VkClearValue clear_values[1] = {{.color = {.float32={0, fabsf(sinf(ht)), 0, 1}}},}; + VkClearValue clear_values[1] = {{.color = {.float32={1, fabsf(sinf(ht)), 0, 1}}},}; VkRenderPassBeginInfo renderpass_begin = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = render_pass_0, @@ -138,7 +138,11 @@ typedef struct { VkSurfaceKHR vk_surface; VkQueue graphics_queue; VkQueue presentation_queue; + VkRenderPass render_pass_0; MargaretSwapchainBundle swfb; + VkCommandPool command_pool; + VkCommandBuffer rendering_command_buffer_0; + Jane_r3 jane; /* inputs */ struct wl_pointer* pointer; struct wl_keyboard* keyboard; @@ -153,6 +157,9 @@ typedef struct { int32_t height; bool closed; bool first_0x80_keys[0x80]; + /* framerate counting */ + U32 frame_count_since_key; + margaret_ns_time prev_key_frame_time; } state_t; void draw_frame(state_t* state, uint32_t* data, int32_t width, int32_t height) { @@ -403,30 +410,135 @@ static const struct wl_registry_listener main_h_wl_registry_listener = { .global_remove = main_h_wl_registry_global_remove, }; -// 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 -// 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); -// -// if (state->last_frame_time != 0) { -// update_state(state, time - state->last_frame_time); -// } -// -// state->swapchain.want_to_draw = true; -// try_drawing_frame(state); -// -// state->last_frame_time = time; -// } -// -// static const struct wl_callback_listener main_h_wl_surface_frame_listener = { -// .done = main_h_wl_surface_frame_done, -// }; +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"); + wl_callback_add_listener(state->wl_callback, &main_h_wl_surface_frame_listener, state); + + if (state->last_frame_time != 0) { + update_state(state, time - state->last_frame_time); + } + vulkano_frame_drawing(state); + state->last_frame_time = time; +} + +static const struct wl_callback_listener main_h_wl_surface_frame_listener = { + .done = main_h_wl_surface_frame_done, +}; int main() { @@ -481,28 +593,33 @@ int main() { 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); - ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(physical_device, vk_surface); + 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; - VkRenderPass render_pass_0 = create_render_pass_0(device, swapchain_details.surface_format.format); + state.render_pass_0 = create_render_pass_0(state.device, swapchain_details.surface_format.format); // PipelineHands pipeline_hands_0 = create_graphics_pipeline_0(device, render_pass_0, 0); - MargaretSwapchainBundle swfb = MargaretSwapchainBundle_new(device, queue_fam, swapchain_details_res.ok, vk_surface, render_pass_0, NULL); - VkCommandPool command_pool = margaret_create_resettable_command_pool(device, queue_fam.for_graphics); - VkCommandBuffer rendering_command_buffer_0 = margaret_allocate_command_buffer(device, command_pool); + state.swfb = MargaretSwapchainBundle_new(state.device, state.queue_fam, + swapchain_details_res.ok, state.vk_surface, state.render_pass_0, NULL); + state.command_pool = margaret_create_resettable_command_pool(state.device, state.queue_fam.for_graphics); + state.rendering_command_buffer_0 = margaret_allocate_command_buffer(state.device, state.command_pool); - Jane_r3 jane = Jane_r3_create(device); + state.jane = Jane_r3_create(state.device); - // todo: write what I need to write - int wl_display_loop_fd = wl_display_get_fd(state.wl_display); - struct pollfd mainloop_fds[1] = {(struct pollfd){}}; + // 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)) { if (state.closed) break; } - // if (state.wl_callback) - // wl_callback_destroy(state.wl_callback); + vkDeviceWaitIdle(state.device); + // todo: destroy instance and all the shit + + + if (state.wl_callback) + wl_callback_destroy(state.wl_callback); xdg_toplevel_destroy(state.xdg_toplevel); xdg_surface_destroy(state.xdg_surface); xdg_wm_base_destroy(state.xdg_wm_base);