diff --git a/Crafter.Graphics-UiImage.cppm b/Crafter.Graphics-UiImage.cppm deleted file mode 100644 index 51e2e2e..0000000 --- a/Crafter.Graphics-UiImage.cppm +++ /dev/null @@ -1,32 +0,0 @@ -// module; - -// #include - -// export module Crafter.Graphics:UiImage; -// import Crafter.Event; -// import :UiElement; - -// export namespace Crafter { -// class UiImage : public UiElement { -// public: -// int test = 150; -// Pixel* image; -// UiImage() { - -// } -// void Draw(Pixel* buffer, std::uint32_t x, std::uint32_t y, std::uint32_t right, std::uint32_t down) override { -// width = 128; -// height = 128; -// for(std::uint32_t x = 0; x < 128; x++) { -// for(std::uint32_t y = 0; y < 128; y++) { -// buffer[x*128+y].r = test%255; -// buffer[x*128+y].g = test%255; -// buffer[x*128+y].b = test%255; -// buffer[x*128+y].a = 255; -// } -// } -// test++; -// } -// ~UiImage() override {}; -// }; -// } \ No newline at end of file diff --git a/Crafter.Graphics-VulkanDevice.cpp b/Crafter.Graphics-VulkanDevice.cpp new file mode 100644 index 0000000..befe3e4 --- /dev/null +++ b/Crafter.Graphics-VulkanDevice.cpp @@ -0,0 +1,240 @@ +module; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GET_EXTENSION_FUNCTION(_id) ((PFN_##_id)(vkGetInstanceProcAddr(instance, #_id))) + +module Crafter.Graphics; +using namespace Crafter; +const char* const instanceExtensionNames[] = { + "VK_EXT_debug_utils", + "VK_KHR_surface", + "VK_KHR_wayland_surface" +}; +const char* const deviceExtensionNames[] = { + "VK_KHR_swapchain", + "VK_KHR_spirv_1_4", + "VK_EXT_mesh_shader", + "VK_KHR_shader_float_controls" +}; +const char* const layerNames[] = { + "VK_LAYER_KHRONOS_validation" +}; + + +void VulkanDevice::CHECK_VK_RESULT(VkResult result) { + if (result != VK_SUCCESS) + { + throw std::runtime_error(string_VkResult(result)); + } +} + +VkBool32 onError(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) +{ + printf("Vulkan "); + + switch (type) + { + case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT : + printf("general "); + break; + case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT : + printf("validation "); + break; + case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT : + printf("performance "); + break; + } + + switch (severity) + { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT : + printf("(verbose): "); + break; + default : + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT : + printf("(info): "); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT : + printf("(warning): "); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT : + printf("(error): "); + break; + } + + printf("%s\n", callbackData->pMessage); + + return 0; +} + +void VulkanDevice::CreateDevice() { + VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO}; + app.pApplicationName = ""; + app.pEngineName = "Crafter.Graphics"; + app.apiVersion = VK_MAKE_VERSION(1, 4, 0); + + VkInstanceCreateInfo instanceCreateInfo = {}; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceCreateInfo.pApplicationInfo = &app; + instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensionNames) / sizeof(const char*); + instanceCreateInfo.ppEnabledExtensionNames = instanceExtensionNames; + + size_t foundInstanceLayers = 0; + + std::uint32_t instanceLayerCount; + CHECK_VK_RESULT(vkEnumerateInstanceLayerProperties(&instanceLayerCount, NULL)); + + std::vector instanceLayerProperties(instanceLayerCount); + CHECK_VK_RESULT(vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProperties.data())); + + for (uint32_t i = 0; i < instanceLayerCount; i++) + { + for (size_t j = 0; j < sizeof(layerNames) / sizeof(const char*); j++) + { + if (std::strcmp(instanceLayerProperties[i].layerName, layerNames[j]) == 0) + { + foundInstanceLayers++; + } + } + } + + if (foundInstanceLayers >= sizeof(layerNames) / sizeof(const char*)) + { + instanceCreateInfo.enabledLayerCount = sizeof(layerNames) / sizeof(const char*); + instanceCreateInfo.ppEnabledLayerNames = layerNames; + } + + CHECK_VK_RESULT(vkCreateInstance(&instanceCreateInfo, NULL, &instance)); + + VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {}; + debugUtilsMessengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugUtilsMessengerCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugUtilsMessengerCreateInfo.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; + debugUtilsMessengerCreateInfo.pfnUserCallback = onError; + CHECK_VK_RESULT(GET_EXTENSION_FUNCTION(vkCreateDebugUtilsMessengerEXT)(instance, &debugUtilsMessengerCreateInfo, NULL, &debugMessenger)); + + uint32_t physDeviceCount; + vkEnumeratePhysicalDevices(instance, &physDeviceCount, NULL); + + std::vector physDevices(physDeviceCount); + vkEnumeratePhysicalDevices(instance, &physDeviceCount, physDevices.data()); + + uint32_t bestScore = 0; + + for (uint32_t i = 0; i < physDeviceCount; i++) + { + VkPhysicalDevice device = physDevices[i]; + + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + + uint32_t score; + + switch (properties.deviceType) + { + default : + continue; + case VK_PHYSICAL_DEVICE_TYPE_OTHER : + score = 1; + break; + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU : + score = 4; + break; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU : + score = 5; + break; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU : + score = 3; + break; + case VK_PHYSICAL_DEVICE_TYPE_CPU : + score = 2; + break; + } + + if (score > bestScore) + { + physDevice = device; + bestScore = score; + } + } + + + uint32_t queueFamilyCount; + vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, NULL); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, queueFamilies.data()); + + for (uint32_t i = 0; i < queueFamilyCount; i++) + { + if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + queueFamilyIndex = i; + break; + } + } + + float priority = 1; + + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = queueFamilyIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &priority; + + VkPhysicalDeviceMeshShaderFeaturesEXT ext_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT}; + ext_feature.meshShader = VK_TRUE; + VkPhysicalDeviceFeatures2 physical_features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + physical_features2.pNext = &ext_feature; + + VkDeviceCreateInfo deviceCreateInfo = {}; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensionNames) / sizeof(const char*); + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; + deviceCreateInfo.pNext = &physical_features2; + + uint32_t deviceLayerCount; + CHECK_VK_RESULT(vkEnumerateDeviceLayerProperties(physDevice, &deviceLayerCount, NULL)); + + std::vector deviceLayerProperties(deviceLayerCount); + CHECK_VK_RESULT(vkEnumerateDeviceLayerProperties(physDevice, &deviceLayerCount, deviceLayerProperties.data())); + + size_t foundDeviceLayers = 0; + + for (uint32_t i = 0; i < deviceLayerCount; i++) + { + for (size_t j = 0; j < sizeof(layerNames) / sizeof(const char*); j++) + { + if (strcmp(deviceLayerProperties[i].layerName, layerNames[j]) == 0) + { + foundDeviceLayers++; + } + } + } + + if (foundDeviceLayers >= sizeof(layerNames) / sizeof(const char*)) + { + deviceCreateInfo.enabledLayerCount = sizeof(layerNames) / sizeof(const char*); + deviceCreateInfo.ppEnabledLayerNames = layerNames; + } + + CHECK_VK_RESULT(vkCreateDevice(physDevice, &deviceCreateInfo, NULL, &device)); + vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); + + VkCommandPoolCreateInfo commandPoolcreateInfo = {}; + commandPoolcreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + commandPoolcreateInfo.queueFamilyIndex = queueFamilyIndex; + commandPoolcreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + CHECK_VK_RESULT(vkCreateCommandPool(device, &commandPoolcreateInfo, NULL, &commandPool)); +} \ No newline at end of file diff --git a/Crafter.Graphics-VulkanDevice.cppm b/Crafter.Graphics-VulkanDevice.cppm new file mode 100644 index 0000000..66cab39 --- /dev/null +++ b/Crafter.Graphics-VulkanDevice.cppm @@ -0,0 +1,24 @@ +module; + +#include +#include +#include + +export module Crafter.Graphics:VulkanDevice; + +export namespace Crafter { + class VulkanDevice { + public: + static void CreateDevice(); + static void CHECK_VK_RESULT(VkResult result); + inline static VkInstance instance = VK_NULL_HANDLE; + inline static VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + inline static VkPhysicalDevice physDevice = VK_NULL_HANDLE; + inline static VkDevice device = VK_NULL_HANDLE; + inline static std::uint32_t queueFamilyIndex = 0; + inline static VkQueue queue = VK_NULL_HANDLE; + inline static VkCommandPool commandPool = VK_NULL_HANDLE; + inline static VkSwapchainKHR swapchain = VK_NULL_HANDLE; + inline static VkRenderPass renderPass = VK_NULL_HANDLE; + }; +} \ No newline at end of file diff --git a/Crafter.Graphics-VulkanPipeline.cppm b/Crafter.Graphics-VulkanPipeline.cppm new file mode 100644 index 0000000..54b0ad8 --- /dev/null +++ b/Crafter.Graphics-VulkanPipeline.cppm @@ -0,0 +1,110 @@ +module; + +#include +#include +#include + +export module Crafter.Graphics:VulkanPipeline; +import :VulkanDevice; +import :VulkanShader; +import :WindowWaylandVulkan; + +namespace Crafter { + export template + class VulkanPipeline { + public: + inline static VkPipeline pipeline; + inline static VkPipelineLayout layout; + inline static VkDescriptorPool descriptor_pool; + inline static VkDescriptorSetLayout descriptor_set_layout; + inline static VkDescriptorSet descriptor_set; + static void CreatePipeline() { + VkDescriptorPoolCreateInfo descriptor_pool_create_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + descriptor_pool_create_info.maxSets = 2; + descriptor_pool_create_info.poolSizeCount = 0; + descriptor_pool_create_info.pPoolSizes = nullptr; + VulkanDevice::CHECK_VK_RESULT(vkCreateDescriptorPool(VulkanDevice::device, &descriptor_pool_create_info, nullptr, &descriptor_pool)); + + VkDescriptorSetLayoutCreateInfo descriptor_layout = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + descriptor_layout.bindingCount = 0; + descriptor_layout.pBindings = nullptr; + VulkanDevice::CHECK_VK_RESULT(vkCreateDescriptorSetLayout(VulkanDevice::device, &descriptor_layout, nullptr, &descriptor_set_layout)); + + VkDescriptorSetAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + alloc_info.descriptorPool = descriptor_pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &descriptor_set_layout; + VulkanDevice::CHECK_VK_RESULT(vkAllocateDescriptorSets(VulkanDevice::device, &alloc_info, &descriptor_set)); + + VkPipelineLayoutCreateInfo layout_info = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = &descriptor_set_layout; + VulkanDevice::CHECK_VK_RESULT(vkCreatePipelineLayout(VulkanDevice::device, &layout_info, nullptr, &layout)); + + VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; + raster.cullMode = VK_CULL_MODE_BACK_BIT; + raster.frontFace = VK_FRONT_FACE_CLOCKWISE; + raster.lineWidth = 1.0f; + + // Our attachment will write to all color channels, but no blending is enabled. + VkPipelineColorBlendAttachmentState blend_attachment{}; + blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; + blend.attachmentCount = 1; + blend.pAttachments = &blend_attachment; + + // We will have one viewport and scissor box. + VkPipelineViewportStateCreateInfo viewport{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; + viewport.viewportCount = 1; + viewport.scissorCount = 1; + + // Disable all depth testing. + VkPipelineDepthStencilStateCreateInfo depth_stencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; + + // No multisampling. + VkPipelineMultisampleStateCreateInfo multisample{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; + multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + // Specify that these states will be dynamic, i.e. not part of pipeline state object. + std::array dynamics{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + + VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; + dynamic.pDynamicStates = dynamics.data(); + dynamic.dynamicStateCount = static_cast(dynamics.size()); + + // Load our SPIR-V shaders. + std::array shader_stages{}; + + //Mesh stage of the pipeline + shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stages[0].stage = MeshShader::_stage; + shader_stages[0].module = MeshShader::shader; + shader_stages[0].pName = MeshShader::_entrypoint.value; + + // Fragment stage of the pipeline + shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stages[1].stage = FragmentShader::_stage; + shader_stages[1].module = FragmentShader::shader; + shader_stages[1].pName = FragmentShader::_entrypoint.value; + + VkGraphicsPipelineCreateInfo pipe{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; + pipe.stageCount = static_cast(shader_stages.size()); + pipe.pStages = shader_stages.data(); + pipe.pVertexInputState = nullptr; + pipe.pInputAssemblyState = nullptr; + pipe.pRasterizationState = &raster; + pipe.pColorBlendState = &blend; + pipe.pMultisampleState = &multisample; + pipe.pViewportState = &viewport; + pipe.pDepthStencilState = &depth_stencil; + pipe.pDynamicState = &dynamic; + + // We need to specify the pipeline layout and the render pass description up front as well. + pipe.renderPass = WindowWaylandVulkan::renderPass; + pipe.layout = layout; + + VulkanDevice::CHECK_VK_RESULT(vkCreateGraphicsPipelines(VulkanDevice::device, VK_NULL_HANDLE, 1, &pipe, nullptr, &pipeline)); + } + }; +} \ No newline at end of file diff --git a/Crafter.Graphics-VulkanShader.cppm b/Crafter.Graphics-VulkanShader.cppm new file mode 100644 index 0000000..e13fec1 --- /dev/null +++ b/Crafter.Graphics-VulkanShader.cppm @@ -0,0 +1,57 @@ +module; + +#include +#include +#include +#include +#include +#include + +export module Crafter.Graphics:VulkanShader; +import :VulkanDevice; + +namespace Crafter { + export template + struct StringLiteral { + constexpr StringLiteral(const char (&str)[N]) { + std::copy_n(str, N, value); + } + + char value[N]; + }; + + export template + class VulkanShader { + public: + inline static VkShaderModule shader; + constexpr static StringLiteral _entrypoint = entrypoint; + constexpr static VkShaderStageFlagBits _stage = stage; + static void CreateShader() { + std::ifstream file(path.value, std::ios::binary); + if (!file) { + std::cerr << "Error: Could not open file " << path.value << std::endl; + } + + // Move to the end of the file to determine its size + file.seekg(0, std::ios::end); + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector spirv(size / sizeof(std::uint32_t)); + + // Read the data into the vector + if (!file.read(reinterpret_cast(spirv.data()), size)) { + std::cerr << "Error: Could not read data from file" << std::endl; + } + + file.close(); + + VkShaderModuleCreateInfo module_info{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + module_info.codeSize = spirv.size() * sizeof(uint32_t); + module_info.pCode = spirv.data(); + + VkShaderModule shader_module; + VulkanDevice::CHECK_VK_RESULT(vkCreateShaderModule(VulkanDevice::device, &module_info, nullptr, &shader)); + } + }; +} \ No newline at end of file diff --git a/Crafter.Graphics-Window.cpp b/Crafter.Graphics-Window.cpp index 98331a4..bee00d7 100644 --- a/Crafter.Graphics-Window.cpp +++ b/Crafter.Graphics-Window.cpp @@ -1,360 +1,12 @@ module; -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xdg-shell-client-protocol.h" -#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include "cat.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - module Crafter.Graphics; import Crafter.Event; using namespace Crafter; -static void xdg_wm_base_handle_ping(void* data, xdg_wm_base* xdg_wm_base, std::uint32_t serial) { - xdg_wm_base_pong(xdg_wm_base, serial); -} - -xdg_wm_base_listener xdgWmBaseListener = { -.ping = xdg_wm_base_handle_ping, -}; - - -void Window::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state) { - Window* window = reinterpret_cast(data); - if (button == BTN_LEFT) { - if(state == WL_POINTER_BUTTON_STATE_PRESSED) { - window->mouseLeftHeld = true; - window->onMouseLeftClick.Invoke(window->currentMousePos); - } else { - window->mouseLeftHeld = false; - window->onMouseLeftRelease.Invoke(window->currentMousePos); - } - } else if(button == BTN_RIGHT){ - if(state == WL_POINTER_BUTTON_STATE_PRESSED) { - window->mouseRightHeld = true; - window->onMouseRightClick.Invoke(window->currentMousePos); - } else { - window->mouseRightHeld = true; - window->onMouseRightRelease.Invoke(window->currentMousePos); - } - } -} - -void Window::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - Window* window = reinterpret_cast(data); - MousePoint pos = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)}; - window->lastMousePos = window->currentMousePos; - window->currentMousePos = pos; - window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y}; - window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); -} - -void Window::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, uint serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - Window* window = reinterpret_cast(data); - window->onMouseEnter.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); -} - -void Window::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) { - Window* window = reinterpret_cast(data); - window->onMouseEnter.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); -} - -void Window::PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value) { - std::cout << wl_fixed_to_double(value) << std::endl; -} - -wl_pointer_listener Window::pointer_listener = { -.enter = Window::PointerListenerHandleEnter, -.leave = Window::PointerListenerHandleLeave, -.motion = Window::PointerListenerHandleMotion, -.button = Window::pointer_handle_button, -.axis = Window::PointerListenerHandleAxis, -}; - -void Window::seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities) { - Window* window = reinterpret_cast(data); - window->seat = seat; - if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - wl_pointer* pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(pointer, &pointer_listener, window); - } -} - -wl_seat_listener Window::seat_listener = { -.capabilities = seat_handle_capabilities, -}; - -void Window::handle_global(void *data, wl_registry *registry, std::uint32_t name, const char *interface, std::uint32_t version) { - Window* window = reinterpret_cast(data); - if (strcmp(interface, wl_shm_interface.name) == 0) { - window->shm = reinterpret_cast(wl_registry_bind(registry, name, &wl_shm_interface, 1)); - } else if (strcmp(interface, wl_seat_interface.name) == 0) { - wl_seat* seat = reinterpret_cast(wl_registry_bind(registry, name, &wl_seat_interface, 1)); - wl_seat_add_listener(seat, &seat_listener, window); - } else if (compositor == NULL && strcmp(interface, wl_compositor_interface.name) == 0) { - compositor = reinterpret_cast(wl_registry_bind(registry, name, &wl_compositor_interface, 1)); - } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { - window->xdgWmBase = reinterpret_cast(wl_registry_bind(registry, name, &xdg_wm_base_interface, 1)); - xdg_wm_base_add_listener(window->xdgWmBase, &xdgWmBaseListener, NULL); - } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { - window->manager = reinterpret_cast(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1)); - } -} - -static void handle_global_remove(void* data, wl_registry* registry, uint32_t name) { - +Window::Window(std::string name, std::uint32_t width, std::uint32_t height) : name(name), width(width), height(height) { -} - -wl_registry_listener Window::registry_listener = { -.global = Window::handle_global, -.global_remove = handle_global_remove, -}; - -static void noop5(void*, xdg_toplevel*, std::int32_t, std::int32_t, wl_array*){ - -} - -void Window::xdg_toplevel_handle_close(void* data, xdg_toplevel*) { - Window* window = reinterpret_cast(data); - window->onClose.Invoke(); -} - -xdg_toplevel_listener Window::xdg_toplevel_listener = { -.configure = noop5, -.close = Window::xdg_toplevel_handle_close, -}; - -void Window::xdg_surface_handle_configure(void* data, xdg_surface* xdg_surface, std::uint32_t serial) { - Window* window = reinterpret_cast(data); - // The compositor configures our surface, acknowledge the configure event - xdg_surface_ack_configure(xdg_surface, serial); - - if (window->configured) { - // If this isn't the first configure event we've received, we already - // have a buffer attached, so no need to do anything. Commit the - // surface to apply the configure acknowledgement. - wl_surface_commit(window->surface); - } - - window->configured = true; -} - -xdg_surface_listener Window::xdg_surface_listener = { -.configure = xdg_surface_handle_configure, -}; - -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 anonymous_shm_open(void) { - char name[] = "/hello-wayland-XXXXXX"; - int retries = 100; - - do { - randname(name + strlen(name) - 6); - - --retries; - // shm_open guarantees that O_CLOEXEC is set - 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 create_shm_file(off_t size) { - int fd = anonymous_shm_open(); - if (fd < 0) { - return fd; - } - - if (ftruncate(fd, size) < 0) { - close(fd); - return -1; - } - - return fd; -} - -Window::Window(std::string name, std::uint32_t width, std::uint32_t height) : width(width), height(height) { - // Connect to the Wayland compositor - display = wl_display_connect(NULL); - if (display == NULL) { - std::cerr << "failed to create display" << std::endl; - } - // Obtain the wl_registry and fetch the list of globals - wl_registry* registry = wl_display_get_registry(display); - wl_registry_add_listener(registry, ®istry_listener, this); - if (wl_display_roundtrip(display) == -1) { - exit(EXIT_FAILURE); - } - // Check that all globals we require are available - if (shm == NULL || compositor == NULL || xdgWmBase == NULL) { - std::cerr << "no wl_shm, wl_compositor or xdg_wm_base support" << std::endl; - exit(EXIT_FAILURE); - } - - // Create a wl_surface, a xdg_surface and a xdg_toplevel - surface = wl_compositor_create_surface(compositor); - xdgSurface = xdg_wm_base_get_xdg_surface(xdgWmBase, surface); - xdgToplevel = xdg_surface_get_toplevel(xdgSurface); - - - xdg_surface_add_listener(xdgSurface, &xdg_surface_listener, this); - xdg_toplevel_add_listener(xdgToplevel, &xdg_toplevel_listener, this); - wl_surface_commit(surface); - - while (wl_display_dispatch(display) != -1 && !configured) { - // This space intentionally left blank - } - - // Create a wl_buffer, attach it to the surface and commit the surface - int stride = width * 4; - int size = stride * height; - - // Allocate a shared memory file with the right size - int fd = create_shm_file(size); - if (fd < 0) { - fprintf(stderr, "creating a buffer file for %d B failed: %m\n", size); - } - - // Map the shared memory file - shm_data = reinterpret_cast(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); - if (shm_data == MAP_FAILED) { - fprintf(stderr, "mmap failed: %m\n"); - close(fd); - } - - // Create a wl_buffer from our shared memory file descriptor - wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); - buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - - // Now that we've mapped the file and created the wl_buffer, we no longer - // need to keep file descriptor opened - close(fd); - - - if (buffer == NULL) { - exit(EXIT_FAILURE); - } - - wl_surface_attach(surface, buffer, 0, 0); - wl_surface_commit(surface); - - for(std::uint32_t x = 0; x < 128; x++) { - for(std::uint32_t y = 0; y < 128; y++) { - shm_data[x*128+y].r = 0; - shm_data[x*128+y].g = 0; - shm_data[x*128+y].b = 0; - shm_data[x*128+y].a = 255; - } - } - - - zxdg_toplevel_decoration_v1* decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(manager, xdgToplevel); // toplevel is from xdg_surface_get_toplevel - zxdg_toplevel_decoration_v1_set_mode(decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); -} - - -void ScaleBitmapR8G8B8(Pixel* dst, const Pixel* src, std::uint32_t srcWidth, std::uint32_t srcHeight, std::uint32_t dstWidth, std::uint32_t dstHeight) { - for (std::uint32_t y = 0; y < dstHeight; y++) { - std::uint32_t srcY = y * srcHeight / dstHeight; - for (std::uint32_t x = 0; x < dstWidth; x++) { - std::uint32_t srcX = x * srcWidth / dstWidth; - const Pixel* srcPixel = src + (srcY * srcWidth + srcX); - Pixel* dstPixel = dst + (y * dstWidth + x); - dstPixel[0] = srcPixel[0]; - } - } -} - -void Window::Start() { - while (wl_display_dispatch(display) != -1) { - wl_surface_attach(surface, buffer, 0, 0); - for(UiElement* element : elements.components) { - std::int32_t realX; - std::int32_t realY; - std::int32_t elementWidth; - std::int32_t elementHeight; - if(element->ignoreScaling) { - if(element->useRelativeSize) { - elementWidth = element->relativeWidth*width; - elementHeight = element->relativeHeight*height; - } else { - elementWidth = element->absoluteWidth; - elementHeight = element->absoluteHeight; - } - } else { - if(element->useRelativeSize) { - elementWidth = element->relativeWidth*width*scale; - elementHeight = element->relativeHeight*height*scale; - } else { - elementWidth = element->absoluteWidth*scale; - elementHeight = element->absoluteHeight*scale; - } - } - realX = (element->anchorX*width)-(element->anchorOffsetX*elementWidth); - realY = (element->anchorY*height)-(element->anchorOffsetY*elementHeight); - std::vector scaled(elementWidth*elementHeight); - ScaleBitmapR8G8B8(scaled.data(), element->buffer.data(), element->bufferWidth, element->bufferHeight, elementWidth, elementHeight); - for(std::int32_t x = realX; x-realX < elementWidth; x++) { - for(std::int32_t y = realY; y-realY < elementHeight; y++) { - if(x > 0 && x < width && y > 0 && y < height) { - shm_data[x*width+y] = scaled[(x-realX)*elementWidth+(y-realY)]; - } - } - } - wl_surface_damage(surface, realX, realY, elementWidth, elementHeight); - } - wl_surface_commit(surface); - } -} - -Window::~Window() { - xdg_toplevel_destroy(xdgToplevel); - xdg_surface_destroy(xdgSurface); - wl_surface_destroy(surface); - wl_buffer_destroy(buffer); } \ No newline at end of file diff --git a/Crafter.Graphics-Window.cppm b/Crafter.Graphics-Window.cppm index 1025ace..19cc70e 100644 --- a/Crafter.Graphics-Window.cppm +++ b/Crafter.Graphics-Window.cppm @@ -2,10 +2,6 @@ module; #include #include -#include -#include -#include "xdg-shell-client-protocol.h" -#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" export module Crafter.Graphics:Window; import Crafter.Event; @@ -33,39 +29,11 @@ export namespace Crafter { bool mouseLeftHeld = false; bool mouseRightHeld = false; ComponentRefVectorOwning elements; + std::string name; std::uint32_t width; std::uint32_t height; float scale = 1; + bool open = true; Window(std::string name, std::uint32_t width, std::uint32_t height); - ~Window(); - void Start(); - void Draw(std::uint32_t x, std::uint32_t y, std::uint32_t right, std::uint32_t down); - private: - Pixel* shm_data = NULL; - bool configured = false; - wl_shm* shm = NULL; - wl_seat* seat = NULL; - xdg_toplevel* xdgToplevel = NULL; - xdg_wm_base* xdgWmBase = NULL; - zxdg_decoration_manager_v1* manager = NULL; - wl_surface* surface = NULL; - wl_buffer* buffer = NULL; - xdg_surface* xdgSurface = NULL; - wl_display* display = NULL; - inline static wl_compositor* compositor = NULL; - static wl_pointer_listener pointer_listener; - static wl_seat_listener seat_listener; - static wl_registry_listener registry_listener; - static xdg_surface_listener xdg_surface_listener; - static xdg_toplevel_listener xdg_toplevel_listener; - static void PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y); - static void PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value); - static void PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, uint serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y); - static void PointerListenerHandleLeave(void*, wl_pointer*, std::uint32_t, wl_surface*); - static void xdg_toplevel_handle_close(void* data, xdg_toplevel*); - static void handle_global(void* data, wl_registry* registry, std::uint32_t name, const char* interface, std::uint32_t version); - static void pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state); - static void seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities); - static void xdg_surface_handle_configure(void* data, xdg_surface* xdg_surface, std::uint32_t serial); }; } \ No newline at end of file diff --git a/Crafter.Graphics-WindowWayland.cpp b/Crafter.Graphics-WindowWayland.cpp new file mode 100644 index 0000000..7bf5388 --- /dev/null +++ b/Crafter.Graphics-WindowWayland.cpp @@ -0,0 +1,305 @@ +module; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xdg-shell-client-protocol.h" +#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include "cat.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +module Crafter.Graphics; +import Crafter.Event; +using namespace Crafter; + +static void xdg_wm_base_handle_ping(void* data, xdg_wm_base* xdg_wm_base, std::uint32_t serial) { + xdg_wm_base_pong(xdg_wm_base, serial); +} + +xdg_wm_base_listener xdgWmBaseListener = { +.ping = xdg_wm_base_handle_ping, +}; + + +void WindowWayland::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state) { + WindowWayland* window = reinterpret_cast(data); + if (button == BTN_LEFT) { + if(state == WL_POINTER_BUTTON_STATE_PRESSED) { + window->mouseLeftHeld = true; + window->onMouseLeftClick.Invoke(window->currentMousePos); + } else { + window->mouseLeftHeld = false; + window->onMouseLeftRelease.Invoke(window->currentMousePos); + } + } else if(button == BTN_RIGHT){ + if(state == WL_POINTER_BUTTON_STATE_PRESSED) { + window->mouseRightHeld = true; + window->onMouseRightClick.Invoke(window->currentMousePos); + } else { + window->mouseRightHeld = true; + window->onMouseRightRelease.Invoke(window->currentMousePos); + } + } +} + +void WindowWayland::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + WindowWayland* window = reinterpret_cast(data); + MousePoint pos = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)}; + window->lastMousePos = window->currentMousePos; + window->currentMousePos = pos; + window->mouseDelta = {window->currentMousePos.x-window->lastMousePos.x, window->currentMousePos.y-window->lastMousePos.y}; + window->onMouseMove.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); +} + +void WindowWayland::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, uint serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + WindowWayland* window = reinterpret_cast(data); + window->onMouseEnter.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); +} + +void WindowWayland::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) { + WindowWayland* window = reinterpret_cast(data); + window->onMouseEnter.Invoke({window->lastMousePos, window->currentMousePos, window->mouseDelta}); +} + +void WindowWayland::PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value) { + std::cout << wl_fixed_to_double(value) << std::endl; +} + +wl_pointer_listener WindowWayland::pointer_listener = { +.enter = WindowWayland::PointerListenerHandleEnter, +.leave = WindowWayland::PointerListenerHandleLeave, +.motion = WindowWayland::PointerListenerHandleMotion, +.button = WindowWayland::pointer_handle_button, +.axis = WindowWayland::PointerListenerHandleAxis, +}; + +void WindowWayland::seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities) { + WindowWayland* window = reinterpret_cast(data); + window->seat = seat; + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + wl_pointer* pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(pointer, &pointer_listener, window); + } +} + +wl_seat_listener WindowWayland::seat_listener = { +.capabilities = seat_handle_capabilities, +}; + +void WindowWayland::handle_global(void *data, wl_registry *registry, std::uint32_t name, const char *interface, std::uint32_t version) { + WindowWayland* window = reinterpret_cast(data); + if (strcmp(interface, wl_shm_interface.name) == 0) { + window->shm = reinterpret_cast(wl_registry_bind(registry, name, &wl_shm_interface, 1)); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + wl_seat* seat = reinterpret_cast(wl_registry_bind(registry, name, &wl_seat_interface, 1)); + wl_seat_add_listener(seat, &seat_listener, window); + } else if (compositor == NULL && strcmp(interface, wl_compositor_interface.name) == 0) { + compositor = reinterpret_cast(wl_registry_bind(registry, name, &wl_compositor_interface, 1)); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + window->xdgWmBase = reinterpret_cast(wl_registry_bind(registry, name, &xdg_wm_base_interface, 1)); + xdg_wm_base_add_listener(window->xdgWmBase, &xdgWmBaseListener, NULL); + } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + window->manager = reinterpret_cast(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1)); + } +} + +static void handle_global_remove(void* data, wl_registry* registry, uint32_t name) { + + +} + +wl_registry_listener WindowWayland::registry_listener = { +.global = WindowWayland::handle_global, +.global_remove = handle_global_remove, +}; + +static void noop5(void*, xdg_toplevel*, std::int32_t, std::int32_t, wl_array*){ + +} + +void WindowWayland::xdg_toplevel_handle_close(void* data, xdg_toplevel*) { + WindowWayland* window = reinterpret_cast(data); + window->onClose.Invoke(); + window->open = false; +} + +xdg_toplevel_listener WindowWayland::xdg_toplevel_listener = { +.configure = noop5, +.close = WindowWayland::xdg_toplevel_handle_close, +}; + +void WindowWayland::xdg_surface_handle_configure(void* data, xdg_surface* xdg_surface, std::uint32_t serial) { + WindowWayland* window = reinterpret_cast(data); + // The compositor configures our surface, acknowledge the configure event + xdg_surface_ack_configure(xdg_surface, serial); + + if (window->configured) { + // If this isn't the first configure event we've received, we already + // have a buffer attached, so no need to do anything. Commit the + // surface to apply the configure acknowledgement. + wl_surface_commit(window->surface); + } + + window->configured = true; +} + +xdg_surface_listener WindowWayland::xdg_surface_listener = { +.configure = xdg_surface_handle_configure, +}; + +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 anonymous_shm_open(void) { + char name[] = "/hello-wayland-XXXXXX"; + int retries = 100; + + do { + randname(name + strlen(name) - 6); + + --retries; + // shm_open guarantees that O_CLOEXEC is set + 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 create_shm_file(off_t size) { + int fd = anonymous_shm_open(); + if (fd < 0) { + return fd; + } + + if (ftruncate(fd, size) < 0) { + close(fd); + return -1; + } + + return fd; +} + +WindowWayland::WindowWayland(std::string name, std::uint32_t width, std::uint32_t height) : Window(name, width, height) { + // Connect to the Wayland compositor + display = wl_display_connect(NULL); + if (display == NULL) { + std::cerr << "failed to create display" << std::endl; + } + // Obtain the wl_registry and fetch the list of globals + wl_registry* registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, this); + if (wl_display_roundtrip(display) == -1) { + exit(EXIT_FAILURE); + } + // Check that all globals we require are available + if (shm == NULL || compositor == NULL || xdgWmBase == NULL) { + std::cerr << "no wl_shm, wl_compositor or xdg_wm_base support" << std::endl; + exit(EXIT_FAILURE); + } + + // Create a wl_surface, a xdg_surface and a xdg_toplevel + surface = wl_compositor_create_surface(compositor); + xdgSurface = xdg_wm_base_get_xdg_surface(xdgWmBase, surface); + xdgToplevel = xdg_surface_get_toplevel(xdgSurface); + + + xdg_surface_add_listener(xdgSurface, &xdg_surface_listener, this); + xdg_toplevel_add_listener(xdgToplevel, &xdg_toplevel_listener, this); + wl_surface_commit(surface); + + while (wl_display_dispatch(display) != -1 && !configured) { + // This space intentionally left blank + } + + // Create a wl_buffer, attach it to the surface and commit the surface + int stride = width * 4; + int size = stride * height; + + // Allocate a shared memory file with the right size + int fd = create_shm_file(size); + if (fd < 0) { + fprintf(stderr, "creating a buffer file for %d B failed: %m\n", size); + } + + // Map the shared memory file + shm_data = reinterpret_cast(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + if (shm_data == MAP_FAILED) { + fprintf(stderr, "mmap failed: %m\n"); + close(fd); + } + + // Create a wl_buffer from our shared memory file descriptor + wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); + buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + + // Now that we've mapped the file and created the wl_buffer, we no longer + // need to keep file descriptor opened + close(fd); + + + if (buffer == NULL) { + exit(EXIT_FAILURE); + } + + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_commit(surface); + + for(std::uint32_t x = 0; x < 128; x++) { + for(std::uint32_t y = 0; y < 128; y++) { + shm_data[x*128+y].r = 0; + shm_data[x*128+y].g = 0; + shm_data[x*128+y].b = 0; + shm_data[x*128+y].a = 255; + } + } + + zxdg_toplevel_decoration_v1* decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(manager, xdgToplevel); // toplevel is from xdg_surface_get_toplevel + zxdg_toplevel_decoration_v1_set_mode(decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} + +WindowWayland::~WindowWayland() { + xdg_toplevel_destroy(xdgToplevel); + xdg_surface_destroy(xdgSurface); + wl_surface_destroy(surface); + wl_buffer_destroy(buffer); +} \ No newline at end of file diff --git a/Crafter.Graphics-WindowWayland.cppm b/Crafter.Graphics-WindowWayland.cppm new file mode 100644 index 0000000..2447670 --- /dev/null +++ b/Crafter.Graphics-WindowWayland.cppm @@ -0,0 +1,49 @@ +module; + +#include +#include +#include +#include "xdg-shell-client-protocol.h" +#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" + +export module Crafter.Graphics:WindowWayland; +import Crafter.Event; +import :UiElement; +import :Types; +import :Window; +import Crafter.Component; + +export namespace Crafter { + class WindowWayland : public Window { + public: + WindowWayland(std::string name, std::uint32_t width, std::uint32_t height); + ~WindowWayland(); + protected: + Pixel* shm_data = NULL; + bool configured = false; + wl_shm* shm = NULL; + wl_seat* seat = NULL; + xdg_toplevel* xdgToplevel = NULL; + xdg_wm_base* xdgWmBase = NULL; + zxdg_decoration_manager_v1* manager = NULL; + wl_surface* surface = NULL; + wl_buffer* buffer = NULL; + xdg_surface* xdgSurface = NULL; + wl_display* display = NULL; + inline static wl_compositor* compositor = NULL; + static wl_pointer_listener pointer_listener; + static wl_seat_listener seat_listener; + static wl_registry_listener registry_listener; + static xdg_surface_listener xdg_surface_listener; + static xdg_toplevel_listener xdg_toplevel_listener; + static void PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, uint time, wl_fixed_t surface_x, wl_fixed_t surface_y); + static void PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value); + static void PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, uint serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y); + static void PointerListenerHandleLeave(void*, wl_pointer*, std::uint32_t, wl_surface*); + static void xdg_toplevel_handle_close(void* data, xdg_toplevel*); + static void handle_global(void* data, wl_registry* registry, std::uint32_t name, const char* interface, std::uint32_t version); + static void pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state); + static void seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities); + static void xdg_surface_handle_configure(void* data, xdg_surface* xdg_surface, std::uint32_t serial); + }; +} \ No newline at end of file diff --git a/Crafter.Graphics-WindowWaylandVulkan.cpp b/Crafter.Graphics-WindowWaylandVulkan.cpp new file mode 100644 index 0000000..8547c46 --- /dev/null +++ b/Crafter.Graphics-WindowWaylandVulkan.cpp @@ -0,0 +1,268 @@ +module; + +#include +#include +#include +#include +#include +#include +#include +#include + +module Crafter.Graphics; +import Crafter.Event; +using namespace Crafter; + +void WindowWaylandVulkan::CreateSwapchain() +{ + VkResult result; + + VkSurfaceCapabilitiesKHR capabilities; + VulkanDevice::CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VulkanDevice::physDevice, vulkanSurface, &capabilities)); + + uint32_t formatCount; + VulkanDevice::CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(VulkanDevice::physDevice, vulkanSurface, &formatCount, NULL)); + + std::vector formats(formatCount); + VulkanDevice::CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(VulkanDevice::physDevice, vulkanSurface, &formatCount, formats.data())); + + VkSurfaceFormatKHR chosenFormat = formats[0]; + + for (uint32_t i = 0; i < formatCount; i++) + { + if (formats[i].format == VK_FORMAT_B8G8R8A8_UNORM) + { + chosenFormat = formats[i]; + break; + } + } + + format = chosenFormat.format; + + imageCount = capabilities.minImageCount + 1 < capabilities.maxImageCount ? capabilities.minImageCount + 1 : capabilities.minImageCount; + + VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; + swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchainCreateInfo.surface = vulkanSurface; + swapchainCreateInfo.minImageCount = imageCount; + swapchainCreateInfo.imageFormat = chosenFormat.format; + swapchainCreateInfo.imageColorSpace = chosenFormat.colorSpace; + swapchainCreateInfo.imageExtent.width = width; + swapchainCreateInfo.imageExtent.height = height; + swapchainCreateInfo.imageArrayLayers = 1; + swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchainCreateInfo.preTransform = capabilities.currentTransform; + swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchainCreateInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + swapchainCreateInfo.clipped = 1; + VulkanDevice::CHECK_VK_RESULT(vkCreateSwapchainKHR(VulkanDevice::device, &swapchainCreateInfo, NULL, &swapchain)); + + VkAttachmentDescription attachment = {}; + attachment.format = format; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference attachmentRef = {}; + attachmentRef.attachment = 0; + attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attachmentRef; + + VkRenderPassCreateInfo renderPasscreateInfo = {}; + renderPasscreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPasscreateInfo.flags = 0; + renderPasscreateInfo.attachmentCount = 1; + renderPasscreateInfo.pAttachments = &attachment; + renderPasscreateInfo.subpassCount = 1; + renderPasscreateInfo.pSubpasses = &subpass; + VulkanDevice::CHECK_VK_RESULT(vkCreateRenderPass(VulkanDevice::device, &renderPasscreateInfo, NULL, &renderPass)); + + VulkanDevice::CHECK_VK_RESULT(vkGetSwapchainImagesKHR(VulkanDevice::device, swapchain, &imageCount, NULL)); + + std::vector images(imageCount); + VulkanDevice::CHECK_VK_RESULT(vkGetSwapchainImagesKHR(VulkanDevice::device, swapchain, &imageCount, images.data())); + + swapchainElements.resize(imageCount); + + for (uint32_t i = 0; i < imageCount; i++) + { + VkCommandBufferAllocateInfo commandBufferAllocInfo = {}; + commandBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + commandBufferAllocInfo.commandPool = VulkanDevice::commandPool; + commandBufferAllocInfo.commandBufferCount = 1; + commandBufferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(VulkanDevice::device, &commandBufferAllocInfo, &swapchainElements[i].commandBuffer); + + swapchainElements[i].image = images[i]; + + VkImageViewCreateInfo imageViewcreateInfo = {}; + imageViewcreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewcreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewcreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewcreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewcreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewcreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewcreateInfo.subresourceRange.baseMipLevel = 0; + imageViewcreateInfo.subresourceRange.levelCount = 1; + imageViewcreateInfo.subresourceRange.baseArrayLayer = 0; + imageViewcreateInfo.subresourceRange.layerCount = 1; + imageViewcreateInfo.image = swapchainElements[i].image; + imageViewcreateInfo.format = format; + imageViewcreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + VulkanDevice::CHECK_VK_RESULT(vkCreateImageView(VulkanDevice::device, &imageViewcreateInfo, NULL, &swapchainElements[i].imageView)); + + VkFramebufferCreateInfo framebufferCreateInfo = {}; + framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferCreateInfo.renderPass = renderPass; + framebufferCreateInfo.attachmentCount = 1; + framebufferCreateInfo.pAttachments = &swapchainElements[i].imageView; + framebufferCreateInfo.width = width; + framebufferCreateInfo.height = height; + framebufferCreateInfo.layers = 1; + VulkanDevice::CHECK_VK_RESULT(vkCreateFramebuffer(VulkanDevice::device, &framebufferCreateInfo, NULL, &swapchainElements[i].framebuffer)); + + VkSemaphoreCreateInfo startSemaphoreCreateInfo = {}; + startSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VulkanDevice::CHECK_VK_RESULT(vkCreateSemaphore(VulkanDevice::device, &startSemaphoreCreateInfo, NULL, &swapchainElements[i].startSemaphore)); + + VkSemaphoreCreateInfo endSemaphoreCreateInfo = {}; + endSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VulkanDevice::CHECK_VK_RESULT(vkCreateSemaphore(VulkanDevice::device, &endSemaphoreCreateInfo, NULL, &swapchainElements[i].endSemaphore)); + + VkFenceCreateInfo fenceCreateInfo = {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + VulkanDevice::CHECK_VK_RESULT(vkCreateFence(VulkanDevice::device, &fenceCreateInfo, NULL, &swapchainElements[i].fence)); + + swapchainElements[i].lastFence = VK_NULL_HANDLE; + } +} + +void WindowWaylandVulkan::DestroySwapchain() +{ + for (uint32_t i = 0; i < imageCount; i++) + { + vkDestroyFence(VulkanDevice::device, swapchainElements[i].fence, NULL); + vkDestroySemaphore(VulkanDevice::device, swapchainElements[i].endSemaphore, NULL); + vkDestroySemaphore(VulkanDevice::device, swapchainElements[i].startSemaphore, NULL); + vkDestroyFramebuffer(VulkanDevice::device, swapchainElements[i].framebuffer, NULL); + vkDestroyImageView(VulkanDevice::device, swapchainElements[i].imageView, NULL); + vkFreeCommandBuffers(VulkanDevice::device, VulkanDevice::commandPool, 1, &swapchainElements[i].commandBuffer); + } + + vkDestroyRenderPass(VulkanDevice::device, renderPass, NULL); + vkDestroySwapchainKHR(VulkanDevice::device, swapchain, NULL); +} + +PFN_vkCmdDrawMeshTasksEXT command; + +WindowWaylandVulkan::WindowWaylandVulkan(std::string name, std::uint32_t width, std::uint32_t height) : WindowWayland(name, width, height) { + VkWaylandSurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + createInfo.display = display; + createInfo.surface = surface; + VulkanDevice::CHECK_VK_RESULT(vkCreateWaylandSurfaceKHR(VulkanDevice::instance, &createInfo, NULL, &vulkanSurface)); + CreateSwapchain(); + command = reinterpret_cast(vkGetDeviceProcAddr(VulkanDevice::device, "vkCmdDrawMeshTasksEXT")); +} + +void WindowWaylandVulkan::Start() { + thread = std::thread([this](){ + while (open && wl_display_dispatch(display) != -1) { + + } + }); + while(true) { + SwapchainElement* currentElement = &swapchainElements[currentFrame]; + + VulkanDevice::CHECK_VK_RESULT(vkWaitForFences(VulkanDevice::device, 1, ¤tElement->fence, 1, UINT64_MAX)); + VulkanDevice::CHECK_VK_RESULT(vkAcquireNextImageKHR(VulkanDevice::device, swapchain, UINT64_MAX, currentElement->startSemaphore, NULL, &imageIndex)); + + SwapchainElement* element = &swapchainElements[imageIndex]; + if (element->lastFence) { + VulkanDevice::CHECK_VK_RESULT(vkWaitForFences(VulkanDevice::device, 1, &element->lastFence, 1, UINT64_MAX)); + } + + element->lastFence = currentElement->fence; + + VulkanDevice::CHECK_VK_RESULT(vkResetFences(VulkanDevice::device, 1, ¤tElement->fence)); + + VkCommandBufferBeginInfo commandBeginInfo = {}; + commandBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + commandBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VulkanDevice::CHECK_VK_RESULT(vkBeginCommandBuffer(element->commandBuffer, &commandBeginInfo)); + + VkClearValue clearValue = {{ + 1.0f, + 0.0f, + 1.0f, + 1.0f + }}; + + VkRenderPassBeginInfo renderBeginInfo = {}; + renderBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderBeginInfo.renderPass = renderPass; + renderBeginInfo.framebuffer = element->framebuffer; + renderBeginInfo.renderArea.offset.x = 0; + renderBeginInfo.renderArea.offset.y = 0; + renderBeginInfo.renderArea.extent.width = width; + renderBeginInfo.renderArea.extent.height = height; + renderBeginInfo.clearValueCount = 1; + renderBeginInfo.pClearValues = &clearValue; + + vkCmdBeginRenderPass(element->commandBuffer, &renderBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = {0, 0, static_cast(width), static_cast(height), 0, 1}; + vkCmdSetViewport(element->commandBuffer, 0, 1, &viewport); + + VkRect2D scissor = {{static_cast(width), static_cast(height)},{0,0}}; + vkCmdSetScissor(element->commandBuffer, 0, 1, &scissor); + + vkCmdBindDescriptorSets(element->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, VulkanPipeline, VulkanShader<"test2.spirv", "main", VK_SHADER_STAGE_FRAGMENT_BIT>>::layout, 0, 1, &VulkanPipeline, VulkanShader<"test2.spirv", "main", VK_SHADER_STAGE_FRAGMENT_BIT>>::descriptor_set, 0, nullptr); + vkCmdBindPipeline(element->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, VulkanPipeline, VulkanShader<"test2.spirv", "main", VK_SHADER_STAGE_FRAGMENT_BIT>>::pipeline); + + command(element->commandBuffer, 1, 1, 1); + + vkCmdEndRenderPass(element->commandBuffer); + + VulkanDevice::CHECK_VK_RESULT(vkEndCommandBuffer(element->commandBuffer)); + + const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = ¤tElement->startSemaphore; + submitInfo.pWaitDstStageMask = &waitStage; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &element->commandBuffer; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = ¤tElement->endSemaphore; + + VulkanDevice::CHECK_VK_RESULT(vkQueueSubmit(VulkanDevice::queue, 1, &submitInfo, currentElement->fence)); + + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = ¤tElement->endSemaphore; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain; + presentInfo.pImageIndices = &imageIndex; + + VulkanDevice::CHECK_VK_RESULT(vkQueuePresentKHR(VulkanDevice::queue, &presentInfo)); + + currentFrame = (currentFrame + 1) % imageCount; + + wl_display_roundtrip(display); + } +} \ No newline at end of file diff --git a/Crafter.Graphics-WindowWaylandVulkan.cppm b/Crafter.Graphics-WindowWaylandVulkan.cppm new file mode 100644 index 0000000..9859e19 --- /dev/null +++ b/Crafter.Graphics-WindowWaylandVulkan.cppm @@ -0,0 +1,45 @@ +module; + +#include +#include +#include +#include +#include +#include + +export module Crafter.Graphics:WindowWaylandVulkan; +import Crafter.Event; +import :WindowWayland; +import Crafter.Component; + +namespace Crafter { + struct SwapchainElement + { + VkCommandBuffer commandBuffer; + VkImage image; + VkImageView imageView; + VkFramebuffer framebuffer; + VkSemaphore startSemaphore; + VkSemaphore endSemaphore; + VkFence fence; + VkFence lastFence; + }; + + export class WindowWaylandVulkan : public WindowWayland { + public: + WindowWaylandVulkan(std::string name, std::uint32_t width, std::uint32_t height); + void Start(); + inline static VkRenderPass renderPass = VK_NULL_HANDLE; + private: + void CreateSwapchain(); + void DestroySwapchain(); + VkSurfaceKHR vulkanSurface = VK_NULL_HANDLE; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + std::vector swapchainElements; + std::uint32_t imageCount; + std::uint32_t currentFrame = 0; + std::uint32_t imageIndex = 0; + VkFormat format = VK_FORMAT_UNDEFINED; + std::thread thread; + }; +} \ No newline at end of file diff --git a/Crafter.Graphics-WindowWaylandWayland.cpp b/Crafter.Graphics-WindowWaylandWayland.cpp new file mode 100644 index 0000000..dbc3e03 --- /dev/null +++ b/Crafter.Graphics-WindowWaylandWayland.cpp @@ -0,0 +1,102 @@ +module; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xdg-shell-client-protocol.h" +#include "wayland-xdg-decoration-unstable-v1-client-protocol.h" +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include "cat.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +module Crafter.Graphics; +import Crafter.Event; +using namespace Crafter; + + +void ScaleBitmapR8G8B8(Pixel* dst, const Pixel* src, std::uint32_t srcWidth, std::uint32_t srcHeight, std::uint32_t dstWidth, std::uint32_t dstHeight) { + for (std::uint32_t y = 0; y < dstHeight; y++) { + std::uint32_t srcY = y * srcHeight / dstHeight; + for (std::uint32_t x = 0; x < dstWidth; x++) { + std::uint32_t srcX = x * srcWidth / dstWidth; + const Pixel* srcPixel = src + (srcY * srcWidth + srcX); + Pixel* dstPixel = dst + (y * dstWidth + x); + dstPixel[0] = srcPixel[0]; + } + } +} + +WindowWaylandWayland::WindowWaylandWayland(std::string name, std::uint32_t width, std::uint32_t height) : WindowWayland(name, width, height) { + +} + +void WindowWaylandWayland::Start() { + thread = std::thread([this](){ + while (open && wl_display_dispatch(display) != -1) { + wl_surface_attach(surface, buffer, 0, 0); + for(UiElement* element : elements.components) { + std::int32_t realX; + std::int32_t realY; + std::int32_t elementWidth; + std::int32_t elementHeight; + if(element->ignoreScaling) { + if(element->useRelativeSize) { + elementWidth = element->relativeWidth*width; + elementHeight = element->relativeHeight*height; + } else { + elementWidth = element->absoluteWidth; + elementHeight = element->absoluteHeight; + } + } else { + if(element->useRelativeSize) { + elementWidth = element->relativeWidth*width*scale; + elementHeight = element->relativeHeight*height*scale; + } else { + elementWidth = element->absoluteWidth*scale; + elementHeight = element->absoluteHeight*scale; + } + } + realX = (element->anchorX*width)-(element->anchorOffsetX*elementWidth); + realY = (element->anchorY*height)-(element->anchorOffsetY*elementHeight); + std::vector scaled(elementWidth*elementHeight); + ScaleBitmapR8G8B8(scaled.data(), element->buffer.data(), element->bufferWidth, element->bufferHeight, elementWidth, elementHeight); + for(std::int32_t x = realX; x-realX < elementWidth; x++) { + for(std::int32_t y = realY; y-realY < elementHeight; y++) { + if(x > 0 && x < width && y > 0 && y < height) { + shm_data[x*width+y] = scaled[(x-realX)*elementWidth+(y-realY)]; + } + } + } + wl_surface_damage(surface, realX, realY, elementWidth, elementHeight); + } + wl_surface_commit(surface); + } + }); +} \ No newline at end of file diff --git a/Crafter.Graphics-WindowWaylandWayland.cppm b/Crafter.Graphics-WindowWaylandWayland.cppm new file mode 100644 index 0000000..d78117c --- /dev/null +++ b/Crafter.Graphics-WindowWaylandWayland.cppm @@ -0,0 +1,20 @@ +module; + +#include +#include +#include + +export module Crafter.Graphics:WindowWaylandWayland; +import Crafter.Event; +import :WindowWayland; +import Crafter.Component; + +export namespace Crafter { + class WindowWaylandWayland : public WindowWayland { + public: + WindowWaylandWayland(std::string name, std::uint32_t width, std::uint32_t height); + void Start(); + private: + std::thread thread; + }; +} \ No newline at end of file diff --git a/Crafter.Graphics.cppm b/Crafter.Graphics.cppm index 48b6846..a51ec86 100644 --- a/Crafter.Graphics.cppm +++ b/Crafter.Graphics.cppm @@ -1,6 +1,11 @@ export module Crafter.Graphics; export import :Window; +export import :WindowWayland; +export import :WindowWaylandWayland; +export import :WindowWaylandVulkan; export import :UiElement; export import :Types; -// export import :UiImage; \ No newline at end of file +export import :VulkanDevice; +export import :VulkanPipeline; +export import :VulkanShader; \ No newline at end of file diff --git a/main.cpp b/main.cpp index 78042b6..c1fde34 100644 --- a/main.cpp +++ b/main.cpp @@ -1,24 +1,40 @@ #include #include +#include +#include import Crafter.Graphics; using namespace Crafter; int main() { - Window window("test", 128, 128); - UiElement test( - 0.5, //anchorX - 0.5, //anchorY - 2, //bufferWidth - 1, //bufferHeight - std::uint32_t(30), //absoluteSizeX - std::uint32_t(30), //absoluteSizeY - 0.5, //anchorOffsetX - 0.5, //anchorOffsetY - 0, //z - false //ignoreScaling - ); - window.scale = 1; - test.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}}; - window.elements.AddComponent(&test); + // WindowWaylandWayland window("test", 128, 128); + // UiElement test( + // 0.5, //anchorX + // 0.5, //anchorY + // 2, //bufferWidth + // 1, //bufferHeight + // std::uint32_t(30), //absoluteSizeX + // std::uint32_t(30), //absoluteSizeY + // 0.5, //anchorOffsetX + // 0.5, //anchorOffsetY + // 0, //z + // false //ignoreScaling + // ); + // window.scale = 1; + // test.buffer = {{255, 0, 0 ,255}, {0, 255, 0 ,255}}; + // window.elements.AddComponent(&test); + // window.Start(); + // while(true) { + + // } + + VulkanDevice::CreateDevice(); + WindowWaylandVulkan window("bruh", 128, 128); + VulkanShader<"test.spirv", "main", VK_SHADER_STAGE_MESH_BIT_EXT>::CreateShader(); + VulkanShader<"test2.spirv", "main", VK_SHADER_STAGE_FRAGMENT_BIT>::CreateShader(); + VulkanPipeline, VulkanShader<"test2.spirv", "main", VK_SHADER_STAGE_FRAGMENT_BIT>>::CreatePipeline(); + window.Start(); + while(true) { + + } } diff --git a/project.json b/project.json index c62a038..3cce0b5 100644 --- a/project.json +++ b/project.json @@ -4,14 +4,26 @@ { "name": "base", "standard": "c++26", - "source_files": ["Crafter.Graphics-Window", "Crafter.Graphics-UiElement"], + "source_files": ["Crafter.Graphics-Window","Crafter.Graphics-WindowWayland","Crafter.Graphics-WindowWaylandWayland", "Crafter.Graphics-UiElement", "Crafter.Graphics-VulkanDevice", "Crafter.Graphics-WindowWaylandVulkan"], "c_files": ["wayland-xdg-decoration-unstable-v1-client-protocol", "xdg-shell-protocol", "shm"], - "module_files": ["Crafter.Graphics-Window", "Crafter.Graphics", "Crafter.Graphics-UiElement", "Crafter.Graphics-Types"], + "module_files": ["Crafter.Graphics-Window","Crafter.Graphics-WindowWayland","Crafter.Graphics-WindowWaylandWayland", "Crafter.Graphics", "Crafter.Graphics-UiElement", "Crafter.Graphics-Types", "Crafter.Graphics-VulkanDevice", "Crafter.Graphics-VulkanPipeline", "Crafter.Graphics-VulkanShader", "Crafter.Graphics-WindowWaylandVulkan"], "build_dir": "./build", "output_dir": "./bin", "type":"library", - "libs": ["wayland-client"], - "flags": ["-Wno-uninitialized"] + "libs": ["wayland-client", "vulkan"], + "flags": ["-Wno-uninitialized"], + "shaders": [ + { + "path":"test.mesh", + "type":13, + "entrypoint":"main" + }, + { + "path":"test2.frag", + "type":4, + "entrypoint":"main" + } + ] }, { "name": "debug", diff --git a/test.mesh b/test.mesh new file mode 100644 index 0000000..5630a21 --- /dev/null +++ b/test.mesh @@ -0,0 +1,16 @@ +#version 450 +#extension GL_EXT_mesh_shader : require + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +layout(triangles, max_vertices = 3, max_primitives = 1) out; + +void main() +{ + uint vertexCount = 3; + uint triangleCount = 1; + SetMeshOutputsEXT(vertexCount, triangleCount); + gl_MeshVerticesEXT[0].gl_Position = vec4(0.5,-0.5, 0, 1); + gl_MeshVerticesEXT[1].gl_Position = vec4(0.5, 0.5, 0, 1); + gl_MeshVerticesEXT[2].gl_Position = vec4(-0.5, 0.5, 0, 1); + gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); +} \ No newline at end of file diff --git a/test.spirv b/test.spirv new file mode 100644 index 0000000..e4ef206 Binary files /dev/null and b/test.spirv differ diff --git a/test2.frag b/test2.frag new file mode 100644 index 0000000..ebc64ff --- /dev/null +++ b/test2.frag @@ -0,0 +1,25 @@ +#version 450 + +/* Copyright (c) 2023-2024 Holochip Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +layout (location = 0) out vec4 color; + +void main() +{ + color = vec4(1.0,0.0,0.0,1.0); +} \ No newline at end of file diff --git a/test2.spirv b/test2.spirv new file mode 100644 index 0000000..eb0fdd2 Binary files /dev/null and b/test2.spirv differ diff --git a/wayland-vulkan-example b/wayland-vulkan-example deleted file mode 160000 index 4d8d086..0000000 --- a/wayland-vulkan-example +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4d8d086f62864257abc98da3ce259298b2e46874