diff --git a/client/Makefile b/client/Makefile index d2cd396..eb95d75 100644 --- a/client/Makefile +++ b/client/Makefile @@ -2,7 +2,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) CFLAGS = -I $(ROOT_DIR)/include -I/usr/local/include -O0 -g -Wall -Wextra LDFLAGS = -lfreetype -lz -lglfw -lvulkan -ldl -Xlinker -rpath -Xlinker /opt/homebrew/lib -SOURCES = src/main.c src/draw.c src/ui.c src/gpu.c lib/spng.c lib/vma.cpp +SOURCES = src/main.c src/draw.c src/ui.c src/gpu.c src/hex.c lib/spng.c lib/vma.cpp OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) VERT_SPV = $(addsuffix .vert.spv, $(basename $(wildcard shader/*.vert))) FRAG_SPV = $(addsuffix .frag.spv, $(basename $(wildcard shader/*.frag))) diff --git a/client/include/gpu.h b/client/include/gpu.h index 322b87a..06f8ea7 100644 --- a/client/include/gpu.h +++ b/client/include/gpu.h @@ -2,6 +2,7 @@ #define GPU_H #define VK_USE_PLATFORM_MACOS_MVK +#include "vulkan/vk_enum_string_helper.h" #include "vulkan/vulkan_core.h" #include "vk_mem_alloc.h" @@ -28,28 +29,43 @@ #define WINDOW_MIN_WIDTH 800 #define WINDOW_MIN_HEIGHT 600 +#define VK_RESULT(x) {\ + result = x;\ + if(result != VK_SUCCESS) {\ + fprintf(stderr, "%s failed with %s\n", #x, string_VkResult(result));\ + return x;\ + }\ +} + +typedef struct ComputePipelineStruct { + VkPipelineLayout layout; + VkPipeline pipeline; +} ComputePipeline; + +typedef struct GraphicsPipelineStruct { + VkPipelineLayout layout; + VkPipeline pipeline; +} GraphicsPipeline; + +typedef struct DrawCommandStruct { + uint32_t vertex_count; + uint32_t instance_count; + uint32_t first_vertex; + uint32_t first_instance; +} DrawCommand; + +typedef struct DispatchCommandStruct { + uint32_t x; + uint32_t y; + uint32_t z; +} DispatchCommand; + typedef struct GPUQueueStruct { VkQueue handle; uint32_t family; uint32_t index; } GPUQueue; - -VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool); - -VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, GPUQueue transfer_queue); - -void command_copy_buffer(VkCommandBuffer command_buffer, VkBuffer src, VkBuffer dst, VkDeviceSize src_offset, VkDeviceSize dst_offset, VkDeviceSize size); - -VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, GPUQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags); - -#define VK_RESULT(x) {\ - result = x;\ - if(result != VK_SUCCESS) {\ - return x;\ - }\ -} - typedef struct SwapchainDetailsStruct { VkSurfaceCapabilitiesKHR capabilities; @@ -180,4 +196,39 @@ VkResult add_transfers( VkDeviceSize size, RenderContext* gpu); +VkCommandBuffer command_begin_single( + VkDevice device, + VkCommandPool transfer_pool); + +VkResult command_end_single( + VkDevice device, + VkCommandBuffer command_buffer, + VkCommandPool transfer_pool, + GPUQueue transfer_queue); + +void command_copy_buffer( + VkCommandBuffer command_buffer, + VkBuffer src, + VkBuffer dst, + VkDeviceSize src_offset, + VkDeviceSize dst_offset, + VkDeviceSize size); + +VkResult command_transition_image_layout( + VkDevice device, + VkCommandPool transfer_pool, + GPUQueue transfer_queue, + VkImageLayout old_layout, + VkImageLayout new_layout, + VkImage image, + VkAccessFlags src_mask, + VkAccessFlags dst_mask, + VkPipelineStageFlags source, + VkPipelineStageFlags dest, + uint32_t source_family, + uint32_t dest_family, + VkImageAspectFlags aspect_flags); + +VkShaderModule load_shader_file(const char* path, VkDevice device); + #endif diff --git a/client/include/hex.h b/client/include/hex.h new file mode 100644 index 0000000..4fa8e75 --- /dev/null +++ b/client/include/hex.h @@ -0,0 +1,17 @@ +#ifndef HEX_H +#define HEX_H + +#include "gpu.h" + +typedef struct HexPushStruct { + VkDeviceAddress context; + VkDeviceAddress world; +} HexPush; + +VkResult create_hex_pipeline( + VkDevice device, + VkRenderPass render_pass, + GraphicsPipeline* graphics, + ComputePipeline* compute); + +#endif diff --git a/client/include/ui.h b/client/include/ui.h index afb6fb2..b80ed15 100644 --- a/client/include/ui.h +++ b/client/include/ui.h @@ -15,29 +15,6 @@ #define ANCHOR_BOTTOM_RIGHT 3 #define ANCHOR_CENTER 4 -typedef struct ComputePipelineStruct { - VkPipelineLayout layout; - VkPipeline pipeline; -} ComputePipeline; - -typedef struct GraphicsPipelineStruct { - VkPipelineLayout layout; - VkPipeline pipeline; -} GraphicsPipeline; - -typedef struct DrawCommandStruct { - uint32_t vertex_count; - uint32_t instance_count; - uint32_t first_vertex; - uint32_t first_instance; -} DrawCommand; - -typedef struct DispatchCommandStruct { - uint32_t x; - uint32_t y; - uint32_t z; -} DispatchCommand; - typedef struct UIPushConstantStruct { VkDeviceAddress layer; float time; diff --git a/client/src/gpu.c b/client/src/gpu.c index 375678f..b3ab65c 100644 --- a/client/src/gpu.c +++ b/client/src/gpu.c @@ -42,8 +42,6 @@ VkFormat depth_formats[] = { }; uint32_t depth_format_count = sizeof(depth_formats) / sizeof(VkFormat); - - void glfw_error(int error, const char* description) { fprintf(stderr, "GLFW_ERR: 0x%02x - %s\n", error, description); } @@ -63,6 +61,49 @@ GLFWwindow* init_window() { return window; } +VkShaderModule load_shader_file(const char* path, VkDevice device) { + FILE* file; + file = fopen(path, "rb"); + if(file == 0) { + return VK_NULL_HANDLE; + } + + int result = fseek(file, 0, SEEK_END); + if(result != 0) { + return VK_NULL_HANDLE; + } + + long buffer_size = ftell(file); + + result = fseek(file, 0, SEEK_SET); + if(result != 0) { + return VK_NULL_HANDLE; + } + + char * buffer = malloc(buffer_size); + if(buffer == 0) { + return VK_NULL_HANDLE; + } + + size_t read = fread(buffer, 1, buffer_size, file); + + VkShaderModuleCreateInfo shader_info = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = read, + .pCode = (uint32_t*)buffer, + }; + + VkShaderModule shader; + result = vkCreateShaderModule(device, &shader_info, 0, &shader); + free(buffer); + if(result != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + return shader; +} + + bool check_validation_layers(const char ** layers, uint32_t num_layers) { uint32_t layer_count; VkResult result; diff --git a/client/src/hex.c b/client/src/hex.c new file mode 100644 index 0000000..803088f --- /dev/null +++ b/client/src/hex.c @@ -0,0 +1,201 @@ +#include "hex.h" +#include "gpu.h" +#include "vulkan/vulkan_core.h" + +VkResult create_hex_pipeline( + VkDevice device, + VkRenderPass render_pass, + GraphicsPipeline* graphics, + ComputePipeline* compute) { + VkResult result; + + // Compute Pipeline + + VkShaderModule compute_shader = load_shader_file("shader/hex.comp.spv", device); + if(compute_shader == VK_NULL_HANDLE) { + return VK_ERROR_UNKNOWN; + } + + VkPipelineShaderStageCreateInfo compute_shader_stage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .pName = "main", + .module = compute_shader, + }; + + VkPushConstantRange push_constant = { + .size = sizeof(HexPush), + .offset = 0, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT, + }; + + VkPipelineLayoutCreateInfo compute_layout_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pPushConstantRanges = &push_constant, + .pushConstantRangeCount = 1, + }; + + VK_RESULT(vkCreatePipelineLayout(device, &compute_layout_info, NULL, &compute->layout)); + + VkComputePipelineCreateInfo compute_pipeline_info = { + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .stage = compute_shader_stage, + .layout = compute->layout, + }; + + VK_RESULT(vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_info, NULL, &compute->pipeline)); + + // Graphics Pipeline + + VkShaderModule vert_shader = load_shader_file("shader/hex.vert.spv", device); + VkShaderModule frag_shader = load_shader_file("shader/hex.frag.spv", device); + + VkPipelineShaderStageCreateInfo graphics_stages[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .pName = "main", + .module = vert_shader, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .pName = "main", + .module = frag_shader, + }, + }; + + VkPipelineLayoutCreateInfo graphics_layout_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pPushConstantRanges = &push_constant, + .pushConstantRangeCount = 1, + }; + + VK_RESULT(vkCreatePipelineLayout(device, &graphics_layout_info, NULL, &graphics->layout)); + + VkPipelineVertexInputStateCreateInfo vertex_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + }; + + VkPipelineInputAssemblyStateCreateInfo input_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + + VkViewport viewport = { + .x = 0.0f, + .y = 0.0f, + .width = (float)(100), + .height = (float)(100), + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + + VkRect2D scissor = { + .offset = { + .x = 0, + .y = 0, + }, + .extent = { + .width = 100, + .height = 100, + }, + }; + + VkPipelineViewportStateCreateInfo viewport_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor, + }; + + VkPipelineRasterizationStateCreateInfo raster_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .depthClampEnable = VK_TRUE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, + }; + + VkPipelineColorBlendAttachmentState blend_attachments = { + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, + }; + + VkPipelineColorBlendStateCreateInfo blend_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &blend_attachments, + }; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + VkPipelineDynamicStateCreateInfo dynamic_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState), + .pDynamicStates = dynamic_states, + }; + + VkPipelineMultisampleStateCreateInfo multisample_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .minSampleShading = 1.0f, + .pSampleMask = 0, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + VkPipelineDepthStencilStateCreateInfo depth_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = VK_COMPARE_OP_LESS, + .depthBoundsTestEnable = VK_TRUE, + .minDepthBounds = 0.0f, + .maxDepthBounds = 1.0f, + .stencilTestEnable = VK_FALSE, + }; + + VkGraphicsPipelineCreateInfo graphics_pipeline_info = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .layout = graphics->layout, + .stageCount = sizeof(graphics_stages)/sizeof(VkPipelineShaderStageCreateInfo), + .pStages = graphics_stages, + .pVertexInputState = &vertex_info, + .pInputAssemblyState = &input_info, + .pViewportState = &viewport_info, + .pRasterizationState = &raster_info, + .pColorBlendState = &blend_info, + .pDynamicState = &dynamic_info, + .pMultisampleState = &multisample_info, + .pDepthStencilState = &depth_info, + .renderPass = render_pass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = -1, + }; + + VK_RESULT(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &graphics_pipeline_info, NULL, &graphics->pipeline)); + + return VK_SUCCESS; +} diff --git a/client/src/main.c b/client/src/main.c index 842879f..7ef74f9 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -2,6 +2,7 @@ #include "ui.h" #include "gpu.h" #include "draw.h" +#include "hex.h" #include "arpa/inet.h" #include "vk_mem_alloc.h" @@ -28,6 +29,10 @@ void* network_thread(void* data) { VkResult main_thread(ClientContext* context) { VkResult result; + GraphicsPipeline graphics; + ComputePipeline compute; + VK_RESULT(create_hex_pipeline(context->render.device, context->render.render_pass, &graphics, &compute)); + GPUString strings[] = { { .pos = {0, 32}, diff --git a/client/src/ui.c b/client/src/ui.c index 17e5ecd..63233e4 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -11,48 +11,6 @@ #include "spng.h" #include -VkShaderModule load_shader_file(const char* path, VkDevice device) { - FILE* file; - file = fopen(path, "rb"); - if(file == 0) { - return VK_NULL_HANDLE; - } - - int result = fseek(file, 0, SEEK_END); - if(result != 0) { - return VK_NULL_HANDLE; - } - - long buffer_size = ftell(file); - - result = fseek(file, 0, SEEK_SET); - if(result != 0) { - return VK_NULL_HANDLE; - } - - char * buffer = malloc(buffer_size); - if(buffer == 0) { - return VK_NULL_HANDLE; - } - - size_t read = fread(buffer, 1, buffer_size, file); - - VkShaderModuleCreateInfo shader_info = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = read, - .pCode = (uint32_t*)buffer, - }; - - VkShaderModule shader; - result = vkCreateShaderModule(device, &shader_info, 0, &shader); - free(buffer); - if(result != VK_SUCCESS) { - return VK_NULL_HANDLE; - } - - return shader; -} - VkResult create_ui_pipeline( VkDevice device, VkRenderPass render_pass, @@ -124,15 +82,8 @@ VkResult create_ui_pipeline( }, }; - VkVertexInputBindingDescription bindings[] = {}; - VkVertexInputAttributeDescription attributes[] = {}; - VkPipelineVertexInputStateCreateInfo input_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pVertexBindingDescriptions = bindings, - .vertexBindingDescriptionCount = sizeof(bindings)/sizeof(VkVertexInputBindingDescription), - .pVertexAttributeDescriptions = attributes, - .vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), }; VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {