Added Jane to r0. Splitted xlib and wayland margaret code (because I am switching to libwayland). Made some minor enhancements in r1. Wrote r2a program - doublebuffered wayland app that plays instruments. Started writing r3 - wayland client that uses vulkan instance
This commit is contained in:
parent
555712a19d
commit
19b08636a9
@ -43,12 +43,14 @@ target_link_libraries(0_render_test_tex_init_prep -lm)
|
||||
add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon)
|
||||
|
||||
add_executable(2a_render_test src/l2/tests/r2/r2a.c)
|
||||
target_link_libraries(2a_render_test ${LIBPIPEWIRE_LIBS} -lm)
|
||||
add_executable(2a_render_test src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
target_link_libraries(2a_render_test ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon)
|
||||
|
||||
add_executable(2b_render_test src/l2/tests/r2/r2b.c)
|
||||
target_link_libraries(2b_render_test ${LIBPIPEWIRE_LIBS} -lm)
|
||||
|
||||
add_executable(3_render_test src/l2/tests/r3/r3.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
target_link_libraries(3_render_test -lwayland-client -lm -lvulkan -lxkbcommon)
|
||||
|
||||
#add_executable(0_play_test src/l3/tests/p0.c)
|
||||
#target_link_libraries(0_play_test -lncurses)
|
||||
|
||||
23
Makefile
23
Makefile
@ -11,6 +11,7 @@ cflags := -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-typ
|
||||
cc := gcc
|
||||
|
||||
wl_protocols := $(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
||||
libpipewire_flags := $(shell pkg-config --cflags --libs libpipewire-0.3)
|
||||
|
||||
out/l1/codegen: src/l1/codegen/codegen.c $(HEADERS_src_l1)
|
||||
mkdir -p out/l1
|
||||
@ -50,21 +51,31 @@ gen/l_wl_protocols/xdg-shell-private.c: $(wl_protocols)/stable/xdg-shell/xdg-she
|
||||
mkdir -p gen/l_wl_protocols
|
||||
wayland-scanner private-code $< $@
|
||||
|
||||
|
||||
l_wl_protocols := gen/l_wl_protocols/xdg-shell-client.h gen/l_wl_protocols/xdg-shell-private.c
|
||||
|
||||
out/l2/r0: src/l2/tests/r0/r0.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< -lvulkan -lX11 -lm
|
||||
|
||||
#out/l2/r0: src/l2/tests/r0/r0_tex_init_prep.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1)
|
||||
# mkdir -p out/l2
|
||||
# $(cc) $(cflags) -o $@ $< -lm
|
||||
#
|
||||
out/l2/r1: src/l2/tests/r1/r1.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) \
|
||||
gen/l_wl_protocols/xdg-shell-client.h gen/l_wl_protocols/xdg-shell-private.c
|
||||
$(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< gen/l_wl_protocols/xdg-shell-private.c -lwayland-client -lrt -lxkbcommon -lm
|
||||
|
||||
out/l2/r2a: src/l2/tests/r2/r2a.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) \
|
||||
$(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< gen/l_wl_protocols/xdg-shell-private.c -lwayland-client -lrt -lxkbcommon -lm $(libpipewire_flags)
|
||||
|
||||
out/l2/r2b: src/l2/tests/r2/r2b.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< -lwayland-client -lrt -lxkbcommon -lm $(libpipewire_flags)
|
||||
|
||||
out/l2/r3: src/l2/tests/r3/r3.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) \
|
||||
$(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< gen/l_wl_protocols/xdg-shell-private.c -lwayland-client -lrt -lxkbcommon -lm -lvulkan
|
||||
|
||||
clean:
|
||||
rm -rf gen out
|
||||
|
||||
|
||||
@ -25,9 +25,10 @@ void eve_of_l2() {
|
||||
/* Needed in r0_scene.h */
|
||||
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.h */
|
||||
/* 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("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("MargaretChosenQueueFamilies"), true, false);
|
||||
generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkQueueFamilyProperties"), true, false);
|
||||
generate_eve_span_garden_for_primitive(cstr("l2"), cstr(""), cstr("VkExtensionProperties"), true, false);
|
||||
generate_eve_header(cstr("l2"), cstr(""), cstr("VkSurfaceFormatKHR"),
|
||||
@ -61,6 +62,10 @@ void eve_of_l2() {
|
||||
(util_templates_instantiation_options){ .vec = true});
|
||||
generate_eve_header(cstr("l2"), cstr("r2"), cstr("PlayingSound"),
|
||||
(util_templates_instantiation_options){.vec_extended = true});
|
||||
generate_eve_header(cstr("l2"), cstr("r2"), cstr("BoxLizaInstrument"),
|
||||
(util_templates_instantiation_options){ .vec = true});
|
||||
generate_eve_header(cstr("l2"), cstr("r2"), cstr("MyInstrument"),
|
||||
(util_templates_instantiation_options){ .vec = true});
|
||||
}
|
||||
|
||||
void generate_Vec_cvec_header() {
|
||||
|
||||
@ -8,9 +8,11 @@
|
||||
#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;
|
||||
@ -48,6 +50,7 @@ void margaret_win_init_set_properties(Xlib_Display* dpy, Xlib_Window win) {
|
||||
abortf("XChangeProperty");
|
||||
}
|
||||
|
||||
// todo: delete this crap
|
||||
typedef struct {
|
||||
Xlib_Atom A_WM_windel;
|
||||
Xlib_Atom A_WM_protocols;
|
||||
@ -57,6 +60,7 @@ typedef struct {
|
||||
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),
|
||||
@ -66,6 +70,7 @@ Margaret_WEP Margaret_WEP_new(Xlib_Display* dpy, Xlib_Window 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;
|
||||
@ -129,7 +134,8 @@ typedef struct {
|
||||
VkDebugUtilsMessengerEXT debug_messenger;
|
||||
} MargaretInstanceAndItsDebug;
|
||||
|
||||
MargaretInstanceAndItsDebug MargaretInstanceAndItsDebug_new(bool enable_validation_layers) {
|
||||
// todo: delete this crap
|
||||
MargaretInstanceAndItsDebug MargaretInstanceAndItsDebug_new_xlib_flavour(bool enable_validation_layers) {
|
||||
// InstanceAndDebugHands res{};
|
||||
VkApplicationInfo app_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
@ -195,6 +201,72 @@ MargaretInstanceAndItsDebug MargaretInstanceAndItsDebug_new(bool enable_validati
|
||||
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,
|
||||
.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_wayland_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};
|
||||
}
|
||||
|
||||
|
||||
void MargaretInstanceAndItsDebug_drop(MargaretInstanceAndItsDebug instance) {
|
||||
if (instance.debug_messenger) {
|
||||
margaret_destroy_debug_utils_messenger_EXT(instance.instance, instance.debug_messenger, NULL);
|
||||
@ -207,7 +279,6 @@ typedef struct {
|
||||
U32 for_presentation;
|
||||
} MargaretChosenQueueFamilies;
|
||||
|
||||
#include "../../../gen/l2/eve/VecMargaretChosenQueueFamilies.h"
|
||||
#include "../../../gen/l2/eve/VecVkQueueFamilyProperties.h"
|
||||
|
||||
/* MargaretChosenQueueFamilies or a static string, describing which part could not be found
|
||||
@ -241,7 +312,6 @@ ResultMargaretChosenQueueFamiliesOrSpanU8 margaret_choose_good_queue_families(Vk
|
||||
index_for_presentation = Some_U32(i);
|
||||
}
|
||||
VecVkQueueFamilyProperties_drop(queue_families);
|
||||
// todo: method _is_none will soon be gone
|
||||
if (index_for_graphics.variant == Option_None)
|
||||
return (ResultMargaretChosenQueueFamiliesOrSpanU8){ .variant = Result_Err, .err = cstr("No graphics queue family") };
|
||||
if (index_for_presentation.variant == Option_None)
|
||||
@ -704,19 +774,11 @@ VkFence margaret_create_fence(VkDevice device, bool create_signaled) {
|
||||
return res;
|
||||
}
|
||||
|
||||
//todo: strip synchronization lines out of here, pls PLS DO IT ADGASDHH HDJHFHFDKKF DFKDKDK THIS IS SO STUPID
|
||||
// todo: kill myself
|
||||
typedef struct {
|
||||
VkSwapchainKHR swapchain;
|
||||
VecVkImageView image_views;
|
||||
VecVkFramebuffer framebuffers;
|
||||
VkExtent2D extent;
|
||||
|
||||
VkSemaphore in_frame_transfer_complete;
|
||||
VkSemaphore image_available_semaphore;
|
||||
VkSemaphore rendered_to_IT1_semaphore;
|
||||
VkSemaphore render_finished_semaphore;
|
||||
VkFence in_flight_fence;
|
||||
} MargaretSwapchainBundle;
|
||||
|
||||
MargaretSwapchainBundle MargaretSwapchainBundle_new(
|
||||
@ -728,11 +790,6 @@ MargaretSwapchainBundle MargaretSwapchainBundle_new(
|
||||
VecVkFramebuffer framebuffers = margaret_create_swapchain_framebuffers(device, &image_views, render_pass, swapchain_details.image_extent);
|
||||
return (MargaretSwapchainBundle){ .swapchain = swapchain, .image_views = image_views,
|
||||
.framebuffers = framebuffers, .extent = swapchain_details.image_extent,
|
||||
.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),
|
||||
};
|
||||
}
|
||||
|
||||
@ -743,11 +800,6 @@ VkSwapchainKHR MargaretSwapchainBundle_pop_swapchain_drop_rest(VkDevice device,
|
||||
for (size_t i = 0; i < swfb.image_views.len; i++) {
|
||||
vkDestroyImageView(device, *VecVkImageView_at(&swfb.image_views, i), NULL);
|
||||
}
|
||||
vkDestroyFence(device, swfb.in_flight_fence, NULL);
|
||||
vkDestroySemaphore(device, swfb.render_finished_semaphore, NULL);
|
||||
vkDestroySemaphore(device, swfb.rendered_to_IT1_semaphore, NULL);
|
||||
vkDestroySemaphore(device, swfb.image_available_semaphore, NULL);
|
||||
vkDestroySemaphore(device, swfb.in_frame_transfer_complete, NULL);
|
||||
// Old swapchain bundle is 83% dropped
|
||||
return swfb.swapchain;
|
||||
}
|
||||
@ -815,12 +867,14 @@ VkCommandBuffer margaret_allocate_command_buffer(VkDevice device, VkCommandPool
|
||||
return res;
|
||||
}
|
||||
|
||||
// todo: remove this dumb crap
|
||||
typedef struct {
|
||||
Xlib_Display* dpy;
|
||||
Xlib_Window win;
|
||||
} MargaretSingleWindowSetup;
|
||||
} MargaretSingleWindowSetup_XlibFlavour;
|
||||
|
||||
MargaretSingleWindowSetup MargaretSingleWindowSetup_new() {
|
||||
// todo: delte this garbage
|
||||
MargaretSingleWindowSetup_XlibFlavour MargaretSingleWindowSetup_XlibFlavour_new() {
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
if (!dpy)
|
||||
abortf("Unable to open X display");
|
||||
@ -841,15 +895,17 @@ MargaretSingleWindowSetup MargaretSingleWindowSetup_new() {
|
||||
|
||||
/* 3) Select for ConfigureNotify and Expose events */
|
||||
XSelectInput(dpy, win, StructureNotifyMask | ExposureMask | PointerMotionMask | KeyPressMask | KeyReleaseMask);
|
||||
return (MargaretSingleWindowSetup){ .dpy = dpy, .win = win };
|
||||
return (MargaretSingleWindowSetup_XlibFlavour){ .dpy = dpy, .win = win };
|
||||
}
|
||||
|
||||
void MargaretSingleWindowSetup_drop(MargaretSingleWindowSetup x) {
|
||||
// todo: ahfadlhja kjdelete this crap
|
||||
void MargaretSingleWindowSetup_XlibFlavour_drop(MargaretSingleWindowSetup_XlibFlavour x) {
|
||||
XDestroyWindow(x.dpy, x.win);
|
||||
XCloseDisplay(x.dpy);
|
||||
}
|
||||
|
||||
VkSurfaceKHR margaret_create_surface(VkInstance instance, const MargaretSingleWindowSetup* x) {
|
||||
// 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,
|
||||
};
|
||||
@ -859,6 +915,17 @@ VkSurfaceKHR margaret_create_surface(VkInstance instance, const MargaretSingleWi
|
||||
return surface;
|
||||
}
|
||||
|
||||
VkSurfaceKHR margaret_create_surface(VkInstance instance, struct wl_display* wl_display, struct wl_surface* wl_surface) {
|
||||
VkWaylandSurfaceCreateInfoKHR crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||
.display = wl_display, .surface = wl_surface
|
||||
};
|
||||
VkSurfaceKHR surface;
|
||||
if (vkCreateWaylandSurfaceKHR(instance, &crinfo, NULL, &surface) != VK_SUCCESS)
|
||||
abortf("vkCreateWaylandSurfaceKHR\n");
|
||||
return surface;
|
||||
}
|
||||
|
||||
// type_filter is a set of memory types (bit set) and we return one of its elements.
|
||||
// Result must satisfy `properties`
|
||||
// Bit index in `type_filter` is an index in VkPhysicalDeviceMemoryProperties::memoryTypes for that physical_device
|
||||
@ -1098,6 +1165,7 @@ void margaret_copy_buffer_imm (
|
||||
margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer);
|
||||
}
|
||||
|
||||
// todo: get rid of this crap. I can do better
|
||||
// For application initialization purposes only
|
||||
void transition_image_layout (
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
@ -1163,6 +1231,7 @@ void margaret_copy_buffer_to_trans_dst_optimal_image (
|
||||
margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer);
|
||||
}
|
||||
|
||||
// todo: AHFHDF EW WHAT IS THAT???
|
||||
// For application initialization purposes only
|
||||
void margaret_copy_buffer_to_texture_for_frag_shader_imm(
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
@ -1187,6 +1256,7 @@ void margaret_copy_buffer_to_texture_for_frag_shader_imm(
|
||||
);
|
||||
}
|
||||
|
||||
// todo: cjafhs WHAT IS THIS?? I need to remove this. I can do better than this
|
||||
// For texture
|
||||
VkImageView margaret_create_view_for_image (
|
||||
VkDevice device, const MargaretImageInMemoryInfo* image, VkImageAspectFlags aspect_flags
|
||||
@ -1270,19 +1340,6 @@ VkDescriptorPool margaret_create_descriptor_set_pool(VkDevice device,
|
||||
return descriptor_pool;
|
||||
}
|
||||
|
||||
/* Won't actually use this function, it's too underpowered */
|
||||
// void margaret_record_buf_copying_command_buf(VkCommandBuffer command_buffer,
|
||||
// VkBuffer dest_buffer, VkBuffer src_buffer, VkDeviceSize buffer_size
|
||||
// ) {
|
||||
// VkCommandBufferBeginInfo beginfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, };
|
||||
// if (vkBeginCommandBuffer(command_buffer, &beginfo) != VK_SUCCESS)
|
||||
// abortf("vkBeginCommandBuffer");
|
||||
// VkBufferCopy regions_to_copy[1] = {(VkBufferCopy){.srcOffset = 0, .dstOffset = 0, .size = buffer_size}};
|
||||
// vkCmdCopyBuffer(command_buffer, src_buffer, dest_buffer, ARRAY_SIZE(regions_to_copy), regions_to_copy);
|
||||
// if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
|
||||
// abortf("vkEndCommandBuffer");
|
||||
// }
|
||||
|
||||
VkDescriptorSet margaret_allocate_descriptor_set(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSetLayout layout) {
|
||||
VkDescriptorSetAllocateInfo alloc_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
|
||||
@ -19,10 +19,4 @@ void marie_clip_triang_with_triang_append_to_Vec(MarieTriangle C, MarieTriangle
|
||||
marie_clip_ccw_triang_with_ccw_triang_append_to_Vec(C, T, pile);
|
||||
}
|
||||
|
||||
// /* Better allocate 2n elements in pile */
|
||||
// void marie_closed_path_to_polygon_outline_tangy_append_to_Vec(ConstSpanvec2 path, float thickness, VecMarieTriangle* pile) {
|
||||
// size_t n = path.len;
|
||||
// // for (size_t )
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
||||
@ -595,31 +595,6 @@ void reset_and_record_command_buffer_0(
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(command_buffer);
|
||||
|
||||
// VkImageMemoryBarrier barrier = {
|
||||
// .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
// .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
// .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
// .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
// .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
// .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
// .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
// .image = IT1_image,
|
||||
// .subresourceRange = (VkImageSubresourceRange){
|
||||
// .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = 1,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 1,
|
||||
// },
|
||||
// };
|
||||
// vkCmdPipelineBarrier(command_buffer,
|
||||
// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
// VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
// 0,
|
||||
// 0, NULL,
|
||||
// 0, NULL,
|
||||
// 1, &barrier);
|
||||
if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
|
||||
abortf("vkEndCommandBuffer");
|
||||
}
|
||||
@ -755,13 +730,40 @@ void copy_scene_info_to_buffer_and_rerecord_full_copy_command_buffer(
|
||||
abortf("vkEndCommandBuffer");
|
||||
}
|
||||
|
||||
// todo: generate this structure in l2
|
||||
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;
|
||||
|
||||
NODISCARD Jane Jane_create(VkDevice device) {
|
||||
return (Jane){
|
||||
.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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// todo: add here deletion and recreation of several synchronization primitives
|
||||
void recreate_swapchain(
|
||||
VkPhysicalDevice physical_device, VkDevice device, MargaretChosenQueueFamilies queue_fam, VkSurfaceKHR surface,
|
||||
VkRenderPass render_pass, MargaretSwapchainBundle* swfb) {
|
||||
VkRenderPass render_pass, MargaretSwapchainBundle* swfb, Jane* jane) {
|
||||
// We are about stop program and rebuild our sem+sem+fence synchronization mechanism
|
||||
vkDeviceWaitIdle(device);
|
||||
Jane_destroy(device, *jane);
|
||||
*jane = Jane_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);
|
||||
@ -800,17 +802,17 @@ int main() {
|
||||
const U32 MAX_WIN_WIDTH = 1920;
|
||||
const U32 MAX_WIN_HEIGHT = 1080;
|
||||
|
||||
MargaretSingleWindowSetup x = MargaretSingleWindowSetup_new();
|
||||
MargaretSingleWindowSetup_XlibFlavour x = MargaretSingleWindowSetup_XlibFlavour_new();
|
||||
Margaret_WEP wep = Margaret_WEP_new(x.dpy, x.win);
|
||||
XMapWindow(x.dpy, x.win);
|
||||
|
||||
MargaretInstanceAndItsDebug inst_hands = MargaretInstanceAndItsDebug_new(ENABLE_VALIDATION_LAYERS);
|
||||
MargaretInstanceAndItsDebug inst_hands = MargaretInstanceAndItsDebug_new_xlib_flavour(ENABLE_VALIDATION_LAYERS);
|
||||
VkInstance instance = inst_hands.instance;
|
||||
|
||||
// print_instance_available_extensions(instance);
|
||||
// print_instance_available_layers(instance);
|
||||
|
||||
VkSurfaceKHR surface = margaret_create_surface(instance, &x);
|
||||
VkSurfaceKHR surface = margaret_create_surface_x_dunk(instance, &x);
|
||||
|
||||
VkPhysicalDevice physical_device = margaret_select_one_physical_device(instance, surface, GPU, bugged_GPU);
|
||||
|
||||
@ -831,7 +833,6 @@ int main() {
|
||||
ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(physical_device, surface);
|
||||
if (swapchain_details_res.variant != Result_Ok)
|
||||
abortf("swapchain_details_res.variant != Result_Ok");
|
||||
MargaretChosenSwapchainDetails swapchain_details = swapchain_details_res.ok;
|
||||
|
||||
// We hope that the image format won't be changed even when window gets resized
|
||||
// (swapchain_details.surface_format.format)
|
||||
@ -845,10 +846,10 @@ int main() {
|
||||
VkRenderPass render_pass_0 = create_render_pass_0(device, IT1_format.some, zbuffer_format.some);
|
||||
PipelineHands pipeline_hands_0 = create_graphics_pipeline_0(device, render_pass_0, 0);
|
||||
|
||||
VkRenderPass render_pass_1 = create_render_pass_1(device, swapchain_details.surface_format.format);
|
||||
VkRenderPass render_pass_1 = create_render_pass_1(device, swapchain_details_res.ok.surface_format.format);
|
||||
PipelineHands pipeline_hands_1 = create_graphics_pipeline_1(device, render_pass_1, 0);
|
||||
|
||||
MargaretSwapchainBundle swfb = MargaretSwapchainBundle_new(device, queue_fam, swapchain_details, surface, render_pass_1, NULL);
|
||||
MargaretSwapchainBundle swfb = MargaretSwapchainBundle_new(device, queue_fam, swapchain_details_res.ok, surface, render_pass_1, NULL);
|
||||
|
||||
SceneTemplate scene_template = {.models = VecModelInSceneTemplate_new(),
|
||||
.point_lights_max_count = pipeline_0_ubo_point_light_max_count,
|
||||
@ -1081,6 +1082,8 @@ int main() {
|
||||
CamControlInfo my_cam_control_info = CamControlInfo_new();
|
||||
vec3 Buba_control_info = {0};
|
||||
|
||||
Jane jane = Jane_create(device);
|
||||
|
||||
// Mainloop
|
||||
margaret_ns_time start = margaret_clock_gettime_monotonic_raw();
|
||||
margaret_ns_time prev_key_frame_time = start;
|
||||
@ -1171,25 +1174,25 @@ int main() {
|
||||
|
||||
|
||||
// Rendering
|
||||
vkWaitForFences(device, 1, &swfb.in_flight_fence, VK_TRUE, UINT64_MAX);
|
||||
vkWaitForFences(device, 1, &jane.in_flight_fence, VK_TRUE, UINT64_MAX);
|
||||
uint32_t ij;
|
||||
VkResult aq_ret = vkAcquireNextImageKHR(
|
||||
device, swfb.swapchain,
|
||||
UINT64_MAX, swfb.image_available_semaphore, VK_NULL_HANDLE, &ij
|
||||
UINT64_MAX, 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(physical_device, device, queue_fam, surface, render_pass_1, &swfb);
|
||||
recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane);
|
||||
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);
|
||||
recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane);
|
||||
continue;
|
||||
} else if (aq_ret != VK_SUCCESS) {
|
||||
abortf("vkAcquireNextImageKHR");
|
||||
}
|
||||
|
||||
vkResetFences(device, 1, &swfb.in_flight_fence);
|
||||
vkResetFences(device, 1, &jane.in_flight_fence);
|
||||
|
||||
float ae = margaret_ns_time_sec_diff(start, frame_A0);
|
||||
scene.anim_time = ae;
|
||||
@ -1207,7 +1210,7 @@ int main() {
|
||||
transfer_command_buffer, host_mem_buffer.buffer, host_mem_buffer_mem, &scene, device_lighting_ubo.buffer,
|
||||
device_instance_attrs_for_all_generic_meshes.buffer);
|
||||
VkCommandBuffer command_buffers[1] = { transfer_command_buffer };
|
||||
VkSemaphore signaling_semaphores[1] = { swfb.in_frame_transfer_complete };
|
||||
VkSemaphore signaling_semaphores[1] = { jane.in_frame_transfer_complete };
|
||||
VkSubmitInfo submit_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = ARRAY_SIZE(command_buffers),
|
||||
@ -1230,7 +1233,7 @@ int main() {
|
||||
|
||||
{
|
||||
VkSemaphore waiting_for_semaphores_if_dt_transfer_required[1] = {
|
||||
swfb.in_frame_transfer_complete
|
||||
jane.in_frame_transfer_complete
|
||||
};
|
||||
VkPipelineStageFlags waiting_stages_if_dt_transfer_required[1] = {
|
||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
|
||||
@ -1238,7 +1241,7 @@ int main() {
|
||||
assert(ARRAY_SIZE(waiting_for_semaphores_if_dt_transfer_required) ==
|
||||
ARRAY_SIZE(waiting_stages_if_dt_transfer_required));
|
||||
VkCommandBuffer command_buffers[1] = {rendering_command_buffer_0};
|
||||
VkSemaphore signaling_semaphores[1] = { swfb.rendered_to_IT1_semaphore };
|
||||
VkSemaphore signaling_semaphores[1] = { jane.rendered_to_IT1_semaphore };
|
||||
VkSubmitInfo submit_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
|
||||
@ -1262,8 +1265,8 @@ int main() {
|
||||
}
|
||||
{
|
||||
VkSemaphore waiting_for_semaphores[2] = {
|
||||
swfb.image_available_semaphore,
|
||||
swfb.rendered_to_IT1_semaphore };
|
||||
jane.image_available_semaphore,
|
||||
jane.rendered_to_IT1_semaphore };
|
||||
VkPipelineStageFlags waiting_stages[2] = {
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
@ -1271,7 +1274,7 @@ int main() {
|
||||
};
|
||||
assert(ARRAY_SIZE(waiting_for_semaphores) == ARRAY_SIZE(waiting_stages));
|
||||
VkCommandBuffer command_buffers[1] = { rendering_command_buffer_1 };
|
||||
VkSemaphore signaling_semaphores[1] = { swfb.render_finished_semaphore };
|
||||
VkSemaphore signaling_semaphores[1] = { jane.render_finished_semaphore };
|
||||
VkSubmitInfo cmd_submit_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
|
||||
@ -1286,12 +1289,12 @@ int main() {
|
||||
.pSignalSemaphores = signaling_semaphores,
|
||||
};
|
||||
|
||||
if (vkQueueSubmit(graphics_queue, 1, &cmd_submit_info, swfb.in_flight_fence) != VK_SUCCESS)
|
||||
if (vkQueueSubmit(graphics_queue, 1, &cmd_submit_info, jane.in_flight_fence) != VK_SUCCESS)
|
||||
abortf("vkQueueSubmit");
|
||||
}
|
||||
|
||||
{
|
||||
VkSemaphore waiting_for_semaphores[] = { swfb.render_finished_semaphore };
|
||||
VkSemaphore waiting_for_semaphores[] = { jane.render_finished_semaphore };
|
||||
VkSwapchainKHR swapchains[] = { swfb.swapchain };
|
||||
uint32_t image_indices[] = { ij };
|
||||
assert( ARRAY_SIZE(swapchains) == ARRAY_SIZE(image_indices) );
|
||||
@ -1311,11 +1314,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);
|
||||
recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane);
|
||||
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);
|
||||
recreate_swapchain(physical_device, device, queue_fam, surface, render_pass_1, &swfb, &jane);
|
||||
continue;
|
||||
} else if (pres_ret != VK_SUCCESS) {
|
||||
abortf("vkQueuePresentKHR");
|
||||
@ -1363,6 +1366,7 @@ int main() {
|
||||
vkFreeMemory(device, host_mem, NULL);
|
||||
vkDestroyCommandPool(device, command_pool, NULL);
|
||||
MargaretSwapchainBundle_drop_with_device(device, swfb);
|
||||
Jane_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);
|
||||
@ -1370,5 +1374,5 @@ int main() {
|
||||
vkDestroyDevice(device, NULL);
|
||||
vkDestroySurfaceKHR(instance, surface, NULL);
|
||||
MargaretInstanceAndItsDebug_drop(inst_hands);
|
||||
MargaretSingleWindowSetup_drop(x);
|
||||
MargaretSingleWindowSetup_XlibFlavour_drop(x);
|
||||
}
|
||||
|
||||
@ -12,50 +12,37 @@
|
||||
#include "../../marie/graphics_geom.h"
|
||||
#include "../../marie/rasterization.h"
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
||||
#define MAX_BUFFER_WIDTH 1000
|
||||
#define MAX_BUFFER_HEIGHT 800
|
||||
#define SWAPCHAIN_SLOTS 2
|
||||
|
||||
_Static_assert(INT32_MAX / MAX_BUFFER_WIDTH / MAX_BUFFER_HEIGHT / 4 / SWAPCHAIN_SLOTS > 1, "Swapchain is too big");
|
||||
|
||||
// todo: write something normal here
|
||||
/* Shared memory support code */
|
||||
static void randname(char *buf) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
long r = ts.tv_nsec;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
buf[i] = 'A'+(r&15)+(r&16)*2;
|
||||
r >>= 5;
|
||||
static int create_shm_file(){
|
||||
char name[] = "/prototype1-XXXXXXXXXXXX";
|
||||
U64 v = ((U64)rand() << 32) + (U64)rand();
|
||||
for (int i = 0; i < 12; i++) {
|
||||
name[sizeof(name) - 1 - 12 + i] = 'A' + (v&15) + (v&16)*2;
|
||||
v >>= 5;
|
||||
}
|
||||
}
|
||||
|
||||
static int create_shm_file(void){
|
||||
int retries = 100;
|
||||
do {
|
||||
char name[] = "/wl_shm-XXXXXX";
|
||||
randname(name + sizeof(name) - 7);
|
||||
--retries;
|
||||
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
shm_unlink(name);
|
||||
return fd;
|
||||
}
|
||||
} while (retries > 0 && errno == EEXIST);
|
||||
return -1;
|
||||
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0)
|
||||
abortf("shm_open(\"%s\")", name);
|
||||
if (shm_unlink(name) < 0)
|
||||
abortf("shm_unlink(\"%s\")", name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int allocate_shm_file(size_t size) {
|
||||
int fd = create_shm_file();
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
int ret;
|
||||
do {
|
||||
ret = ftruncate(fd, size);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
abortf("ftruncate(%ld)", size);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
@ -104,7 +91,7 @@ typedef struct {
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
bool closed;
|
||||
} audio_thread_state_t;
|
||||
} state_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t* data;
|
||||
@ -123,7 +110,7 @@ void draw_frame_h_rasterizer_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
g->data[y * g->width + x] = color_vec4_to_color_u32(attr);
|
||||
}
|
||||
|
||||
void draw_frame(audio_thread_state_t* state, uint32_t* data, int32_t width, int32_t height) {
|
||||
void draw_frame(state_t* state, uint32_t* data, int32_t width, int32_t height) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
data[y * width + x] = 0xFF00FFFF;
|
||||
@ -170,7 +157,7 @@ void durackaya_tochka_update(durackaya_tochka* dot, float dur, float width, floa
|
||||
}
|
||||
}
|
||||
|
||||
void update_state(audio_thread_state_t* state, uint32_t fl) {
|
||||
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;
|
||||
@ -180,7 +167,7 @@ void update_state(audio_thread_state_t* state, uint32_t fl) {
|
||||
}
|
||||
|
||||
static void main_h_wl_buffer_release(void *data, struct wl_buffer *buffer) {
|
||||
audio_thread_state_t* state = data;
|
||||
state_t* state = data;
|
||||
for (int ij = 0; ij < SWAPCHAIN_SLOTS; ij++) {
|
||||
if (state->swapchain.used_buffers[ij] == buffer) {
|
||||
// printf("Buffer %p was released and destroyed\n", buffer);
|
||||
@ -196,7 +183,7 @@ static const struct wl_buffer_listener main_h_wl_buffer_listener = {
|
||||
.release = main_h_wl_buffer_release,
|
||||
};
|
||||
|
||||
int swapchain_take_slot(audio_thread_state_t *state) {
|
||||
int swapchain_take_slot(state_t *state) {
|
||||
for (int ij = 0; ij < SWAPCHAIN_SLOTS; ij++) {
|
||||
if (!state->swapchain.used_buffers[ij]) {
|
||||
const int32_t width = state->width < MAX_BUFFER_WIDTH ? state->width : MAX_BUFFER_WIDTH;
|
||||
@ -215,7 +202,7 @@ int swapchain_take_slot(audio_thread_state_t *state) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void try_drawing_frame(audio_thread_state_t *state){
|
||||
void try_drawing_frame(state_t *state){
|
||||
if (!state->swapchain.want_to_draw)
|
||||
return;
|
||||
int ij = swapchain_take_slot(state);
|
||||
@ -236,7 +223,7 @@ void try_drawing_frame(audio_thread_state_t *state){
|
||||
}
|
||||
|
||||
static void main_h_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial){
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
printf("XDG surface configured!\n");
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
// todo: synchronize with frame event
|
||||
@ -247,7 +234,7 @@ static void main_h_xdg_surface_configure(void *data, struct xdg_surface *xdg_sur
|
||||
static void main_h_xdg_toplevel_configure(
|
||||
void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states
|
||||
){
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
printf("XDG toplevel configured to (%d %d)\n", width, height);
|
||||
if (width <= 0 || height < 0)
|
||||
return;
|
||||
@ -256,7 +243,7 @@ static void main_h_xdg_toplevel_configure(
|
||||
}
|
||||
|
||||
static void main_h_xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel){
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
state->closed = true;
|
||||
}
|
||||
|
||||
@ -283,11 +270,12 @@ static const struct xdg_wm_base_listener main_h_xdg_wm_base_listener = {
|
||||
static void main_h_wl_keyboard_keymap(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size
|
||||
) {
|
||||
audio_thread_state_t* state = data;
|
||||
// todo: replace asserts with abortf
|
||||
assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
|
||||
state_t* state = data;
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
||||
abortf("O_o");
|
||||
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
assert(map_shm != MAP_FAILED);
|
||||
if (map_shm == MAP_FAILED)
|
||||
abortf("Couldn't mmap new keymap ha-ha\n");
|
||||
|
||||
xkb_keymap_unref(state->xkb_keymap);
|
||||
xkb_state_unref(state->xkb_state);
|
||||
@ -303,7 +291,7 @@ static void main_h_wl_keyboard_keymap(
|
||||
static void main_h_wl_keyboard_enter(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys
|
||||
) {
|
||||
audio_thread_state_t* state = data;
|
||||
state_t* state = data;
|
||||
printf("keyboard enter; keys pressed are:\n");
|
||||
uint32_t *key;
|
||||
wl_array_for_each(key, keys) {
|
||||
@ -322,14 +310,14 @@ static void main_h_wl_keyboard_enter(
|
||||
static void main_h_wl_keyboard_leave(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface
|
||||
) {
|
||||
audio_thread_state_t* state = data;
|
||||
state_t* state = data;
|
||||
memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys));
|
||||
}
|
||||
|
||||
static void main_h_wl_keyboard_key(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t key_action
|
||||
) {
|
||||
audio_thread_state_t* state = data;
|
||||
state_t* state = data;
|
||||
char buf1[128];
|
||||
char buf2[128];
|
||||
uint32_t actual_key = key + 8;
|
||||
@ -350,7 +338,7 @@ static void main_h_wl_keyboard_modifiers(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group
|
||||
) {
|
||||
audio_thread_state_t* state = data;
|
||||
state_t* state = data;
|
||||
xkb_state_update_mask(state->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
@ -372,27 +360,27 @@ static void main_h_wl_pointer_enter(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||
struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y
|
||||
) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
state->pointer_pos = (vec2){(float)surface_x / 256.f, (float)surface_y / 256.f};
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_leave(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface
|
||||
) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_motion(
|
||||
void *data,struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y
|
||||
) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
state->pointer_pos = (vec2){(float)surface_x / 256.f, (float)surface_y / 256.f};
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_button(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t btn_action
|
||||
) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
if (btn_action == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
printf("button = %u\n", button);
|
||||
if (button == 0x110) {
|
||||
@ -404,11 +392,11 @@ static void main_h_wl_pointer_button(
|
||||
static void main_h_wl_pointer_axis(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value
|
||||
) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
const struct wl_pointer_listener main_h_wl_pointer_listener = {
|
||||
@ -421,7 +409,7 @@ const struct wl_pointer_listener main_h_wl_pointer_listener = {
|
||||
};
|
||||
|
||||
static void main_h_wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
|
||||
audio_thread_state_t* state = data;
|
||||
state_t* state = data;
|
||||
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
|
||||
state->pointer = wl_seat_get_pointer(wl_seat);
|
||||
if (!state->pointer)
|
||||
@ -448,7 +436,7 @@ static const struct wl_seat_listener main_h_wl_seat_listener = {
|
||||
static void main_h_wl_registry_global(
|
||||
void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version
|
||||
) {
|
||||
audio_thread_state_t *state = data;
|
||||
state_t *state = data;
|
||||
if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
state->wl_shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1);
|
||||
if (!state->wl_shm)
|
||||
@ -486,7 +474,7 @@ static const struct wl_registry_listener main_h_wl_registry_listener = {
|
||||
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){
|
||||
audio_thread_state_t *state = data;
|
||||
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);
|
||||
@ -510,7 +498,7 @@ static const struct wl_callback_listener main_h_wl_surface_frame_listener = {
|
||||
|
||||
|
||||
int main() {
|
||||
audio_thread_state_t state = { .width = 800, .height = 480 };
|
||||
state_t state = { .width = 800, .height = 480 };
|
||||
state.v0 = (durackaya_tochka){.pos = {10, 10}, .speed = {100, 100}};
|
||||
state.v1 = (durackaya_tochka){.pos = {100, 10}, .speed = {100, -50}};
|
||||
state.v2 = (durackaya_tochka){.pos = {5, 330}, .speed = {-20, 170}};
|
||||
@ -570,9 +558,33 @@ int main() {
|
||||
abortf("wl_surface_frame\n");
|
||||
wl_callback_add_listener(state.wl_callback, &main_h_wl_surface_frame_listener, &state);
|
||||
|
||||
while (wl_display_dispatch(state.wl_display)) {
|
||||
if (state.closed)
|
||||
break;
|
||||
|
||||
int display_fd = wl_display_get_fd(state.wl_display);
|
||||
struct pollfd pollfds[1] = {{.fd = display_fd, .events = POLLIN | POLLERR}};
|
||||
while (!state.closed) {
|
||||
wl_display_prepare_read(state.wl_display);
|
||||
if (wl_display_flush(state.wl_display) < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
printf("Not enough space for a flush!\n");
|
||||
pollfds[0].events |= POLLOUT;
|
||||
}
|
||||
else {
|
||||
abortf("wl_display_flush\n");
|
||||
}
|
||||
} else {
|
||||
pollfds[0].events &= ~POLLOUT;
|
||||
}
|
||||
if (poll(pollfds, ARRAY_SIZE(pollfds), -1) < 0)
|
||||
abortf("poll\n");
|
||||
if (pollfds[0].revents & (POLLIN | POLLERR)) {
|
||||
if (wl_display_read_events(state.wl_display))
|
||||
abortf("wl_display_read_events\n");
|
||||
int ret;
|
||||
if ((ret =wl_display_dispatch_pending(state.wl_display) )< 0)
|
||||
abortf("wl_display_dispatch_pending\n");
|
||||
} else {
|
||||
wl_display_cancel_read(state.wl_display);
|
||||
}
|
||||
}
|
||||
if (state.wl_callback)
|
||||
wl_callback_destroy(state.wl_callback);
|
||||
|
||||
65
src/l2/tests/r2/liza.h
Normal file
65
src/l2/tests/r2/liza.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef PROTOTYPE1_SRC_L2_TESTS_R2_LIZA_H
|
||||
#define PROTOTYPE1_SRC_L2_TESTS_R2_LIZA_H
|
||||
|
||||
typedef struct {
|
||||
/* self (takes ownership) */
|
||||
void (*drop)(void*);
|
||||
/* self, returns: pcm value */
|
||||
double (*next)(void*);
|
||||
/* self, returns: duration in frames */
|
||||
size_t (*get_duration)(const void*);
|
||||
} LizaSound_Table;
|
||||
|
||||
typedef struct {
|
||||
const void* r;
|
||||
const LizaSound_Table* t;
|
||||
} RefLizaSound;
|
||||
|
||||
typedef struct {
|
||||
void* r;
|
||||
const LizaSound_Table* t;
|
||||
} MutRefLizaSound;
|
||||
|
||||
/* Existence of Box<Trait> type implies that _drop method is virtual according to this trait */
|
||||
typedef struct {
|
||||
void* m; /* Owns memory block r and object in it */
|
||||
const LizaSound_Table* t;
|
||||
} BoxLizaSound;
|
||||
|
||||
void BoxLizaSound_drop(BoxLizaSound self) {
|
||||
self.t->drop(self.m);
|
||||
free(self.m);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l2/eve/r2/VecBoxLizaSound.h"
|
||||
|
||||
typedef struct {
|
||||
/* self (takes ownership) */
|
||||
void (*drop)(void*);
|
||||
/* self, frequency, time, returns: new sound box */
|
||||
BoxLizaSound (*ding)(const void*, double, double);
|
||||
// todo: request options for instrument
|
||||
} LizaInstrument_Table;
|
||||
|
||||
typedef struct {
|
||||
const void* r;
|
||||
const LizaInstrument_Table* t;
|
||||
} RefLizaInstrument;
|
||||
|
||||
typedef struct {
|
||||
void* r;
|
||||
const LizaInstrument_Table* t;
|
||||
} MutLizaInstrument;
|
||||
|
||||
typedef struct {
|
||||
void* m;
|
||||
const LizaInstrument_Table* t;
|
||||
} BoxLizaInstrument;
|
||||
|
||||
void BoxLizaInstrument_drop(BoxLizaInstrument self) {
|
||||
self.t->drop(self.m);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l2/eve/r2/VecBoxLizaInstrument.h"
|
||||
|
||||
#endif
|
||||
285
src/l2/tests/r2/liza_collection.h
Normal file
285
src/l2/tests/r2/liza_collection.h
Normal file
@ -0,0 +1,285 @@
|
||||
#ifndef PROTOTYPE1_SRC_L2_TESTS_R2_LIZA_COLLECTION_H
|
||||
#define PROTOTYPE1_SRC_L2_TESTS_R2_LIZA_COLLECTION_H
|
||||
|
||||
#include "liza.h"
|
||||
|
||||
// todo: dfasjshfdasfkjld
|
||||
// double get_decay_factor(double planned_decay_time, double passes_per_second) {
|
||||
// return pow(0.01, 1 / (planned_decay_time * passes_per_second));
|
||||
// }
|
||||
|
||||
/* WeirdGuitar that produces StringTwitchSound */
|
||||
|
||||
// todo: remove decay_factor, replace with decay base
|
||||
// todo: replace ding randomness with something better
|
||||
typedef struct {
|
||||
double rate;
|
||||
double ta;
|
||||
double decay_base;
|
||||
double planned_time;
|
||||
|
||||
double time;
|
||||
double* buffer;
|
||||
int buffer_size;
|
||||
int i;
|
||||
|
||||
} StringTwitchSound;
|
||||
|
||||
StringTwitchSound StringTwitchSound_new(double frequency, double time, double rate) {
|
||||
int buffer_size = (int)(rate / frequency);
|
||||
double* buffer = safe_calloc(buffer_size, sizeof(double));
|
||||
for (int i = 0; i < buffer_size; i++) {
|
||||
/* random noise in [-1, 1] */
|
||||
buffer[i] = ((double)rand() / RAND_MAX) * 2.0 - 1.0;
|
||||
}
|
||||
return (StringTwitchSound){
|
||||
.rate = rate, .ta = 0.01, .decay_base = pow(0.01, 1/time), .planned_time = 0.01 + time,
|
||||
.buffer = buffer, .buffer_size = buffer_size, .i = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void StringTwitchSound_drop(StringTwitchSound self) {
|
||||
free(self.buffer);
|
||||
}
|
||||
|
||||
double StringTwitchSound_next(StringTwitchSound* self) {
|
||||
double volume_c = (self->time > self->ta) ? pow(self->decay_base, self->time) : self->time / self->ta;
|
||||
int j = (self->i + 1) % self->buffer_size;
|
||||
double A = self->buffer[self->i];
|
||||
double B = self->buffer[j];
|
||||
self->buffer[self->i] = 0.5 * (A + B);
|
||||
self->i = j;
|
||||
self->time += 1. / self->rate;
|
||||
return A * volume_c;
|
||||
}
|
||||
|
||||
size_t StringTwitchSound_get_duration(const StringTwitchSound* self) {
|
||||
return (size_t)ceil(self->planned_time * self->rate);
|
||||
}
|
||||
|
||||
void LizaSound_Table_StringTwitchSound_drop(void* g) {
|
||||
StringTwitchSound_drop(*(StringTwitchSound*)g);
|
||||
}
|
||||
double LizaSound_Table_StringTwitchSound_next(void* g) {
|
||||
return StringTwitchSound_next(g);
|
||||
}
|
||||
size_t LizaSound_Table_StringTwitchSound_get_duration(const void* g) {
|
||||
return StringTwitchSound_get_duration(g);
|
||||
}
|
||||
const LizaSound_Table LizaSound_Table_StringTwitchSound = {
|
||||
.drop = LizaSound_Table_StringTwitchSound_drop,
|
||||
.next = LizaSound_Table_StringTwitchSound_next,
|
||||
.get_duration = LizaSound_Table_StringTwitchSound_get_duration
|
||||
};
|
||||
|
||||
BoxLizaSound BoxLizaSound_from_StringTwitchSound(StringTwitchSound obj) {
|
||||
void* mem = safe_malloc(sizeof(StringTwitchSound));
|
||||
memcpy(mem, &obj, sizeof(StringTwitchSound));
|
||||
return (BoxLizaSound){.m = mem, .t = &LizaSound_Table_StringTwitchSound};
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
double rate;
|
||||
} WeirdGuitar;
|
||||
|
||||
WeirdGuitar WeirdGuitar_new(double rate) {
|
||||
return (WeirdGuitar){.rate = rate};
|
||||
}
|
||||
|
||||
StringTwitchSound WeirdGuitar_ding(const WeirdGuitar* self, double frequency, double time) {
|
||||
return StringTwitchSound_new(frequency, time, self->rate);
|
||||
}
|
||||
|
||||
void LizaInstrument_Table_WeirdGuitar_drop(void* self) {
|
||||
|
||||
}
|
||||
BoxLizaSound LizaInstrument_Table_WeirdGuitar_ding(const void* self, double frequency, double time) {
|
||||
return BoxLizaSound_from_StringTwitchSound(WeirdGuitar_ding(self, frequency, time));
|
||||
}
|
||||
const LizaInstrument_Table LizaInstrument_Table_WeirdGuitar = {
|
||||
.drop = LizaInstrument_Table_WeirdGuitar_drop,
|
||||
.ding = LizaInstrument_Table_WeirdGuitar_ding
|
||||
};
|
||||
|
||||
BoxLizaInstrument BoxLizaInstrument_from_WeirdGuitar(WeirdGuitar obj) {
|
||||
void* mem = safe_malloc(sizeof(WeirdGuitar));
|
||||
memcpy(mem, &obj, sizeof(WeirdGuitar));
|
||||
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_WeirdGuitar};
|
||||
}
|
||||
|
||||
/* ElectroBlaster which produces AmplitudeModulationSound */
|
||||
|
||||
typedef struct {
|
||||
double rate;
|
||||
double mod_frequency;
|
||||
double second_frequency;
|
||||
double low_amplitude;
|
||||
double ta;
|
||||
double decay_base;
|
||||
double planned_time;
|
||||
|
||||
double ph1;
|
||||
double ph2;
|
||||
double time;
|
||||
} AmplitudeModulationSound;
|
||||
|
||||
double AmplitudeModulationSound_next(AmplitudeModulationSound* self) {
|
||||
double volume_c = (self->time > self->ta) ? pow(self->decay_base, self->time) : self->time / self->ta;
|
||||
double res = volume_c * (self->low_amplitude + (sin(self->ph2) + 1) * (1 - self->low_amplitude) / 2) * sin(self->ph1);
|
||||
self->ph1 += 2 * M_PI * self->mod_frequency / self->rate;
|
||||
if (self->ph1 > 2 * M_PI)
|
||||
self->ph1 -= 2 * M_PI;
|
||||
self->ph2 += 2 * M_PI * self->second_frequency / self->rate;
|
||||
if (self->ph2 > 2 * M_PI)
|
||||
self->ph2 -= 2 * M_PI;
|
||||
self->time += 1. / self->rate;
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t AmplitudeModulationSound_get_duration(const AmplitudeModulationSound* self) {
|
||||
return (size_t)ceil(self->planned_time * self->rate);
|
||||
}
|
||||
|
||||
void LizaSound_Table_AmplitudeModulationSound_drop(void* self) {
|
||||
|
||||
}
|
||||
double LizaSound_Table_AmplitudeModulationSound_next(void* self) {
|
||||
return AmplitudeModulationSound_next(self);
|
||||
}
|
||||
size_t LizaSound_Table_AmplitudeModulationSound_get_duration(const void* self) {
|
||||
return AmplitudeModulationSound_get_duration(self);
|
||||
}
|
||||
const LizaSound_Table LizaSound_Table_AmplitudeModulationSound = {
|
||||
.drop = LizaSound_Table_AmplitudeModulationSound_drop,
|
||||
.next = LizaSound_Table_AmplitudeModulationSound_next,
|
||||
.get_duration = LizaSound_Table_AmplitudeModulationSound_get_duration,
|
||||
};
|
||||
|
||||
BoxLizaSound BoxLizaSound_from_AmplitudeModulationSound(AmplitudeModulationSound obj) {
|
||||
void* mem = safe_malloc(sizeof(AmplitudeModulationSound));
|
||||
memcpy(mem, &obj, sizeof(AmplitudeModulationSound));
|
||||
return (BoxLizaSound){.m = mem, .t = &LizaSound_Table_AmplitudeModulationSound};
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
double rate;
|
||||
} AMKeys;
|
||||
|
||||
AMKeys AMKeys_new(double rate) {
|
||||
return (AMKeys){rate};
|
||||
}
|
||||
|
||||
AmplitudeModulationSound AMKeys_ding(const AMKeys* self, double frequency, double time) {
|
||||
return (AmplitudeModulationSound){
|
||||
.rate = self->rate, .mod_frequency = frequency, .second_frequency = 600,
|
||||
.low_amplitude = 0.1, .ta = 0.01, .decay_base = pow(0.01, 1/time), .planned_time = 0.01 + time,
|
||||
};
|
||||
}
|
||||
|
||||
void LizaInstrument_Table_AMKeys_drop(void* self) {
|
||||
|
||||
}
|
||||
BoxLizaSound LizaInstrument_Table_AMKeys_ding(const void* self, double freq, double time) {
|
||||
return BoxLizaSound_from_AmplitudeModulationSound(AMKeys_ding(self, freq, time));
|
||||
}
|
||||
const LizaInstrument_Table LizaInstrument_Table_AMKeys = {
|
||||
.drop = LizaInstrument_Table_AMKeys_drop,
|
||||
.ding = LizaInstrument_Table_AMKeys_ding
|
||||
};
|
||||
|
||||
BoxLizaInstrument BoxLizaInstrument_from_AMKeys(AMKeys obj) {
|
||||
void* mem = safe_malloc(sizeof(AMKeys));
|
||||
memcpy(mem, &obj, sizeof(AMKeys));
|
||||
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_AMKeys};
|
||||
}
|
||||
|
||||
/* FMKeys which produces FrequencyModulationSound */
|
||||
|
||||
typedef struct {
|
||||
double rate;
|
||||
double freq_1;
|
||||
double freq_2;
|
||||
double fmc;
|
||||
double ta;
|
||||
double decay_base;
|
||||
double planned_time;
|
||||
|
||||
double ph1;
|
||||
double ph2;
|
||||
double time;
|
||||
} FrequencyModulationSound;
|
||||
|
||||
double FrequencyModulationSound_next(FrequencyModulationSound* self) {
|
||||
double volume_c = (self->time > self->ta) ? pow(self->decay_base, self->time) : self->time / self->ta;
|
||||
double res = volume_c * sin(self->ph1);
|
||||
self->ph1 += 2 * M_PI / self->rate * pow(self->freq_1, self->fmc * sin(self->ph2));
|
||||
if (self->ph1 > 2 * M_PI)
|
||||
self->ph1 -= 2 * M_PI;
|
||||
self->ph2 += 2 * M_PI * self->freq_2 / self->rate;
|
||||
if (self->ph2 > 2 * M_PI)
|
||||
self->ph2 -= 2 * M_PI;
|
||||
self->time += 1. / self->rate;
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t FrequencyModulationSound_get_duration(const FrequencyModulationSound* self) {
|
||||
return (size_t)ceil(self->planned_time * self->rate);
|
||||
}
|
||||
|
||||
void LizaSound_Table_FrequencyModulationSound_drop(void* self) {
|
||||
|
||||
}
|
||||
double LizaSound_Table_FrequencyModulationSound_next(void* self) {
|
||||
return FrequencyModulationSound_next(self);
|
||||
}
|
||||
size_t LizaSound_Table_FrequencyModulationSound_get_duration(const void* self) {
|
||||
return FrequencyModulationSound_get_duration(self);
|
||||
}
|
||||
const LizaSound_Table LizaSound_Table_FrequencyModulationSound = {
|
||||
.drop = LizaSound_Table_FrequencyModulationSound_drop,
|
||||
.next = LizaSound_Table_FrequencyModulationSound_next,
|
||||
.get_duration = LizaSound_Table_FrequencyModulationSound_get_duration
|
||||
};
|
||||
|
||||
BoxLizaSound BoxLizaSound_from_FrequencyModulationSound(FrequencyModulationSound obj) {
|
||||
void* mem = safe_malloc(sizeof(FrequencyModulationSound));
|
||||
memcpy(mem, &obj, sizeof(FrequencyModulationSound));
|
||||
return (BoxLizaSound){.m = mem, .t = &LizaSound_Table_FrequencyModulationSound};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
double rate;
|
||||
} FMKeys;
|
||||
|
||||
FMKeys FMKeys_new(double rate) {
|
||||
return (FMKeys){rate};
|
||||
}
|
||||
|
||||
FrequencyModulationSound FMKeys_ding(FMKeys* self, double frequency, double time) {
|
||||
return (FrequencyModulationSound){
|
||||
.rate = self->rate, .freq_1 = frequency, .freq_2 = 600,
|
||||
.fmc = 3, .ta = 0.01, .decay_base = pow(0.01, 1/time), .planned_time = 0.01 + time,
|
||||
};
|
||||
}
|
||||
|
||||
void LizaInstrument_Table_FMKeys_drop(void* self) {
|
||||
|
||||
}
|
||||
BoxLizaSound LizaInstrument_Table_FMKeys_ding(const void* self, double freq, double time) {
|
||||
return BoxLizaSound_from_FrequencyModulationSound(FMKeys_ding(self, freq, time));
|
||||
}
|
||||
const LizaInstrument_Table LizaInstrument_Table_FMKeys = {
|
||||
.drop = LizaInstrument_Table_FMKeys_drop,
|
||||
.ding = LizaInstrument_Table_FMKeys_ding
|
||||
};
|
||||
|
||||
BoxLizaInstrument BoxLizaInstrument_from_FMKeys(FMKeys obj) {
|
||||
void* mem = safe_malloc(sizeof(FMKeys));
|
||||
memcpy(mem, &obj, sizeof(FMKeys));
|
||||
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_FMKeys};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@ -4,154 +4,63 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "../../../l1/system/pthread.h"
|
||||
#include "../../margaret/time.h"
|
||||
#include "../../marie/graphics_geom.h"
|
||||
#include "../../marie/rasterization.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/mman.h>
|
||||
#include <wayland-client.h>
|
||||
#include "../../../../gen/l_wl_protocols/xdg-shell-client.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "liza_collection.h"
|
||||
|
||||
#define DEFAULT_RATE 44100
|
||||
#define DEFAULT_CHANNELS 2
|
||||
#define DEFAULT_VOLUME 0.1
|
||||
|
||||
/* [roundtrip] */
|
||||
typedef struct {
|
||||
int pending;
|
||||
struct pw_main_loop *loop;
|
||||
} Roundtrip_H_GuestData;
|
||||
|
||||
static void roundtrip_h_pw_core_done(void *data, uint32_t id, int seq) {
|
||||
Roundtrip_H_GuestData *g = data;
|
||||
|
||||
if (id == PW_ID_CORE && seq == g->pending)
|
||||
pw_main_loop_quit(g->loop);
|
||||
}
|
||||
|
||||
static void roundtrip(struct pw_core *core, struct pw_main_loop *loop) {
|
||||
int err;
|
||||
static const struct pw_core_events core_events = {
|
||||
PW_VERSION_CORE_EVENTS,
|
||||
.done = roundtrip_h_pw_core_done,
|
||||
};
|
||||
|
||||
Roundtrip_H_GuestData aboba = {.pending = pw_core_sync(core, PW_ID_CORE, 0), .loop = loop };
|
||||
struct spa_hook core_listener;
|
||||
|
||||
pw_core_add_listener(core, &core_listener, &core_events, &aboba);
|
||||
|
||||
if ((err = pw_main_loop_run(loop)) < 0)
|
||||
printf("main_loop_run error:%d!\n", err);
|
||||
|
||||
spa_hook_remove(&core_listener);
|
||||
}
|
||||
/* [roundtrip] */
|
||||
|
||||
static void main_h_pw_registry_global(
|
||||
void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const struct spa_dict *props
|
||||
) {
|
||||
printf("object: id:%u type:%s/%d\n", id, type, version);
|
||||
}
|
||||
|
||||
static const struct pw_registry_events main_h_pw_registry_listener = {
|
||||
PW_VERSION_REGISTRY_EVENTS,
|
||||
.global = main_h_pw_registry_global,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
double* buffer;
|
||||
int buffer_size;
|
||||
int i;
|
||||
double decay;
|
||||
} KaplusStrong;
|
||||
|
||||
KaplusStrong KaplusStrong_new(double frequency) {
|
||||
int buffer_size = (int)(DEFAULT_RATE / frequency);
|
||||
double* buffer = safe_calloc(buffer_size, sizeof(double));
|
||||
return (KaplusStrong){buffer, buffer_size, 0, 0.999};
|
||||
}
|
||||
|
||||
void KaplusStrong_ding(KaplusStrong* self) {
|
||||
for (int i = 0; i < self->buffer_size; i++) {
|
||||
/* random noise in [-1, 1] */
|
||||
self->buffer[i] = ((double)rand() / RAND_MAX) * 2.0 - 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
double KaplusStrong_next(KaplusStrong* self) {
|
||||
int j = (self->i + 1) % self->buffer_size;
|
||||
double A = self->buffer[self->i];
|
||||
double B = self->buffer[j];
|
||||
self->buffer[self->i] = self->decay * 0.5 * (A + B);
|
||||
self->i = j;
|
||||
return A;
|
||||
}
|
||||
|
||||
void KaplusStrong_drop(KaplusStrong self) {
|
||||
free(self.buffer);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
double freq;
|
||||
int tones;
|
||||
bool raise_first;
|
||||
double* phase;
|
||||
double* tone_c;
|
||||
double c;
|
||||
} Multitone;
|
||||
|
||||
Multitone Multitone_new(double frequency) {
|
||||
int tones = MAX_S32(1, (int)floor(DEFAULT_RATE / frequency) - 1);
|
||||
double* phase = safe_calloc(tones, sizeof(double));
|
||||
double* tone_c = safe_calloc(tones, sizeof(double));
|
||||
double nc = 0;
|
||||
for (int i = 0; i < tones; i++)
|
||||
nc += exp(-(double)i / 16);
|
||||
for (int i = 0; i < tones; i++) {
|
||||
tone_c[i] = exp(-(double)i / 16) / nc;
|
||||
}
|
||||
// for (int i = 0; i < tones; i++) {
|
||||
// tone_c[i] = 1. / (double)(i + 1);
|
||||
// }
|
||||
return (Multitone){.freq = frequency, .tones = tones, .phase = phase, .tone_c = tone_c};
|
||||
}
|
||||
|
||||
void Multitone_ding(Multitone* self) {
|
||||
self->raise_first = true;
|
||||
}
|
||||
|
||||
double Multitone_next(Multitone* self) {
|
||||
if (self->raise_first) {
|
||||
self->c += 0.01;
|
||||
if (self->c >= 1) {
|
||||
self->c = 1;
|
||||
self->raise_first = false;
|
||||
}
|
||||
} else {
|
||||
self->c *= 0.9999;
|
||||
}
|
||||
|
||||
double a = 0;
|
||||
for (int t = 0; t < self->tones; t++) {
|
||||
a += sin(self->phase[t]) * self->tone_c[t];
|
||||
self->phase[t] += M_PI * 2 * self->freq * (float)(t + 1) / DEFAULT_RATE;
|
||||
if (self->phase[t] >= M_PI * 2)
|
||||
self->phase[t] -= M_PI * 2;
|
||||
}
|
||||
return a * self->c;
|
||||
}
|
||||
|
||||
void Multitone_drop(Multitone self) {
|
||||
free(self.phase);
|
||||
free(self.tone_c);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool stop;
|
||||
bool note_ks;
|
||||
bool note_mt;
|
||||
VecBoxLizaSound new_sounds;
|
||||
} AudioThreadCommands;
|
||||
|
||||
/* Can't be copied, can't be cloned (contains mutex) */
|
||||
void AudioThreadCommands_drop(AudioThreadCommands self) {
|
||||
VecBoxLizaSound_drop(self.new_sounds);
|
||||
}
|
||||
|
||||
/* Not movable and even so more it isn't trivially movable */
|
||||
typedef struct {
|
||||
pthread_mutex_t mut;
|
||||
AudioThreadCommands cmd;
|
||||
} AudioThreadBridge;
|
||||
|
||||
/* non-copyable trivially movable (because of BoxLizaSound field) */
|
||||
typedef struct {
|
||||
BoxLizaSound gen;
|
||||
size_t remaining_frames;
|
||||
} PlayingSound;
|
||||
|
||||
void PlayingSound_drop(PlayingSound self) {
|
||||
BoxLizaSound_drop(self.gen);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l2/eve/r2/PlayingSound.h"
|
||||
|
||||
double fix_loud_sound(double a) {
|
||||
const double L = 0.5;
|
||||
const double b = (1 - L) / exp(-L / (1 - L));
|
||||
const double d = 1 / (1 - L);
|
||||
if (a < -L) {
|
||||
return - (1 - d * exp(b * a));
|
||||
} else if (a < L) {
|
||||
return a;
|
||||
} else {
|
||||
return 1 - d * exp(-b * a);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct pw_main_loop *pw_main_loop;
|
||||
struct pw_context *pw_context;
|
||||
@ -162,63 +71,74 @@ typedef struct {
|
||||
struct spa_hook stream_listener_hook;
|
||||
AudioThreadBridge* bridge;
|
||||
|
||||
KaplusStrong ks;
|
||||
Multitone mt;
|
||||
VecPlayingSound playing_sounds;
|
||||
double time_written;
|
||||
} audio_thread_state_t;
|
||||
|
||||
static void main_h_pw_stream_process(void *ug){
|
||||
static void r2a_app_h_pw_stream_process(void *ug){
|
||||
audio_thread_state_t* state = ug;
|
||||
safe_pthread_mutex_lock(&state->bridge->mut);
|
||||
AudioThreadCommands cmd = state->bridge->cmd;
|
||||
state->bridge->cmd = (AudioThreadCommands){ 0};
|
||||
safe_pthread_mutex_unlock(&state->bridge->mut);
|
||||
if (cmd.stop) {
|
||||
AudioThreadCommands* incoming_cmd = &state->bridge->cmd;
|
||||
if (incoming_cmd->stop) {
|
||||
pw_main_loop_quit(state->pw_main_loop);
|
||||
safe_pthread_mutex_unlock(&state->bridge->mut);
|
||||
return;
|
||||
}
|
||||
if (cmd.note_ks)
|
||||
KaplusStrong_ding(&state->ks);
|
||||
if (cmd.note_mt)
|
||||
Multitone_ding(&state->mt);
|
||||
for (size_t i = 0; i < incoming_cmd->new_sounds.len; i++) {
|
||||
/* effectively moved out (will resize incoming_cmd->new_sounds to 0 soon) */
|
||||
BoxLizaSound snd = *VecBoxLizaSound_at(&incoming_cmd->new_sounds, i);
|
||||
VecPlayingSound_append(&state->playing_sounds, (PlayingSound){
|
||||
.gen = snd, .remaining_frames = snd.t->get_duration(snd.m)
|
||||
});
|
||||
}
|
||||
incoming_cmd->new_sounds.len = 0; /* We moved everything out */
|
||||
safe_pthread_mutex_unlock(&state->bridge->mut);
|
||||
|
||||
struct pw_buffer *b = pw_stream_dequeue_buffer(state->pw_stream);
|
||||
if (!b) {
|
||||
pw_log_warn("out of buffers: %m");
|
||||
pw_log_warn("out of buffers");
|
||||
return;
|
||||
}
|
||||
|
||||
struct spa_buffer *buf = b->buffer;
|
||||
int16_t *dst = buf->datas[0].data;
|
||||
if (dst == NULL)
|
||||
return;
|
||||
|
||||
uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS;
|
||||
uint32_t n_frames = buf->datas[0].maxsize / stride;
|
||||
if (b->requested)
|
||||
n_frames = SPA_MIN(b->requested, n_frames);
|
||||
|
||||
for (uint32_t i = 0; i < n_frames; i++) {
|
||||
int16_t *dst = buf->datas[0].data;
|
||||
if (dst == NULL)
|
||||
return;
|
||||
|
||||
for (uint32_t f = 0; f < n_frames; f++) {
|
||||
double a = 0;
|
||||
a += KaplusStrong_next(&state->ks);
|
||||
a += Multitone_next(&state->mt);
|
||||
state->time_written += 1. / DEFAULT_RATE;
|
||||
int16_t val = (int16_t)round(a * DEFAULT_VOLUME * 32767.0);
|
||||
for (size_t i = 0; i < state->playing_sounds.len;) {
|
||||
PlayingSound* snd = VecPlayingSound_mat(&state->playing_sounds, i);
|
||||
if (snd->remaining_frames == 0) {
|
||||
/* snd invalidated, but iteration continues */
|
||||
VecPlayingSound_unordered_pop_and_drop(&state->playing_sounds, i);
|
||||
continue;
|
||||
}
|
||||
a += snd->gen.t->next(snd->gen.m);
|
||||
snd->remaining_frames--;
|
||||
i++;
|
||||
}
|
||||
int16_t val = (int16_t)round(fix_loud_sound(a * DEFAULT_VOLUME) * 32767.0);
|
||||
for (int c = 0; c < DEFAULT_CHANNELS; c++)
|
||||
*dst++ = val;
|
||||
}
|
||||
state->time_written += (double)n_frames / DEFAULT_RATE;
|
||||
|
||||
|
||||
buf->datas[0].chunk->offset = 0;
|
||||
buf->datas[0].chunk->stride = (int32_t)stride;
|
||||
buf->datas[0].chunk->size = n_frames * stride;
|
||||
|
||||
pw_stream_queue_buffer(state->pw_stream, b);
|
||||
printf("Time written = %lf\n", state->time_written);
|
||||
}
|
||||
|
||||
const static struct pw_stream_events main_h_pw_stream_listener = {
|
||||
const static struct pw_stream_events r2a_app_h_pw_stream_listener = {
|
||||
PW_VERSION_STREAM_EVENTS,
|
||||
.process = main_h_pw_stream_process
|
||||
.process = r2a_app_h_pw_stream_process
|
||||
};
|
||||
|
||||
void AudioThreadBridge_init(AudioThreadBridge* place) {
|
||||
@ -227,12 +147,13 @@ void AudioThreadBridge_init(AudioThreadBridge* place) {
|
||||
}
|
||||
|
||||
void AudioThreadBridge_destroy(AudioThreadBridge* resid) {
|
||||
AudioThreadCommands_drop(resid->cmd);
|
||||
pthread_mutex_destroy(&resid->mut);
|
||||
}
|
||||
|
||||
/* Full of audio */
|
||||
void* audio_thread(void* ug) {
|
||||
audio_thread_state_t state = { .ks = KaplusStrong_new(440), .mt = Multitone_new(440), .bridge = ug };
|
||||
audio_thread_state_t state = { .playing_sounds = VecPlayingSound_new(), .bridge = ug };
|
||||
|
||||
state.pw_main_loop = pw_main_loop_new(NULL /* properties */);
|
||||
if (!state.pw_main_loop)
|
||||
@ -247,16 +168,11 @@ void* audio_thread(void* ug) {
|
||||
if (!state.pw_registry)
|
||||
abortf("pw_core_get_registry\n");
|
||||
|
||||
struct spa_hook registry_listener_hook;
|
||||
pw_registry_add_listener(state.pw_registry, ®istry_listener_hook, &main_h_pw_registry_listener, NULL);
|
||||
|
||||
roundtrip(state.pw_core, state.pw_main_loop);
|
||||
|
||||
state.pw_stream = pw_stream_new(state.pw_core, "audio-src", pw_properties_new(
|
||||
PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Playback", PW_KEY_MEDIA_ROLE, "Music", NULL));
|
||||
|
||||
struct spa_hook stream_listener_hook;
|
||||
pw_stream_add_listener(state.pw_stream, &stream_listener_hook, &main_h_pw_stream_listener, &state);
|
||||
pw_stream_add_listener(state.pw_stream, &stream_listener_hook, &r2a_app_h_pw_stream_listener, &state);
|
||||
|
||||
const struct spa_pod *stream_params[1];
|
||||
uint8_t pod_buffer[1024];
|
||||
@ -279,17 +195,603 @@ void* audio_thread(void* ug) {
|
||||
printf("Exited mainloop\n");
|
||||
|
||||
pw_stream_destroy(state.pw_stream);
|
||||
KaplusStrong_drop(state.ks);
|
||||
Multitone_drop(state.mt);
|
||||
pw_proxy_destroy((struct pw_proxy*)state.pw_registry);
|
||||
pw_core_disconnect(state.pw_core);
|
||||
pw_context_destroy(state.pw_context);
|
||||
pw_main_loop_destroy(state.pw_main_loop);
|
||||
printf("Thread finished\n");
|
||||
|
||||
VecPlayingSound_drop(state.playing_sounds);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/* No we specify what happens in the main thread */
|
||||
|
||||
#define MAX_BUFFER_WIDTH 1000
|
||||
#define MAX_BUFFER_HEIGHT 800
|
||||
#define SWAPCHAIN_SLOTS 2
|
||||
|
||||
_Static_assert(INT32_MAX / MAX_BUFFER_WIDTH / MAX_BUFFER_HEIGHT / 4 / SWAPCHAIN_SLOTS > 1, "Swapchain is too big");
|
||||
|
||||
static int create_shm_file(){
|
||||
char name[] = "/prototype1-XXXXXXXXXXXX";
|
||||
U64 v = ((U64)rand() << 32) + (U64)rand();
|
||||
for (int i = 0; i < 12; i++) {
|
||||
name[sizeof(name) - 1 - 12 + i] = 'A' + (v&15) + (v&16)*2;
|
||||
v >>= 5;
|
||||
}
|
||||
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0)
|
||||
abortf("shm_open(\"%s\")", name);
|
||||
if (shm_unlink(name) < 0)
|
||||
abortf("shm_unlink(\"%s\")", name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int allocate_shm_file(size_t size) {
|
||||
int fd = create_shm_file();
|
||||
int ret;
|
||||
do {
|
||||
ret = ftruncate(fd, size);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0) {
|
||||
abortf("ftruncate(%ld)", size);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
uint32_t* data;
|
||||
struct wl_shm_pool* pool;
|
||||
bool want_to_draw;
|
||||
struct wl_buffer* used_buffers[SWAPCHAIN_SLOTS];
|
||||
} swapchain_t;
|
||||
|
||||
typedef struct {
|
||||
BoxLizaInstrument liza;
|
||||
float turn_progress;
|
||||
} MyInstrument;
|
||||
|
||||
MyInstrument MyInstrument_new(BoxLizaInstrument liza) {
|
||||
return (MyInstrument){liza, 0};
|
||||
}
|
||||
|
||||
void MyInstrument_drop(MyInstrument self) {
|
||||
BoxLizaInstrument_drop(self.liza);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l2/eve/r2/VecMyInstrument.h"
|
||||
|
||||
typedef struct {
|
||||
/* Globals */
|
||||
struct wl_display *wl_display;
|
||||
struct wl_registry *wl_registry;
|
||||
struct wl_shm *wl_shm;
|
||||
struct wl_compositor *wl_compositor;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct wl_seat *wl_seat;
|
||||
/* Objects */
|
||||
swapchain_t swapchain;
|
||||
struct wl_surface *wl_surface;
|
||||
struct wl_callback* wl_callback;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
/* inputs */
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_keyboard* keyboard;
|
||||
/* xkb */
|
||||
struct xkb_state* xkb_state;
|
||||
struct xkb_context* xkb_context;
|
||||
struct xkb_keymap* xkb_keymap;
|
||||
/* app state */
|
||||
vec2 pointer_pos;
|
||||
bool first_0x80_keys[0x80];
|
||||
uint32_t last_frame_time;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
bool closed;
|
||||
/* instruments */
|
||||
VecMyInstrument instruments;
|
||||
size_t selected_instrument;
|
||||
/* Bridge to audio thread */
|
||||
AudioThreadBridge* audio_thread_bridge;
|
||||
} wl_app_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t* data;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
} WhereToDrawTriangle;
|
||||
|
||||
U32 color_vec4_to_color_u32(vec4 color) {
|
||||
return (((U32)roundf(color.w * 255)) << 24) + (((U32)roundf(color.x * color.w * 255)) << 16) +
|
||||
(((U32)roundf(color.y * color.w * 255)) << 8) + (((U32)roundf(color.z * color.w * 255)) << 0);
|
||||
}
|
||||
|
||||
void draw_frame_h_rasterizer_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
WhereToDrawTriangle* g = ug;
|
||||
if (0 <= x && x < g->width && 0 <= y && y < g->height)
|
||||
g->data[y * g->width + x] = color_vec4_to_color_u32(attr);
|
||||
}
|
||||
|
||||
void draw_frame(wl_app_state_t* state, uint32_t* data, int32_t width, int32_t height) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
data[y * width + x] = 0xFF00FFFF;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < state->instruments.len; i++) {
|
||||
MyInstrument* inst = VecMyInstrument_mat(&state->instruments, i);
|
||||
vec2 pos = {60 + 80 * (float)i, 60};
|
||||
WhereToDrawTriangle aboba = {data, width, height};
|
||||
vec2 triangle[3] = {};
|
||||
for (int v = 0; v < 3; v++) {
|
||||
triangle[v] = vec2_add_vec2(pos, vec2_mul_scal(
|
||||
marie_trigonom_circle(3 * M_PIf / 2 + (float)v * 2 * M_PIf / 3 + M_PIf * inst->turn_progress),
|
||||
10 + 10 * inst->turn_progress));
|
||||
}
|
||||
vec4 color = {1, 1 - inst->turn_progress, 1 - inst->turn_progress, 1};
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = triangle[0], .attr = color},
|
||||
(MariePlaneVertAttr){.pos = triangle[1], .attr = color},
|
||||
(MariePlaneVertAttr){.pos = triangle[2], .attr = color},
|
||||
(FnMarieRasterizerCallback){.fn = draw_frame_h_rasterizer_cb, .guest = &aboba});
|
||||
}
|
||||
}
|
||||
|
||||
void update_state(wl_app_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;
|
||||
for (size_t i = 0; i < state->instruments.len; i++) {
|
||||
MyInstrument* inst = VecMyInstrument_mat(&state->instruments, i);
|
||||
if (i == state->selected_instrument) {
|
||||
inst->turn_progress = MIN_float(1, inst->turn_progress + dur * 1);
|
||||
} else {
|
||||
inst->turn_progress = MAX_float(0, inst->turn_progress - dur * 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_buffer_release(void *data, struct wl_buffer *buffer) {
|
||||
wl_app_state_t* state = data;
|
||||
for (int ij = 0; ij < SWAPCHAIN_SLOTS; ij++) {
|
||||
if (state->swapchain.used_buffers[ij] == buffer) {
|
||||
// printf("Buffer %p was released and destroyed\n", buffer);
|
||||
wl_buffer_destroy(buffer);
|
||||
state->swapchain.used_buffers[ij] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
abortf("HUH??!!!\n");
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener r2a_app_h_wl_buffer_listener = {
|
||||
.release = r2a_app_h_wl_buffer_release,
|
||||
};
|
||||
|
||||
int swapchain_take_slot(wl_app_state_t *state) {
|
||||
for (int ij = 0; ij < SWAPCHAIN_SLOTS; ij++) {
|
||||
if (!state->swapchain.used_buffers[ij]) {
|
||||
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;
|
||||
struct wl_buffer* s = wl_shm_pool_create_buffer(
|
||||
state->swapchain.pool, ij * 4 * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT,
|
||||
width, height, 4 * width, WL_SHM_FORMAT_ARGB8888);
|
||||
state->swapchain.used_buffers[ij] = s;
|
||||
if (!s)
|
||||
abortf("wl_shm_pool_create_buffer\n");
|
||||
wl_buffer_add_listener(s, &r2a_app_h_wl_buffer_listener, state);
|
||||
|
||||
return ij;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void try_drawing_frame(wl_app_state_t *state){
|
||||
if (!state->swapchain.want_to_draw)
|
||||
return;
|
||||
int ij = swapchain_take_slot(state);
|
||||
// printf("Got slot %d", ij);
|
||||
if (ij < 0)
|
||||
return;
|
||||
assert(ij < SWAPCHAIN_SLOTS);
|
||||
state->swapchain.want_to_draw = false;
|
||||
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);
|
||||
}
|
||||
|
||||
static void r2a_app_h_xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial){
|
||||
wl_app_state_t *state = data;
|
||||
printf("XDG surface configured!\n");
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
// todo: synchronize with frame event
|
||||
state->swapchain.want_to_draw = true;
|
||||
try_drawing_frame(state);
|
||||
}
|
||||
|
||||
static void r2a_app_h_xdg_toplevel_configure(
|
||||
void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states
|
||||
){
|
||||
wl_app_state_t *state = data;
|
||||
printf("XDG toplevel configured to (%d %d)\n", width, height);
|
||||
if (width <= 0 || height < 0)
|
||||
return;
|
||||
state->width = width;
|
||||
state->height = height;
|
||||
}
|
||||
|
||||
static void r2a_app_h_xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel){
|
||||
wl_app_state_t *state = data;
|
||||
state->closed = true;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener r2a_app_h_xdg_toplevel_listener = {
|
||||
.configure = r2a_app_h_xdg_toplevel_configure,
|
||||
.close = r2a_app_h_xdg_toplevel_close,
|
||||
};
|
||||
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = r2a_app_h_xdg_surface_configure,
|
||||
};
|
||||
|
||||
static void r2a_app_h_xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial){
|
||||
xdg_wm_base_pong(xdg_wm_base, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener r2a_app_h_xdg_wm_base_listener = {
|
||||
.ping = r2a_app_h_xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void r2a_app_h_wl_keyboard_keymap(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size
|
||||
) {
|
||||
wl_app_state_t* state = data;
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
||||
abortf("O_o");
|
||||
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (map_shm == MAP_FAILED)
|
||||
abortf("Couldn't mmap new keymap ha-ha\n");
|
||||
|
||||
xkb_keymap_unref(state->xkb_keymap);
|
||||
xkb_state_unref(state->xkb_state);
|
||||
state->xkb_keymap = xkb_keymap_new_from_string(
|
||||
state->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap(map_shm, size);
|
||||
close(fd);
|
||||
state->xkb_state = xkb_state_new(state->xkb_keymap);
|
||||
printf("Keymap changed!\n");
|
||||
memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys));
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_keyboard_enter(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys
|
||||
) {
|
||||
wl_app_state_t* state = data;
|
||||
// todo: fill first_0x80_keys array
|
||||
// todo: move all of this into a separate framework
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_keyboard_leave(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface
|
||||
) {
|
||||
wl_app_state_t* state = data;
|
||||
memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys));
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_keyboard_key(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t key_action
|
||||
) {
|
||||
wl_app_state_t* state = data;
|
||||
uint32_t actual_key = key + 8;
|
||||
/* It actually could be nokey keysym. You never know without checking */
|
||||
xkb_keysym_t keysym = xkb_state_key_get_one_sym(state->xkb_state, actual_key);
|
||||
if (keysym < 0x80 && key_action == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
||||
state->first_0x80_keys[keysym] = false;
|
||||
} else if (keysym < 0x80 && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
state->first_0x80_keys[keysym] = true;
|
||||
}
|
||||
if (keysym == XKB_KEY_0 && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
state->selected_instrument = 10;
|
||||
}
|
||||
if (XKB_KEY_1 <= keysym && keysym <= XKB_KEY_9 && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
state->selected_instrument = keysym - XKB_KEY_1;
|
||||
}
|
||||
const xkb_keysym_t octave[] = {
|
||||
XKB_KEY_a, XKB_KEY_w, XKB_KEY_s, XKB_KEY_e, XKB_KEY_d, XKB_KEY_r,
|
||||
XKB_KEY_f, XKB_KEY_t, XKB_KEY_g, XKB_KEY_y, XKB_KEY_h, XKB_KEY_u
|
||||
};
|
||||
if (state->selected_instrument < state->instruments.len) {
|
||||
// todo: add box to ref and box to mref methods
|
||||
const BoxLizaInstrument* instrument = &VecMyInstrument_at(&state->instruments, state->selected_instrument)->liza;
|
||||
for (int i = 0; i < ARRAY_SIZE(octave); i++) {
|
||||
if (keysym == octave[i] && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
safe_pthread_mutex_lock(&state->audio_thread_bridge->mut);
|
||||
VecBoxLizaSound_append(&state->audio_thread_bridge->cmd.new_sounds,
|
||||
instrument->t->ding(instrument->m, 440 * pow(2, (double)i / 12), 0.9));
|
||||
safe_pthread_mutex_unlock(&state->audio_thread_bridge->mut);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_keyboard_modifiers(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group
|
||||
) {
|
||||
wl_app_state_t* state = data;
|
||||
xkb_state_update_mask(state->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){
|
||||
printf("Repeat timings changed: rate = %d, delay = %d", rate, delay);
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener r2a_app_h_wl_keyboard_listener = {
|
||||
.keymap = r2a_app_h_wl_keyboard_keymap,
|
||||
.enter = r2a_app_h_wl_keyboard_enter,
|
||||
.leave = r2a_app_h_wl_keyboard_leave,
|
||||
.key = r2a_app_h_wl_keyboard_key,
|
||||
.modifiers = r2a_app_h_wl_keyboard_modifiers,
|
||||
.repeat_info = r2a_app_h_wl_keyboard_repeat_info,
|
||||
};
|
||||
|
||||
|
||||
static void r2a_app_h_wl_pointer_enter(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||
struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y
|
||||
) {
|
||||
wl_app_state_t *state = data;
|
||||
state->pointer_pos = (vec2){(float)surface_x / 256.f, (float)surface_y / 256.f};
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_pointer_leave(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface
|
||||
) {
|
||||
wl_app_state_t *state = data;
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_pointer_motion(
|
||||
void *data,struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y
|
||||
) {
|
||||
wl_app_state_t *state = data;
|
||||
state->pointer_pos = (vec2){(float)surface_x / 256.f, (float)surface_y / 256.f};
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_pointer_button(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t btn_action
|
||||
) {
|
||||
wl_app_state_t *state = data;
|
||||
if (btn_action == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
printf("button = %u\n", button);
|
||||
if (button == 0x110) {
|
||||
printf("Bup!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_pointer_axis(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value
|
||||
) {
|
||||
wl_app_state_t *state = data;
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) {
|
||||
wl_app_state_t *state = data;
|
||||
}
|
||||
|
||||
const struct wl_pointer_listener r2a_app_h_wl_pointer_listener = {
|
||||
.enter = r2a_app_h_wl_pointer_enter,
|
||||
.leave = r2a_app_h_wl_pointer_leave,
|
||||
.motion = r2a_app_h_wl_pointer_motion,
|
||||
.button = r2a_app_h_wl_pointer_button,
|
||||
.axis = r2a_app_h_wl_pointer_axis,
|
||||
.frame = r2a_app_h_wl_pointer_frame
|
||||
};
|
||||
|
||||
static void r2a_app_h_wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
|
||||
wl_app_state_t* state = data;
|
||||
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
|
||||
state->pointer = wl_seat_get_pointer(wl_seat);
|
||||
if (!state->pointer)
|
||||
abortf("wl_seat_get_pointer\n");
|
||||
wl_pointer_add_listener(state->pointer, &r2a_app_h_wl_pointer_listener, state);
|
||||
}
|
||||
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
state->keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
if (!state->keyboard)
|
||||
abortf("wl_seat_get_keyboard\n");
|
||||
wl_keyboard_add_listener(state->keyboard, &r2a_app_h_wl_keyboard_listener, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {
|
||||
printf("Our seat name: %s\n", name);
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener r2a_app_h_wl_seat_listener = {
|
||||
.capabilities = r2a_app_h_wl_seat_capabilities,
|
||||
.name = r2a_app_h_wl_seat_name,
|
||||
};
|
||||
|
||||
static void r2a_app_h_wl_registry_global(
|
||||
void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version
|
||||
) {
|
||||
wl_app_state_t *state = data;
|
||||
if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
state->wl_shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1);
|
||||
if (!state->wl_shm)
|
||||
abortf("wl_registry_bind\n");
|
||||
} else if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||
state->wl_compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
|
||||
if (!state->wl_compositor)
|
||||
abortf("wl_registry_bind\n");
|
||||
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
|
||||
state->xdg_wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
|
||||
if (!state->xdg_wm_base)
|
||||
abortf("wl_registry_bind\n");
|
||||
xdg_wm_base_add_listener(state->xdg_wm_base, &r2a_app_h_xdg_wm_base_listener, state);
|
||||
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
if (state->wl_seat) {
|
||||
printf("We got second seat, but we only need one\n");
|
||||
return;
|
||||
}
|
||||
state->wl_seat = wl_registry_bind(wl_registry, name, &wl_seat_interface, 4);
|
||||
if (!state->wl_seat)
|
||||
abortf("wl_registry_bind\n");
|
||||
wl_seat_add_listener(state->wl_seat, &r2a_app_h_wl_seat_listener, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void r2a_app_h_wl_registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name){
|
||||
// todo: delete seats
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener r2a_app_h_wl_registry_listener = {
|
||||
.global = r2a_app_h_wl_registry_global,
|
||||
.global_remove = r2a_app_h_wl_registry_global_remove,
|
||||
};
|
||||
|
||||
static const struct wl_callback_listener r2a_app_h_wl_surface_frame_listener;
|
||||
|
||||
static void r2a_app_h_wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time){
|
||||
wl_app_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, &r2a_app_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 r2a_app_h_wl_surface_frame_listener = {
|
||||
.done = r2a_app_h_wl_surface_frame_done,
|
||||
};
|
||||
|
||||
|
||||
void r2a_app(AudioThreadBridge *audio_thread_bridge) {
|
||||
wl_app_state_t state = { .width = 800, .height = 480,
|
||||
.instruments = VecMyInstrument_new(),
|
||||
.selected_instrument = UINT64_MAX, .audio_thread_bridge = audio_thread_bridge
|
||||
};
|
||||
VecMyInstrument_append(&state.instruments, MyInstrument_new(BoxLizaInstrument_from_WeirdGuitar(WeirdGuitar_new(DEFAULT_RATE))));
|
||||
VecMyInstrument_append(&state.instruments, MyInstrument_new(BoxLizaInstrument_from_AMKeys(AMKeys_new(DEFAULT_RATE))));
|
||||
VecMyInstrument_append(&state.instruments, MyInstrument_new(BoxLizaInstrument_from_FMKeys(FMKeys_new(DEFAULT_RATE))));
|
||||
|
||||
state.wl_display = wl_display_connect(NULL);
|
||||
if (!state.wl_display)
|
||||
abortf("Could not connect");
|
||||
state.wl_registry = wl_display_get_registry(state.wl_display);
|
||||
if (!state.wl_registry)
|
||||
abortf("wl_display_get_registry");
|
||||
wl_registry_add_listener(state.wl_registry, &r2a_app_h_wl_registry_listener, &state);
|
||||
wl_display_roundtrip(state.wl_display);
|
||||
if (!state.wl_shm)
|
||||
abortf("No wl_shm");
|
||||
if (!state.wl_compositor)
|
||||
abortf("No wl_compositor");
|
||||
if (!state.xdg_wm_base)
|
||||
abortf("No xdg_wm_base");
|
||||
{
|
||||
size_t size = SWAPCHAIN_SLOTS * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT * 4;
|
||||
assert(size < INT32_MAX);
|
||||
state.swapchain.fd = allocate_shm_file(size);
|
||||
if (state.swapchain.fd == -1) {
|
||||
abortf("AAA");
|
||||
}
|
||||
|
||||
state.swapchain.data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, state.swapchain.fd, 0);
|
||||
if (state.swapchain.data == MAP_FAILED) {
|
||||
close(state.swapchain.fd);
|
||||
abortf("what the dog doing");
|
||||
}
|
||||
|
||||
state.swapchain.pool = wl_shm_create_pool(state.wl_shm, state.swapchain.fd, size);
|
||||
if (!state.swapchain.pool)
|
||||
abortf("wl_shm_create_pool");
|
||||
close(state.swapchain.fd);
|
||||
}
|
||||
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!state.xkb_context)
|
||||
abortf("xkb_context_new\n");
|
||||
state.wl_surface = wl_compositor_create_surface(state.wl_compositor);
|
||||
if (!state.wl_surface)
|
||||
abortf("wl_compositor_create_surface\n");
|
||||
state.xdg_surface = xdg_wm_base_get_xdg_surface(
|
||||
state.xdg_wm_base, state.wl_surface);
|
||||
if (!state.xdg_surface)
|
||||
abortf("xdg_wm_base_get_xdg_surface\n");
|
||||
xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state);
|
||||
state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
|
||||
if (!state.xdg_toplevel)
|
||||
abortf("xdg_surface_get_toplevel\n");
|
||||
xdg_toplevel_add_listener(state.xdg_toplevel, &r2a_app_h_xdg_toplevel_listener, &state);
|
||||
xdg_toplevel_set_title(state.xdg_toplevel, "r2a");
|
||||
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, &r2a_app_h_wl_surface_frame_listener, &state);
|
||||
|
||||
while (wl_display_dispatch(state.wl_display)) {
|
||||
if (state.closed)
|
||||
break;
|
||||
}
|
||||
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);
|
||||
wl_surface_destroy(state.wl_surface);
|
||||
wl_compositor_destroy(state.wl_compositor);
|
||||
if (state.pointer)
|
||||
wl_pointer_destroy(state.pointer);
|
||||
xkb_context_unref(state.xkb_context);
|
||||
xkb_keymap_unref(state.xkb_keymap);
|
||||
xkb_state_unref(state.xkb_state);
|
||||
if (state.keyboard)
|
||||
wl_keyboard_destroy(state.keyboard);
|
||||
if (state.wl_seat)
|
||||
wl_seat_destroy(state.wl_seat);
|
||||
munmap(state.swapchain.data, SWAPCHAIN_SLOTS * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT * 2);
|
||||
for (size_t i = 0; i < SWAPCHAIN_SLOTS; i++) {
|
||||
if (state.swapchain.used_buffers[i])
|
||||
wl_buffer_destroy(state.swapchain.used_buffers[i]);
|
||||
}
|
||||
wl_shm_pool_destroy(state.swapchain.pool);
|
||||
wl_shm_destroy(state.wl_shm);
|
||||
wl_registry_destroy(state.wl_registry);
|
||||
wl_display_disconnect(state.wl_display);
|
||||
|
||||
/* Cleaning Up my state */
|
||||
VecMyInstrument_drop(state.instruments);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
pw_init(NULL, NULL);
|
||||
|
||||
AudioThreadBridge bridge;
|
||||
@ -298,30 +800,11 @@ int main(int argc, char *argv[]) {
|
||||
if (pthread_create(&th, NULL, audio_thread, &bridge))
|
||||
abortf("pthread_create\n");
|
||||
|
||||
while (true) {
|
||||
char line[50];
|
||||
if (!fgets(line, sizeof(line), stdin))
|
||||
break;
|
||||
line[strcspn(line, "\n")] = '\0';
|
||||
if (strcmp(line, "1") == 0) {
|
||||
safe_pthread_mutex_lock(&bridge.mut);
|
||||
bridge.cmd.note_ks = true;
|
||||
safe_pthread_mutex_unlock(&bridge.mut);
|
||||
} else if (strcmp(line, "2") == 0) {
|
||||
safe_pthread_mutex_lock(&bridge.mut);
|
||||
bridge.cmd.note_mt = true;
|
||||
safe_pthread_mutex_unlock(&bridge.mut);
|
||||
} else if (strcmp(line, "q") == 0) {
|
||||
safe_pthread_mutex_lock(&bridge.mut);
|
||||
bridge.cmd.stop = true;
|
||||
safe_pthread_mutex_unlock(&bridge.mut);
|
||||
break;
|
||||
} else {
|
||||
printf("?\n");
|
||||
}
|
||||
|
||||
}
|
||||
r2a_app(&bridge);
|
||||
|
||||
safe_pthread_mutex_lock(&bridge.mut);
|
||||
bridge.cmd.stop = true;
|
||||
safe_pthread_mutex_unlock(&bridge.mut);
|
||||
safe_pthread_join(th);
|
||||
printf("The End!\n");
|
||||
AudioThreadBridge_destroy(&bridge);
|
||||
|
||||
@ -129,10 +129,12 @@ void PlayingSound_drop(PlayingSound self) {
|
||||
#include "../../../../gen/l2/eve/r2/PlayingSound.h"
|
||||
|
||||
double fix_loud_sound(double a) {
|
||||
return a;
|
||||
const double L = 0.5;
|
||||
const double b = (1 - L) / exp(-L / (1 - L));
|
||||
const double d = 1 / (1 - L);
|
||||
if (a < -L) {
|
||||
printf("Whhohps: %lf\n", a);
|
||||
return - (1 - d * exp(b * a));
|
||||
} else if (a < L) {
|
||||
return a;
|
||||
@ -203,7 +205,7 @@ static void main_h_pw_stream_process(void *ug){
|
||||
snd->remaining_frames--;
|
||||
i++;
|
||||
}
|
||||
int16_t val = (int16_t)round(fix_loud_sound(a) * DEFAULT_VOLUME * 32767.0);
|
||||
int16_t val = (int16_t)round(fix_loud_sound(a * DEFAULT_VOLUME) * 32767.0);
|
||||
for (int c = 0; c < DEFAULT_CHANNELS; c++)
|
||||
*dst++ = val;
|
||||
}
|
||||
@ -286,8 +288,7 @@ void* audio_thread(void* ug) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int ret;
|
||||
int main() {
|
||||
pw_init(NULL, NULL);
|
||||
|
||||
AudioThreadBridge bridge;
|
||||
|
||||
514
src/l2/tests/r3/r3.c
Normal file
514
src/l2/tests/r3/r3.c
Normal file
@ -0,0 +1,514 @@
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <wayland-client.h>
|
||||
#include "../../../../gen/l_wl_protocols/xdg-shell-client.h"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "../../../l1/core/util.h"
|
||||
#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) {
|
||||
VkAttachmentDescription all_attachments[1] = {
|
||||
{
|
||||
.format = colorbuffer_format,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.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,
|
||||
}
|
||||
};
|
||||
|
||||
// For our one single render subpass
|
||||
VkAttachmentReference color_attachments_refs[1] = {
|
||||
{
|
||||
.attachment = 0,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
} };
|
||||
|
||||
VkSubpassDescription subpasses_descr[1] = { (VkSubpassDescription){
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = ARRAY_SIZE(color_attachments_refs),
|
||||
.pColorAttachments = color_attachments_refs,
|
||||
} };
|
||||
|
||||
VkSubpassDependency subpass_dependencies[1] = {
|
||||
// subpass_0_external
|
||||
(VkSubpassDependency) {
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
}};
|
||||
|
||||
VkRenderPassCreateInfo render_pass_crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.attachmentCount = ARRAY_SIZE(all_attachments),
|
||||
.pAttachments = all_attachments,
|
||||
.subpassCount = ARRAY_SIZE(subpasses_descr),
|
||||
.pSubpasses = subpasses_descr,
|
||||
.dependencyCount = ARRAY_SIZE(subpass_dependencies),
|
||||
.pDependencies = subpass_dependencies,
|
||||
};
|
||||
VkRenderPass render_pass;
|
||||
if (vkCreateRenderPass(logical_device, &render_pass_crinfo, NULL, &render_pass) != VK_SUCCESS)
|
||||
abortf("vkCreateRenderPass");
|
||||
return render_pass;
|
||||
}
|
||||
|
||||
void reset_and_record_command_buffer_0(
|
||||
VkCommandBuffer command_buffer, VkRenderPass render_pass_0,
|
||||
VkFramebuffer swapchain_image_framebuffer, VkExtent2D image_extent,
|
||||
float ht
|
||||
) {
|
||||
if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS)
|
||||
abortf("vkResetCommandBuffer");
|
||||
VkCommandBufferBeginInfo info_begin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS)
|
||||
abortf("vkBeginCommandBuffer");
|
||||
|
||||
VkClearValue clear_values[1] = {{.color = {.float32={0, fabsf(sinf(ht)), 0, 1}}},};
|
||||
VkRenderPassBeginInfo renderpass_begin = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderPass = render_pass_0,
|
||||
.framebuffer = swapchain_image_framebuffer,
|
||||
.renderArea.offset = (VkOffset2D){0, 0},
|
||||
.renderArea.extent = image_extent,
|
||||
.clearValueCount = ARRAY_SIZE(clear_values),
|
||||
.pClearValues = clear_values,
|
||||
};
|
||||
|
||||
vkCmdBeginRenderPass(command_buffer, &renderpass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdEndRenderPass(command_buffer);
|
||||
if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
|
||||
abortf("vkEndCommandBuffer");
|
||||
}
|
||||
|
||||
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 {
|
||||
/* Globals */
|
||||
struct wl_display *wl_display;
|
||||
struct wl_registry *wl_registry;
|
||||
struct wl_compositor *wl_compositor;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct wl_seat *wl_seat;
|
||||
/* Objects */
|
||||
struct wl_surface *wl_surface;
|
||||
struct wl_callback* wl_callback;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
/* vulkan objects */
|
||||
/* inputs */
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_keyboard* keyboard;
|
||||
/* xkb */
|
||||
struct xkb_state* xkb_state;
|
||||
struct xkb_context* xkb_context;
|
||||
struct xkb_keymap* xkb_keymap;
|
||||
/* app state */
|
||||
float ht;
|
||||
uint32_t last_frame_time;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
bool closed;
|
||||
bool first_0x80_keys[0x80];
|
||||
} 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);
|
||||
// }
|
||||
|
||||
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");
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
// state->swapchain.want_to_draw = true;
|
||||
// try_drawing_frame(state);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = main_h_xdg_surface_configure,
|
||||
};
|
||||
|
||||
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;
|
||||
printf("XDG toplevel configured to (%d %d)\n", width, height);
|
||||
if (width <= 0 || height < 0)
|
||||
return;
|
||||
state->width = width;
|
||||
state->height = height;
|
||||
}
|
||||
|
||||
static void main_h_xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel){
|
||||
state_t *state = data;
|
||||
state->closed = true;
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener main_h_xdg_toplevel_listener = {
|
||||
.configure = main_h_xdg_toplevel_configure,
|
||||
.close = main_h_xdg_toplevel_close,
|
||||
};
|
||||
|
||||
static void main_h_xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial){
|
||||
xdg_wm_base_pong(xdg_wm_base, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener main_h_xdg_wm_base_listener = {
|
||||
.ping = main_h_xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void main_h_wl_keyboard_keymap(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size
|
||||
) {
|
||||
state_t* state = data;
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
||||
abortf("O_o");
|
||||
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (map_shm == MAP_FAILED)
|
||||
abortf("Couldn't mmap new keymap ha-ha\n");
|
||||
|
||||
xkb_keymap_unref(state->xkb_keymap);
|
||||
xkb_state_unref(state->xkb_state);
|
||||
state->xkb_keymap = xkb_keymap_new_from_string(
|
||||
state->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap(map_shm, size);
|
||||
close(fd);
|
||||
state->xkb_state = xkb_state_new(state->xkb_keymap);
|
||||
printf("Keymap changed!\n");
|
||||
memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys));
|
||||
}
|
||||
|
||||
static void main_h_wl_keyboard_enter(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys
|
||||
) {
|
||||
state_t* state = data;
|
||||
printf("keyboard enter; keys pressed are:\n");
|
||||
uint32_t *key;
|
||||
wl_array_for_each(key, keys) {
|
||||
uint32_t actual_key = *key + 8;
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb_state, actual_key);
|
||||
if (sym < 0x80)
|
||||
state->first_0x80_keys[sym] = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void main_h_wl_keyboard_leave(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface
|
||||
) {
|
||||
state_t* state = data;
|
||||
memset(&state->first_0x80_keys, 0, sizeof(state->first_0x80_keys));
|
||||
}
|
||||
|
||||
static void main_h_wl_keyboard_key(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t key_action
|
||||
) {
|
||||
state_t* state = data;
|
||||
uint32_t actual_key = key + 8;
|
||||
/* It actually could be nokey keysym. You never know without checking */
|
||||
xkb_keysym_t keysym = xkb_state_key_get_one_sym(state->xkb_state, actual_key);
|
||||
if (keysym < 0x80 && key_action == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
||||
state->first_0x80_keys[keysym] = false;
|
||||
} else if (keysym < 0x80 && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
state->first_0x80_keys[keysym] = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void main_h_wl_keyboard_modifiers(
|
||||
void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group
|
||||
) {
|
||||
state_t* state = data;
|
||||
xkb_state_update_mask(state->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
static void main_h_wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){
|
||||
printf("Repeat timings changed: rate = %d, delay = %d", rate, delay); // todo: use this information
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener main_h_wl_keyboard_listener = {
|
||||
.keymap = main_h_wl_keyboard_keymap,
|
||||
.enter = main_h_wl_keyboard_enter,
|
||||
.leave = main_h_wl_keyboard_leave,
|
||||
.key = main_h_wl_keyboard_key,
|
||||
.modifiers = main_h_wl_keyboard_modifiers,
|
||||
.repeat_info = main_h_wl_keyboard_repeat_info,
|
||||
};
|
||||
|
||||
|
||||
static void main_h_wl_pointer_enter(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
||||
struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y
|
||||
) {
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_leave(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface
|
||||
) {
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_motion(
|
||||
void *data,struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y
|
||||
) {
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_button(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t btn_action
|
||||
) {
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_axis(
|
||||
void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value
|
||||
) {
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
static void main_h_wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) {
|
||||
state_t *state = data;
|
||||
}
|
||||
|
||||
const struct wl_pointer_listener main_h_wl_pointer_listener = {
|
||||
.enter = main_h_wl_pointer_enter,
|
||||
.leave = main_h_wl_pointer_leave,
|
||||
.motion = main_h_wl_pointer_motion,
|
||||
.button = main_h_wl_pointer_button,
|
||||
.axis = main_h_wl_pointer_axis,
|
||||
.frame = main_h_wl_pointer_frame
|
||||
};
|
||||
|
||||
static void main_h_wl_seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) {
|
||||
state_t* state = data;
|
||||
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
|
||||
state->pointer = wl_seat_get_pointer(wl_seat);
|
||||
if (!state->pointer)
|
||||
abortf("wl_seat_get_pointer\n");
|
||||
wl_pointer_add_listener(state->pointer, &main_h_wl_pointer_listener, state);
|
||||
}
|
||||
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
state->keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
if (!state->keyboard)
|
||||
abortf("wl_seat_get_keyboard\n");
|
||||
wl_keyboard_add_listener(state->keyboard, &main_h_wl_keyboard_listener, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void main_h_wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {
|
||||
printf("Our seat name: %s\n", name);
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener main_h_wl_seat_listener = {
|
||||
.capabilities = main_h_wl_seat_capabilities,
|
||||
.name = main_h_wl_seat_name,
|
||||
};
|
||||
|
||||
static void main_h_wl_registry_global(
|
||||
void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version
|
||||
) {
|
||||
state_t *state = data;
|
||||
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||
state->wl_compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
|
||||
if (!state->wl_compositor)
|
||||
abortf("wl_registry_bind\n");
|
||||
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
|
||||
state->xdg_wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
|
||||
if (!state->xdg_wm_base)
|
||||
abortf("wl_registry_bind\n");
|
||||
xdg_wm_base_add_listener(state->xdg_wm_base, &main_h_xdg_wm_base_listener, state);
|
||||
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
if (state->wl_seat) {
|
||||
printf("We got second seat, but we only need one\n");
|
||||
return;
|
||||
}
|
||||
state->wl_seat = wl_registry_bind(wl_registry, name, &wl_seat_interface, 4);
|
||||
if (!state->wl_seat)
|
||||
abortf("wl_registry_bind\n");
|
||||
wl_seat_add_listener(state->wl_seat, &main_h_wl_seat_listener, state);
|
||||
}
|
||||
}
|
||||
|
||||
static void main_h_wl_registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name){
|
||||
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener main_h_wl_registry_listener = {
|
||||
.global = main_h_wl_registry_global,
|
||||
.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,
|
||||
// };
|
||||
|
||||
|
||||
int main() {
|
||||
state_t state = { .width = 800, .height = 480 };
|
||||
state.wl_display = wl_display_connect(NULL);
|
||||
|
||||
if (!state.wl_display)
|
||||
abortf("Could not connect");
|
||||
state.wl_registry = wl_display_get_registry(state.wl_display);
|
||||
if (!state.wl_registry)
|
||||
abortf("wl_display_get_registry");
|
||||
wl_registry_add_listener(state.wl_registry, &main_h_wl_registry_listener, &state);
|
||||
wl_display_roundtrip(state.wl_display);
|
||||
if (!state.wl_compositor)
|
||||
abortf("No wl_compositor");
|
||||
if (!state.xdg_wm_base)
|
||||
abortf("No xdg_wm_base");
|
||||
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!state.xkb_context)
|
||||
abortf("xkb_context_new\n");
|
||||
state.wl_surface = wl_compositor_create_surface(state.wl_compositor);
|
||||
if (!state.wl_surface)
|
||||
abortf("wl_compositor_create_surface\n");
|
||||
state.xdg_surface = xdg_wm_base_get_xdg_surface(
|
||||
state.xdg_wm_base, state.wl_surface);
|
||||
if (!state.xdg_surface)
|
||||
abortf("xdg_wm_base_get_xdg_surface\n");
|
||||
xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state);
|
||||
state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
|
||||
if (!state.xdg_toplevel)
|
||||
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");
|
||||
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);
|
||||
|
||||
MargaretInstanceAndItsDebug vk_instance_and_debug = MargaretInstanceAndItsDebug_new(true);
|
||||
VkInstance vk_instance = vk_instance_and_debug.instance;
|
||||
VkSurfaceKHR vk_surface = margaret_create_surface(vk_instance, state.wl_display, state.wl_surface);
|
||||
VkPhysicalDevice physical_device = margaret_select_one_physical_device(vk_instance, vk_surface, cstr("nvidia"), cstr("NOT SPECIFIED"));
|
||||
ResultMargaretChosenQueueFamiliesOrSpanU8 queue_fam_res = margaret_choose_good_queue_families(physical_device, vk_surface);
|
||||
if (queue_fam_res.variant != Result_Ok)
|
||||
abortf("queue_fam_res.variant != Result_Ok");
|
||||
MargaretChosenQueueFamilies queue_fam = queue_fam_res.ok;
|
||||
VkDevice device = margaret_create_logical_device(physical_device, queue_fam);
|
||||
VkQueue graphics_queue;
|
||||
vkGetDeviceQueue(device, queue_fam.for_graphics, 0, &graphics_queue);
|
||||
VkQueue presentation_queue;
|
||||
vkGetDeviceQueue(device, queue_fam.for_graphics, 0, &presentation_queue);
|
||||
ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details(physical_device, 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);
|
||||
// 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);
|
||||
|
||||
Jane_r3 jane = Jane_r3_create(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)) {
|
||||
if (state.closed)
|
||||
break;
|
||||
}
|
||||
// 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);
|
||||
wl_surface_destroy(state.wl_surface);
|
||||
wl_compositor_destroy(state.wl_compositor);
|
||||
if (state.pointer)
|
||||
wl_pointer_destroy(state.pointer);
|
||||
xkb_context_unref(state.xkb_context);
|
||||
xkb_keymap_unref(state.xkb_keymap);
|
||||
xkb_state_unref(state.xkb_state);
|
||||
if (state.keyboard)
|
||||
wl_keyboard_destroy(state.keyboard);
|
||||
if (state.wl_seat)
|
||||
wl_seat_destroy(state.wl_seat);
|
||||
wl_registry_destroy(state.wl_registry);
|
||||
wl_display_disconnect(state.wl_display);
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user