Compare commits

...

2 Commits

Author SHA1 Message Date
d4d97ed8c6 Now my vulkan program works on wayland (r3) 2025-08-29 15:05:06 +03:00
a1807a4dfa УУУПС X) 2025-08-28 18:10:27 +03:00
6 changed files with 491 additions and 311 deletions

View File

@ -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(%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"

View File

@ -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"),
@ -44,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,

View File

@ -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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_xlib.h>
#include <vulkan/vulkan_wayland.h>
#include "../core/stringop.h"
#include "../../l1/system/fileio.h"
#include "time.h"
#include <wayland-client.h>
// 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 Some_VkExtent2D(capabilities->currentExtent);
}
uint32_t margaret_choose_swapchain_image_count(const VkSurfaceCapabilitiesKHR* capabilities) {
@ -445,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)
@ -475,17 +345,27 @@ 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(
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);
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,
.surface_pre_transform = surface_capabilities.currentTransform
.image_extent = image_extent.some, .image_count = image_count,
.surface_pre_transform = surface_capabilities.currentTransform,
.composite_alpha = chosen_composite_alpha.some
}
};
}
@ -547,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);
@ -589,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")};
}
@ -611,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)
@ -622,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));
@ -631,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);
@ -673,7 +556,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,
@ -697,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,
@ -779,6 +663,7 @@ typedef struct {
VecVkImageView image_views;
VecVkFramebuffer framebuffers;
VkExtent2D extent;
VecVkSemaphore rendering_finished_here_semaphores;
} MargaretSwapchainBundle;
MargaretSwapchainBundle MargaretSwapchainBundle_new(
@ -788,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);
}
@ -867,53 +758,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 = {

View File

@ -6,6 +6,207 @@
#include "r0_scene.h"
#include <sys/wait.h> // 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <vulkan/vulkan_xlib.h>
// 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;
@ -735,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);
@ -759,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;
@ -801,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);
@ -814,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);
@ -830,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");
@ -1082,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();
@ -1182,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");
@ -1274,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,
@ -1294,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) );
@ -1314,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");
@ -1366,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);

View File

@ -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);

View File

@ -11,9 +11,6 @@
#include "../../margaret/vulkan.h"
#include <poll.h>
#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,
}
};
@ -80,7 +77,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,
@ -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;
@ -138,7 +134,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,38 +153,145 @@ 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) {
}
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 = {
@ -195,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;
@ -403,34 +514,34 @@ 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;
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);
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);
// 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;
}
static const struct wl_callback_listener main_h_wl_surface_frame_listener = {
.done = main_h_wl_surface_frame_done,
};
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)
@ -460,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)
@ -479,30 +595,35 @@ 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);
ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(physical_device, vk_surface);
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.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;
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){}};
while (wl_display_dispatch(state.wl_display)) {
// 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) >= 0) {
if (state.closed)
break;
}
// if (state.wl_callback)
// wl_callback_destroy(state.wl_callback);
printf("Finished!\n");
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);