diff --git a/renderer/shaders/pos2color3.frag b/renderer/shaders/pos2color3.frag deleted file mode 100644 index 13009da..0000000 --- a/renderer/shaders/pos2color3.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 fragColor; - -layout(location = 0) out vec4 outColor; - -void main() { - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file diff --git a/renderer/shaders/pos2color3.vert b/renderer/shaders/pos2color3.vert deleted file mode 100644 index 17a265e..0000000 --- a/renderer/shaders/pos2color3.vert +++ /dev/null @@ -1,12 +0,0 @@ -#version 460 - -layout(location = 0) in vec2 inPos; -layout(location = 1) in vec3 inColor; - -layout(location = 0) out vec3 fragColor; - -void main() -{ - gl_Position = vec4(inPos, 0.0, 1.0); - fragColor = inColor; -} diff --git a/renderer/shaders/ui-pane.frag b/renderer/shaders/ui-pane.frag new file mode 100644 index 0000000..e451c4a --- /dev/null +++ b/renderer/shaders/ui-pane.frag @@ -0,0 +1,10 @@ +#version 460 + +layout(location = 0) in vec4 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() +{ + outColor = fragColor; +} diff --git a/renderer/shaders/ui-pane.vert b/renderer/shaders/ui-pane.vert new file mode 100644 index 0000000..1817567 --- /dev/null +++ b/renderer/shaders/ui-pane.vert @@ -0,0 +1,18 @@ +#version 460 + +// vertex geometry data +layout(location = 0) in vec2 inPos; + +// instance data +layout(location = 1) in vec2 inInstancePos; +layout(location = 2) in vec2 inInstanceScale; +layout(location = 3) in vec4 inInstanceColor; + +layout(location = 0) out vec4 fragColor; + +void main() +{ + vec2 pos = inPos * inInstanceScale + inInstancePos; + gl_Position = vec4(pos, 0.0, 1.0); + fragColor = inInstanceColor; +} diff --git a/renderer/src/renderer.c b/renderer/src/renderer.c index 4288617..09355c6 100644 --- a/renderer/src/renderer.c +++ b/renderer/src/renderer.c @@ -46,20 +46,25 @@ typedef struct vulkan_buffer typedef struct mesh { vulkan_buffer vertex_buffer; + vulkan_buffer instance_buffer; vulkan_buffer index_buffer; u64 index_count; + u64 instance_count; } mesh; -typedef struct graphics_pipeline +typedef struct mesh_pipeline { VkPipelineLayout layout; VkPipeline handle; VkPipeline main; VkPipeline wireframe; + + vertex_input_type geometry_type; + vertex_input_type instance_type; hash_table meshes; -} graphics_pipeline; +} mesh_pipeline; #define MAX_FRAMES_IN_FLIGHT 2 // must be a power of two! @@ -110,7 +115,7 @@ typedef struct vulkan_context } single_submit_context; - hash_table graphics_pipelines; + hash_table mesh_pipelines; } vulkan_context; @@ -140,16 +145,6 @@ static const char* validation_layers[] = { "VK_LAYER_KHRONOS_validation" }; #endif static const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; -static VkVertexInputBindingDescription pos2_color3_vertex_input_binding = -{ - .binding = 0, .stride = sizeof(pos2_color3_vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX -}; -static VkVertexInputAttributeDescription pos2_color3_vertex_input_attributes[] = -{ - (VkVertexInputAttributeDescription){ .location = 0, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(pos2_color3_vertex, pos) }, - (VkVertexInputAttributeDescription){ .location = 1, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(pos2_color3_vertex, color) } -}; - // // Window // @@ -1119,7 +1114,7 @@ static void shutdown_frame_data() static u8 init_frame_data() { - trace_log(LOG_INFO, "Initializing Vulkan frame data ..."); + trace_log(LOG_DEBUG, "Initializing Vulkan frame data ..."); VkCommandBuffer command_buffers[MAX_FRAMES_IN_FLIGHT]; if (!allocate_command_buffers(context.command_pool, command_buffers, MAX_FRAMES_IN_FLIGHT)) return 0; @@ -1189,7 +1184,7 @@ u8 init_single_submit_context() return 0; } - trace_log(LOG_DEBUG, "Vulkan upload single-submit successfully created."); + trace_log(LOG_DEBUG, "Vulkan single-submit context successfully created."); signal_for_shutdown(shutdown_single_submit_context); return 1; @@ -1219,7 +1214,7 @@ static u8 end_single_submit_command_recording(VkCommandBuffer command_buffer) }; if (vkQueueSubmit(context.device.graphics_queue, 1, &submit_info, context.single_submit_context.fence) != VK_SUCCESS) { - trace_log(LOG_ERROR, "vkQueueSubmit call failed in end_upload."); + trace_log(LOG_ERROR, "vkQueueSubmit call failed in end_single_submit_command_recording."); return 0; } @@ -1294,6 +1289,14 @@ static u8 init_vulkan_staging_buffer(vulkan_buffer* buffer, VkDeviceSize byte_si return init_vulkan_buffer(buffer, byte_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); } +// uniform buffer, CPU accessible memory +/* +static u8 init_vulkan_uniform_buffer(vulkan_buffer* buffer, VkDeviceSize byte_size) +{ + return init_vulkan_buffer(buffer, byte_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); +} +*/ + // vertex buffer, device memory static u8 init_vulkan_vertex_buffer(vulkan_buffer* buffer, VkDeviceSize byte_size) { @@ -1340,7 +1343,7 @@ static u8 load_vulkan_buffer(vulkan_buffer* buffer, VkDeviceSize offset, VkDevic return 1; } -u8 copy_vulkan_buffer(vulkan_buffer* dst, vulkan_buffer* src, VkDeviceSize dst_offset, VkDeviceSize src_offset, VkDeviceSize byte_size) +static u8 copy_vulkan_buffer(vulkan_buffer* dst, vulkan_buffer* src, VkDeviceSize dst_offset, VkDeviceSize src_offset, VkDeviceSize byte_size) { VkCommandBuffer command_buffer; if (!allocate_command_buffers(context.single_submit_context.command_pool, &command_buffer, 1)) return 0; @@ -1361,29 +1364,64 @@ u8 copy_vulkan_buffer(vulkan_buffer* dst, vulkan_buffer* src, VkDeviceSize dst_o return 1; } -static u8 init_mesh(mesh* msh, const mesh_geometry* geometry) +static u8 init_mesh(mesh* msh, const mesh_geometry* geometry, vertex_input_type geometry_type, const mesh_instance_data* instance_data, vertex_input_type instance_type) { - VkDeviceSize vertices_byte_size = 0; - switch (geometry->vert_type) + VkDeviceSize geometry_vertices_byte_size = 0, instance_data_byte_size = 0; + for (u8 i = 0; i < 2; i++) { - case VERTEX_TYPE_POS2_COLOR3: - vertices_byte_size = geometry->vertex_count * sizeof(pos2_color3_vertex); - break; - default: - trace_log(LOG_ERROR, "Failed to create Vulkan mesh; invalid vertex type."); - return 0; + vertex_input_type t; + VkDeviceSize* ds; + u64 count; + if (i < 1) + { + t = geometry_type; + ds = &geometry_vertices_byte_size; + count = geometry->vertex_count; + } + else + { + t = instance_type; + ds = &instance_data_byte_size; + count = instance_data->instance_count; + } + + switch (t) + { + case VERTEX_INPUT_TYPE_POS2: + *ds = count * sizeof(pos2); + break; + case VERTEX_INPUT_TYPE_POS2_POS2_COLOR4: + *ds = count * sizeof(pos2_pos2_color4); + break; + default: + trace_log(LOG_ERROR, "Failed to create mesh; invalid vertex type (binding = %d).", i); + return 0; + } } VkDeviceSize indices_byte_size = geometry->index_count * sizeof(u32); + if (geometry->vertex_count && geometry->vertices) { vulkan_buffer staging_buffer; - if (!init_vulkan_staging_buffer(&staging_buffer, vertices_byte_size)) return 0; - if (!load_vulkan_buffer(&staging_buffer, 0, vertices_byte_size, 0, geometry->vertices)) return 0; - if (!init_vulkan_vertex_buffer(&msh->vertex_buffer, vertices_byte_size)) return 0; - if (!copy_vulkan_buffer(&msh->vertex_buffer, &staging_buffer, 0, 0, vertices_byte_size)) return 0; + if (!init_vulkan_staging_buffer(&staging_buffer, geometry_vertices_byte_size)) return 0; + if (!load_vulkan_buffer(&staging_buffer, 0, geometry_vertices_byte_size, 0, geometry->vertices)) return 0; + if (!init_vulkan_vertex_buffer(&msh->vertex_buffer, geometry_vertices_byte_size)) return 0; + if (!copy_vulkan_buffer(&msh->vertex_buffer, &staging_buffer, 0, 0, geometry_vertices_byte_size)) return 0; shutdown_vulkan_buffer(&staging_buffer); } + if (instance_data->instance_count && instance_data) + { + vulkan_buffer staging_buffer; + if (!init_vulkan_staging_buffer(&staging_buffer, instance_data_byte_size)) return 0; + if (!load_vulkan_buffer(&staging_buffer, 0, instance_data_byte_size, 0, instance_data->instances)) return 0; + if (!init_vulkan_vertex_buffer(&msh->instance_buffer, instance_data_byte_size)) return 0; + if (!copy_vulkan_buffer(&msh->instance_buffer, &staging_buffer, 0, 0, instance_data_byte_size)) return 0; + shutdown_vulkan_buffer(&staging_buffer); + } + msh->instance_count = instance_data->instance_count; + + if (geometry->index_count && geometry->indices) { vulkan_buffer staging_buffer; if (!init_vulkan_staging_buffer(&staging_buffer, indices_byte_size)) return 0; @@ -1400,6 +1438,7 @@ static u8 init_mesh(mesh* msh, const mesh_geometry* geometry) static void shutdown_mesh(mesh* msh) { shutdown_vulkan_buffer(&msh->index_buffer); + shutdown_vulkan_buffer(&msh->instance_buffer); shutdown_vulkan_buffer(&msh->vertex_buffer); } @@ -1443,7 +1482,7 @@ static void shutdown_shader_module(VkShaderModule module) vkDestroyShaderModule(context.device.logical, module, context.allocator); } -static u8 init_graphics_pipeline(graphics_pipeline* pipeline, const graphics_pipeline_template* template) +static u8 init_mesh_pipeline(mesh_pipeline* pipeline, const mesh_pipeline_template* template) { // device features VkPhysicalDeviceFeatures device_features; @@ -1454,10 +1493,8 @@ static u8 init_graphics_pipeline(graphics_pipeline* pipeline, const graphics_pip VkShaderModule modules[2]; const VkShaderStageFlagBits stage_flag_bits[2] = { VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }; const char* stage_names[2] = { "vert", "frag" }; - const u8 is_stage[2] = { template->is_vertex, template->is_fragment }; for (u8 i = 0; i < 2; i++) { - if (!is_stage[i]) continue; char path[512]; snprintf(path, 512, "renderer/shaders/%s.%s.spv", template->name, stage_names[i]); if (!init_shader_module(modules + i, path)) return 0; @@ -1474,31 +1511,60 @@ static u8 init_graphics_pipeline(graphics_pipeline* pipeline, const graphics_pip stage_infos = darray_pushback(stage_infos, &stage_info, 1); } - + // vertex input - VkPipelineVertexInputStateCreateInfo vertex_input_info = + VkVertexInputBindingDescription* binding_descriptions = create_darray(2, sizeof(VkVertexInputBindingDescription)); + VkVertexInputAttributeDescription* attribute_descriptions = create_darray(8, sizeof(VkVertexInputAttributeDescription)); + VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; + vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + for (u8 i = 0; i < 2; i++) { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 0, - .pVertexBindingDescriptions = NULL, - .vertexAttributeDescriptionCount = 0, - .pVertexAttributeDescriptions = NULL, - .flags = 0, - .pNext = NULL - }; - switch (template->vert_type) - { - case VERTEX_TYPE_POS2_COLOR3: - vertex_input_info.vertexBindingDescriptionCount = 1; - vertex_input_info.pVertexBindingDescriptions = &pos2_color3_vertex_input_binding; - vertex_input_info.vertexAttributeDescriptionCount = 2; - vertex_input_info.pVertexAttributeDescriptions = pos2_color3_vertex_input_attributes; - break; + vertex_input_type t = i < 1 ? template->geometry_type : template->instance_type; + VkVertexInputRate input_rate = i < 1 ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE; + const u8 idx = get_darray_size(attribute_descriptions); + switch (t) + { + case VERTEX_INPUT_TYPE_POS2: + { + u8 idx = get_darray_size(attribute_descriptions); + const VkVertexInputBindingDescription binding = + { + .binding = i, .stride = sizeof(pos2), .inputRate = input_rate + }; + const VkVertexInputAttributeDescription attributes[] = + { + (VkVertexInputAttributeDescription){ .location = idx, .binding = i, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(pos2, pos) } + }; + binding_descriptions = darray_pushback(binding_descriptions, &binding, 1); + attribute_descriptions = darray_pushback(attribute_descriptions, attributes, 1); + } + break; + case VERTEX_INPUT_TYPE_POS2_POS2_COLOR4: + { + const VkVertexInputBindingDescription binding = + { + .binding = i, .stride = sizeof(pos2_pos2_color4), .inputRate = input_rate + }; + const VkVertexInputAttributeDescription attributes[] = + { + (VkVertexInputAttributeDescription){ .location = idx, .binding = i, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(pos2_pos2_color4, posa) }, + (VkVertexInputAttributeDescription){ .location = idx + 1, .binding = i, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(pos2_pos2_color4, posb) }, + (VkVertexInputAttributeDescription){ .location = idx + 2, .binding = i, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(pos2_pos2_color4, color) } + }; + binding_descriptions = darray_pushback(binding_descriptions, &binding, 1); + attribute_descriptions = darray_pushback(attribute_descriptions, attributes, 3); + } + break; - default: - trace_log(LOG_ERROR, "Failed to receive a valid vertex type for graphics pipeline '%s'.", template->name); - return 0; + default: + trace_log(LOG_ERROR, "Failed to receive a valid vertex input type (binding = %d) for mesh pipeline '%s'.", i, template->name); + return 0; + } } + vertex_input_info.vertexBindingDescriptionCount = get_darray_size(binding_descriptions); + vertex_input_info.pVertexBindingDescriptions = binding_descriptions; + vertex_input_info.vertexAttributeDescriptionCount = get_darray_size(attribute_descriptions); + vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions; // input assembly const VkPipelineInputAssemblyStateCreateInfo input_assembly_info = @@ -1602,7 +1668,7 @@ static u8 init_graphics_pipeline(graphics_pipeline* pipeline, const graphics_pip }; if (vkCreatePipelineLayout(context.device.logical, &layout_info, context.allocator, &pipeline->layout) != VK_SUCCESS) { - trace_log(LOG_ERROR, "Failed to create layout for graphics pipeline '%s'", template->name); + trace_log(LOG_ERROR, "Failed to create layout for mesh pipeline '%s'", template->name); return 0; } @@ -1631,7 +1697,7 @@ static u8 init_graphics_pipeline(graphics_pipeline* pipeline, const graphics_pip }; if (vkCreateGraphicsPipelines(context.device.logical, VK_NULL_HANDLE, 1, &pipeline_info, context.allocator, &pipeline->main) != VK_SUCCESS) { - trace_log(LOG_ERROR, "Failed to create main handle graphics pipeline '%s'.", template->name); + trace_log(LOG_ERROR, "Failed to create main handle for mesh pipeline '%s'.", template->name); return 0; } if (device_features.fillModeNonSolid == VK_TRUE) @@ -1645,26 +1711,29 @@ static u8 init_graphics_pipeline(graphics_pipeline* pipeline, const graphics_pip if (vkCreateGraphicsPipelines(context.device.logical, VK_NULL_HANDLE, 1, &wireframe_create_info, context.allocator, &pipeline->wireframe) != VK_SUCCESS) { - trace_log(LOG_ERROR, "Failed to create wireframe handle for graphics pipeline '%s'.", template->name); + trace_log(LOG_ERROR, "Failed to create wireframe handle for mesh pipeline '%s'.", template->name); return 0; } } else pipeline->wireframe = VK_NULL_HANDLE; pipeline->handle = pipeline->main; - trace_log(LOG_DEBUG, "Successfully created graphics pipeline '%s'.", template->name); + trace_log(LOG_DEBUG, "Successfully created mesh pipeline '%s'.", template->name); // clean up + destroy_darray(binding_descriptions); + destroy_darray(attribute_descriptions); destroy_darray(stage_infos); - for (u8 i = 0; i < 2; i++) - if (is_stage[i]) shutdown_shader_module(modules[i]); + for (u8 i = 0; i < 2; i++) shutdown_shader_module(modules[i]); - // mesh hashtable + // meshes + pipeline->geometry_type = template->geometry_type; + pipeline->instance_type = template->instance_type; init_hash_table(&pipeline->meshes, 8, sizeof(mesh), basic_hash); return 1; } -static void shutdown_graphics_pipeline(graphics_pipeline* pipeline) +static void shutdown_mesh_pipeline(mesh_pipeline* pipeline) { // clean up meshes for (u32 i = 0; i < pipeline->meshes.slot_count; i++) @@ -1680,13 +1749,12 @@ static void shutdown_graphics_pipeline(graphics_pipeline* pipeline) vkDestroyPipelineLayout(context.device.logical, pipeline->layout, context.allocator); } -// TO DO: instanced rendering, for now just draw every mesh belonging to a pipeline once -u8 draw_graphics_pipeline(const char* name) +u8 draw_mesh_pipeline(const char* name) { - graphics_pipeline* pipeline = hash_table_lookup(&context.graphics_pipelines, name); + mesh_pipeline* pipeline = hash_table_lookup(&context.mesh_pipelines, name); if (!pipeline) { - trace_log(LOG_ERROR, "Failed to draw graphics pipeline '%s'; lookup failed." , name); + trace_log(LOG_ERROR, "Failed to draw mesh pipeline '%s'; lookup failed." , name); return 0; } @@ -1698,60 +1766,62 @@ u8 draw_graphics_pipeline(const char* name) { mesh* msh = entry->data; - // bind vertex and index buffer - const VkDeviceSize vertex_offsets[] = { 0 }; + // bind vertex, instance, and index buffers + const VkDeviceSize offsets[] = { 0 }; const VkBuffer vertex_buffers[] = { msh->vertex_buffer.handle }; - vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offsets); + const VkBuffer instance_buffers[] = { msh->instance_buffer.handle }; + vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets); + vkCmdBindVertexBuffers(command_buffer, 1, 1, instance_buffers, offsets); vkCmdBindIndexBuffer(command_buffer, msh->index_buffer.handle, 0, VK_INDEX_TYPE_UINT32); - + // draw - vkCmdDrawIndexed(command_buffer, msh->index_count, 1, 0, 0, 0); + vkCmdDrawIndexed(command_buffer, msh->index_count, msh->instance_count, 0, 0, 0); } return 1; } -u8 insert_graphics_pipeline(const graphics_pipeline_template* template) +u8 insert_mesh_pipeline(const mesh_pipeline_template* template) { - graphics_pipeline pipeline; - if (!init_graphics_pipeline(&pipeline, template)) return 0; - if (!hash_table_insert(&context.graphics_pipelines, template->name, &pipeline)) + mesh_pipeline pipeline; + if (!init_mesh_pipeline(&pipeline, template)) return 0; + if (!hash_table_insert(&context.mesh_pipelines, template->name, &pipeline)) { - shutdown_graphics_pipeline(&pipeline); + shutdown_mesh_pipeline(&pipeline); return 0; } return 1; } -u8 remove_graphics_pipeline(const char* name) +u8 remove_mesh_pipeline(const char* name) { - graphics_pipeline* pipeline = hash_table_lookup(&context.graphics_pipelines, name); + mesh_pipeline* pipeline = hash_table_lookup(&context.mesh_pipelines, name); if (!pipeline) { - trace_log(LOG_ERROR, "Failed to remove graphics pipeline '%s'; lookup failed."); + trace_log(LOG_ERROR, "Failed to remove mesh pipeline '%s'; lookup failed."); return 0; } - shutdown_graphics_pipeline(pipeline); - return hash_table_remove(&context.graphics_pipelines, name, NULL); + shutdown_mesh_pipeline(pipeline); + return hash_table_remove(&context.mesh_pipelines, name, NULL); } -u8 change_graphics_pipeline_mode(const char* name, graphics_pipeline_mode mode) +u8 change_mesh_pipeline_mode(const char* name, mesh_pipeline_mode mode) { - graphics_pipeline* pipeline = hash_table_lookup(&context.graphics_pipelines, name); + mesh_pipeline* pipeline = hash_table_lookup(&context.mesh_pipelines, name); if (!pipeline) { - trace_log(LOG_ERROR, "Failed to change mode of graphics pipeline '%s'; lookup failed."); + trace_log(LOG_ERROR, "Failed to change mode of mesh pipeline '%s'; lookup failed."); return 0; } switch (mode) { - case GRAPHICS_PIPELINE_MODE_MAIN: + case MESH_PIPELINE_MODE_MAIN: pipeline->handle = pipeline->main; return 1; - case GRAPHICS_PIPELINE_MODE_WIREFRAME: + case MESH_PIPELINE_MODE_WIREFRAME: if (pipeline->wireframe != VK_NULL_HANDLE) { pipeline->handle = pipeline->wireframe; @@ -1759,24 +1829,24 @@ u8 change_graphics_pipeline_mode(const char* name, graphics_pipeline_mode mode) } else { - trace_log(LOG_ERROR, "Failed to change mode of graphics pipeline '%s'; wireframe mode not supported on this device"); + trace_log(LOG_ERROR, "Failed to change mode of mesh pipeline '%s'; wireframe mode not supported on this device"); return 0; } default: return 0; } } -u8 insert_mesh(const char* pipeline_name, const char* mesh_name, const mesh_geometry* geometry) +u8 insert_mesh(const char* pipeline_name, const char* mesh_name, const mesh_geometry* geometry, const mesh_instance_data* instance_data) { - graphics_pipeline* pipeline = hash_table_lookup(&context.graphics_pipelines, pipeline_name); + mesh_pipeline* pipeline = hash_table_lookup(&context.mesh_pipelines, pipeline_name); if (!pipeline) { - trace_log(LOG_ERROR, "Failed to insert mesh '%s'; graphics pipeline '%s' lookup failed.", mesh_name, pipeline_name); + trace_log(LOG_ERROR, "Failed to insert mesh '%s'; mesh pipeline '%s' lookup failed.", mesh_name, pipeline_name); return 0; } mesh msh; - if (!init_mesh(&msh, geometry)) return 0; + if (!init_mesh(&msh, geometry, pipeline->geometry_type, instance_data, pipeline->instance_type)) return 0; if (!hash_table_insert(&pipeline->meshes, mesh_name, &msh)) { shutdown_mesh(&msh); @@ -1788,13 +1858,12 @@ u8 insert_mesh(const char* pipeline_name, const char* mesh_name, const mesh_geom u8 remove_mesh(const char* pipeline_name, const char* mesh_name) { - graphics_pipeline* pipeline = hash_table_lookup(&context.graphics_pipelines, pipeline_name); + mesh_pipeline* pipeline = hash_table_lookup(&context.mesh_pipelines, pipeline_name); if (!pipeline) { - trace_log(LOG_ERROR, "Failed to remove mesh '%s'; graphics pipeline '%s' lookup failed.", mesh_name, pipeline_name); + trace_log(LOG_ERROR, "Failed to remove mesh '%s'; mesh pipeline '%s' lookup failed.", mesh_name, pipeline_name); return 0; } - mesh* msh = hash_table_lookup(&pipeline->meshes, mesh_name); if (!msh) @@ -1823,7 +1892,7 @@ u8 init_vulkan() if (!init_frame_data()) return 0; if (!init_single_submit_context()) return 0; - init_hash_table(&context.graphics_pipelines, 8, sizeof(graphics_pipeline), basic_hash); + init_hash_table(&context.mesh_pipelines, 8, sizeof(mesh_pipeline), basic_hash); context.image_index = 0; context.current_frame = 0; @@ -1836,13 +1905,13 @@ void shutdown_vulkan() { vkDeviceWaitIdle(context.device.logical); - for (u32 i = 0; i < context.graphics_pipelines.slot_count; i++) - for (hash_table_entry* entry = context.graphics_pipelines.entries[i]; entry != NULL; entry = entry->next) + for (u32 i = 0; i < context.mesh_pipelines.slot_count; i++) + for (hash_table_entry* entry = context.mesh_pipelines.entries[i]; entry != NULL; entry = entry->next) { - graphics_pipeline* pipeline = entry->data; - shutdown_graphics_pipeline(pipeline); + mesh_pipeline* pipeline = entry->data; + shutdown_mesh_pipeline(pipeline); } - shutdown_hash_table(&context.graphics_pipelines); + shutdown_hash_table(&context.mesh_pipelines); typedef void (*fn_ptr)(); while (context.deletion_stack.head != NULL) diff --git a/renderer/src/renderer.h b/renderer/src/renderer.h index 7ffa1f6..433b84a 100644 --- a/renderer/src/renderer.h +++ b/renderer/src/renderer.h @@ -17,43 +17,55 @@ typedef enum { - VERTEX_TYPE_NONE, - VERTEX_TYPE_POS2_COLOR3 + VERTEX_INPUT_TYPE_POS2, + VERTEX_INPUT_TYPE_POS2_POS2_COLOR4 -} vertex_type; +} vertex_input_type; -typedef struct pos2_color3_vertex +typedef struct pos2 { f32 pos[2]; - f32 color[3]; -} pos2_color3_vertex; +} pos2; + +typedef struct pos2_pos2_color4 +{ + f32 posa[2]; + f32 posb[2]; + f32 color[4]; + +} pos2_pos2_color4; typedef struct mesh_geometry { const void* vertices; - vertex_type vert_type; u64 vertex_count; const u32* indices; u64 index_count; } mesh_geometry; -typedef struct graphics_pipeline_template +typedef struct mesh_instance_data +{ + const void* instances; + u64 instance_count; + +} mesh_instance_data; + +typedef struct mesh_pipeline_template { const char* name; - u8 is_vertex; - u8 is_fragment; - vertex_type vert_type; + vertex_input_type geometry_type; + vertex_input_type instance_type; -} graphics_pipeline_template; +} mesh_pipeline_template; typedef enum { - GRAPHICS_PIPELINE_MODE_MAIN, - GRAPHICS_PIPELINE_MODE_WIREFRAME + MESH_PIPELINE_MODE_MAIN, + MESH_PIPELINE_MODE_WIREFRAME -} graphics_pipeline_mode; +} mesh_pipeline_mode; // // @@ -66,11 +78,11 @@ void shutdown_window(); u8 is_window_open(); void poll_window_input(); -u8 draw_graphics_pipeline(const char* name); -u8 insert_graphics_pipeline(const graphics_pipeline_template* template); -u8 remove_graphics_pipeline(const char* name); -u8 change_graphics_pipeline_mode(const char* name, graphics_pipeline_mode mode); -u8 insert_mesh(const char* pipeline_name, const char* mesh_name, const mesh_geometry* geometry); +u8 draw_mesh_pipeline(const char* name); +u8 insert_mesh_pipeline(const mesh_pipeline_template* template); +u8 remove_mesh_pipeline(const char* name); +u8 change_mesh_pipeline_mode(const char* name, mesh_pipeline_mode mode); +u8 insert_mesh(const char* pipeline_name, const char* mesh_name, const mesh_geometry* geometry, const mesh_instance_data* instance_data); u8 remove_mesh(const char* pipeline_name, const char* mesh_name); u8 init_vulkan(); diff --git a/src/main.lisp b/src/main.lisp index 9e7e3d8..c048206 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -28,108 +28,150 @@ You should have received a copy of the GNU General Public License along with Sha (unless (cffi:foreign-library-loaded-p 'libsofrenderer) (cffi:use-foreign-library libsofrenderer)) -(cffi:defcenum vertex-type - :vertex-type-none - :vertex-type-pos2-color3) +(cffi:defcenum vertex-input-type + :vertex-input-type-pos2 + :vertex-input-type-pos2-pos2-color4) -(cffi:defcstruct (%pos2-color3-vertex :class c-pos2-color3-vertex) - (pos :float :count 2) - (color :float :count 3)) +(cffi:defcstruct (%pos2 :class c-pos2) + (pos :float :count 2)) -(defstruct pos2-color3-vertex - (pos (vector 0.0 0.0)) - (color (vector 0.0 0.0 0.0))) +(defstruct pos2 + (pos (vector 0.0 0.0))) -(defmethod cffi:translate-from-foreign (ptr (type c-pos2-color3-vertex)) - (cffi:with-foreign-slots ((pos color) ptr (:struct %pos2-color3-vertex)) - (make-pos2-color3-vertex +(defmethod cffi:translate-from-foreign (ptr (type c-pos2)) + (cffi:with-foreign-slots ((pos) ptr (:struct %pos2)) + (make-pos2 :pos (vector (cffi:mem-aref pos :float 0) - (cffi:mem-aref pos :float 1)) + (cffi:mem-aref pos :float 1))))) + +(defmethod cffi:expand-from-foreign (ptr (type c-pos2)) + `(cffi:with-foreign-slots ((pos) ,ptr (:struct %pos2)) + (make-pos2 + :pos (vector (cffi:mem-aref pos :float 0) + (cffi:mem-aref pos :float 1))))) + +(defmethod cffi:translate-into-foreign-memory (value (type c-pos2) ptr) + (cffi:with-foreign-slots ((pos) ptr (:struct %pos2)) + (setf + (cffi:mem-aref pos :float 0) (aref (pos2-pos value) 0) + (cffi:mem-aref pos :float 1) (aref (pos2-pos value) 1)))) + +(defmethod cffi:expand-into-foreign-memory (value (type c-pos2) ptr) + `(cffi:with-foreign-slots ((pos color) ,ptr (:struct %pos2)) + (setf + (cffi:mem-aref pos :float 0) (aref (pos2-pos ,value) 0) + (cffi:mem-aref pos :float 1) (aref (pos2-pos ,value) 1)))) + +(cffi:defcstruct (%pos2-pos2-color4 :class c-pos2-pos2-color4) + (posa :float :count 2) + (posb :float :count 2) + (color :float :count 4)) + +(defstruct pos2-pos2-color4 + (posa (vector 0.0 0.0)) + (posb (vector 0.0 0.0)) + (color (vector 0.0 0.0 0.0 0.0))) + +(defmethod cffi:translate-from-foreign (ptr (type c-pos2-pos2-color4)) + (cffi:with-foreign-slots ((posa posb color) ptr (:struct %pos2-pos2-color4)) + (make-pos2-pos2-color4 + :posa (vector (cffi:mem-aref posa :float 0) + (cffi:mem-aref posa :float 1)) + :posb (vector (cffi:mem-aref posb :float 0) + (cffi:mem-aref posb :float 1)) :color (vector (cffi:mem-aref color :float 0) (cffi:mem-aref color :float 1) - (cffi:mem-aref color :float 2))))) + (cffi:mem-aref color :float 2) + (cffi:mem-aref color :float 4))))) -(defmethod cffi:expand-from-foreign (ptr (type c-pos2-color3-vertex)) - `(cffi:with-foreign-slots ((pos color) ,ptr (:struct %pos2-color3-vertex)) - (make-pos2-color3-vertex - :pos (vector (cffi:mem-aref pos :float 0) - (cffi:mem-aref pos :float 1)) +(defmethod cffi:expand-from-foreign (ptr (type c-pos2-pos2-color4)) + `(cffi:with-foreign-slots ((posa posb color) ,ptr (:struct %pos2-pos2-color4)) + (make-pos2-pos2-color4 + :posa (vector (cffi:mem-aref posa :float 0) + (cffi:mem-aref posa :float 1)) + :posb (vector (cffi:mem-aref posb :float 0) + (cffi:mem-aref posb :float 1)) :color (vector (cffi:mem-aref color :float 0) (cffi:mem-aref color :float 1) - (cffi:mem-aref color :float 2))))) - -(defmethod cffi:translate-into-foreign-memory (value (type c-pos2-color3-vertex) ptr) - (cffi:with-foreign-slots ((pos color) ptr (:struct %pos2-color3-vertex)) + (cffi:mem-aref color :float 2) + (cffi:mem-aref color :float 4))))) + +(defmethod cffi:translate-into-foreign-memory (value (type c-pos2-pos2-color4) ptr) + (cffi:with-foreign-slots ((posa posb color) ptr (:struct %pos2-pos2-color4)) (setf - (cffi:mem-aref pos :float 0) (aref (pos2-color3-vertex-pos value) 0) - (cffi:mem-aref pos :float 1) (aref (pos2-color3-vertex-pos value) 1) - (cffi:mem-aref color :float 0) (aref (pos2-color3-vertex-color value) 0) - (cffi:mem-aref color :float 1) (aref (pos2-color3-vertex-color value) 1) - (cffi:mem-aref color :float 2) (aref (pos2-color3-vertex-color value) 2)))) + (cffi:mem-aref posa :float 0) (aref (pos2-pos2-color4-posa value) 0) + (cffi:mem-aref posa :float 1) (aref (pos2-pos2-color4-posa value) 1) + (cffi:mem-aref posb :float 0) (aref (pos2-pos2-color4-posb value) 0) + (cffi:mem-aref posb :float 1) (aref (pos2-pos2-color4-posb value) 1) + (cffi:mem-aref color :float 0) (aref (pos2-pos2-color4-color value) 0) + (cffi:mem-aref color :float 1) (aref (pos2-pos2-color4-color value) 1) + (cffi:mem-aref color :float 2) (aref (pos2-pos2-color4-color value) 2) + (cffi:mem-aref color :float 3) (aref (pos2-pos2-color4-color value) 3)))) -(defmethod cffi:expand-into-foreign-memory (value (type c-pos2-color3-vertex) ptr) - `(cffi:with-foreign-slots ((pos color) ,ptr (:struct %pos2-color3-vertex)) - (setf - (cffi:mem-aref pos :float 0) (aref (pos2-color3-vertex-pos ,value) 0) - (cffi:mem-aref pos :float 1) (aref (pos2-color3-vertex-pos ,value) 1) - (cffi:mem-aref color :float 0) (aref (pos2-color3-vertex-color ,value) 0) - (cffi:mem-aref color :float 1) (aref (pos2-color3-vertex-color ,value) 1) - (cffi:mem-aref color :float 2) (aref (pos2-color3-vertex-color ,value) 2)))) +(defmethod cffi:expand-into-foreign-memory (value (type c-pos2-pos2-color4) ptr) + `(cffi:with-foreign-slots ((posa posb color) ,ptr (:struct %pos2-pos2-color4)) + (setf + + (cffi:mem-aref posa :float 0) (aref (pos2-pos2-color4-posa ,value) 0) + (cffi:mem-aref posa :float 1) (aref (pos2-pos2-color4-posa ,value) 1) + (cffi:mem-aref posb :float 0) (aref (pos2-pos2-color4-posb ,value) 0) + (cffi:mem-aref posb :float 1) (aref (pos2-pos2-color4-posb ,value) 1) + (cffi:mem-aref color :float 0) (aref (pos2-pos2-color4-color ,value) 0) + (cffi:mem-aref color :float 1) (aref (pos2-pos2-color4-color ,value) 1) + (cffi:mem-aref color :float 2) (aref (pos2-pos2-color4-color ,value) 2) + (cffi:mem-aref color :float 3) (aref (pos2-pos2-color4-color ,value) 3)))) (cffi:defcstruct %mesh-geometry (vertices :pointer) - (vert-type vertex-type) (vertex-count :uint64) (indices (:pointer :uint32)) (index-count :uint64)) -(cffi:defcstruct (%graphics-pipeline-template :class c-graphics-pipeline-template) +(cffi:defcstruct %mesh-instance-data + (instances :pointer) + (instance-count :uint64)) + +(cffi:defcstruct (%mesh-pipeline-template :class c-mesh-pipeline-template) (name :string) - (vertex? :bool) - (fragment? :bool) - (vert-type vertex-type)) + (geometry-type vertex-input-type) + (instance-type vertex-input-type)) -(defstruct graphics-pipeline-template +(defstruct mesh-pipeline-template (name "" :type string) - (vertex? t :type boolean) - (fragment? t :type boolean) - (vert-type 0 :type integer)) + (geometry-type 0 :type integer) + (instance-type 0 :type integer)) -(defmethod cffi:translate-from-foreign (ptr (type c-graphics-pipeline-template)) - (cffi:with-foreign-slots ((name vertex? fragment? vert-type) ptr (:struct %graphics-pipeline-template)) - (make-graphics-pipeline-template +(defmethod cffi:translate-from-foreign (ptr (type c-mesh-pipeline-template)) + (cffi:with-foreign-slots ((name geometry-type instance-type) ptr (:struct %mesh-pipeline-template)) + (make-mesh-pipeline-template :name name - :vertex? vertex? - :fragment? fragment? - :vert-type vert-type))) + :geometry-type geometry-type + :instance-type instance-type))) -(defmethod cffi:expand-from-foreign (ptr (type c-graphics-pipeline-template)) - `(cffi:with-foreign-slots ((name vertex? fragment? vert-type) ,ptr (:struct %graphics-pipeline-template)) - (make-graphics-pipeline-template +(defmethod cffi:expand-from-foreign (ptr (type c-mesh-pipeline-template)) + `(cffi:with-foreign-slots ((name geometry-type instance-type) ,ptr (:struct %mesh-pipeline-template)) + (make-mesh-pipeline-template :name name - :vertex? vertex? - :fragment? fragment? - :vert-type vert-type))) + :geometry-type geometry-type + :instance-type instance-type))) -(defmethod cffi:translate-into-foreign-memory (value (type c-graphics-pipeline-template) ptr) - (cffi:with-foreign-slots ((name vertex? fragment? vert-type) ptr (:struct %graphics-pipeline-template)) +(defmethod cffi:translate-into-foreign-memory (value (type c-mesh-pipeline-template) ptr) + (cffi:with-foreign-slots ((name geometry-type instance-type) ptr (:struct %mesh-pipeline-template)) (setf - name (graphics-pipeline-template-name value) - vertex? (graphics-pipeline-template-vertex? value) - fragment? (graphics-pipeline-template-fragment? value) - vert-type (graphics-pipeline-template-vert-type value)))) + name (mesh-pipeline-template-name value) + geometry-type (mesh-pipeline-template-geometry-type value) + instance-type (mesh-pipeline-template-instance-type value)))) -(defmethod cffi:expand-into-foreign-memory (value (type c-graphics-pipeline-template) ptr) - `(cffi:with-foreign-slots ((name vertex? fragment? vert-type) ,ptr (:struct %graphics-pipeline-template)) +(defmethod cffi:expand-into-foreign-memory (value (type c-mesh-pipeline-template) ptr) + `(cffi:with-foreign-slots ((name geometry-type instance-type) ,ptr (:struct %mesh-pipeline-template)) (setf - name (graphics-pipeline-template-name ,value) - vertex? (graphics-pipeline-template-vertex? ,value) - fragment? (graphics-pipeline-template-fragment? ,value) - vert-type (graphics-pipeline-template-vert-type ,value)))) + name (mesh-pipeline-template-name ,value) + geometry-type (mesh-pipeline-template-geometry-type ,value) + instance-type (mesh-pipeline-template-instance-type ,value)))) -(cffi:defcenum graphics-pipeline-mode - :graphics-pipeline-mode-main - :graphics-pipeline-mode-wireframe) +(cffi:defcenum mesh-pipeline-mode + :mesh-pipeline-mode-main + :mesh-pipeline-mode-wireframe) (cffi:defcfun ("init_window" init-window) :boolean (name :string) @@ -142,29 +184,30 @@ You should have received a copy of the GNU General Public License along with Sha (cffi:defcfun ("poll_window_input" poll-window-input) :void) -(cffi:defcfun ("draw_graphics_pipeline" draw-graphics-pipeline) :boolean +(cffi:defcfun ("draw_mesh_pipeline" draw-mesh-pipeline) :boolean (name :string)) -(cffi:defcfun ("insert_graphics_pipeline" %insert-graphics-pipeline) :boolean - (template (:pointer (:struct %graphics-pipeline-template)))) +(cffi:defcfun ("insert_mesh_pipeline" %insert-mesh-pipeline) :boolean + (template (:pointer (:struct %mesh-pipeline-template)))) -(defun insert-graphics-pipeline (name vert-type &key (vertex? t) (fragment? t)) - (let ((template (make-graphics-pipeline-template :name name :vertex? vertex? :fragment? fragment? :vert-type vert-type))) - (cffi:with-foreign-object (ptr '(:struct %graphics-pipeline-template)) - (setf (cffi:mem-aref ptr '(:struct %graphics-pipeline-template)) template) - (%insert-graphics-pipeline ptr)))) +(defun insert-mesh-pipeline (name geometry-type instance-type) + (let ((template (make-mesh-pipeline-template :name name :geometry-type geometry-type :instance-type instance-type))) + (cffi:with-foreign-object (ptr '(:struct %mesh-pipeline-template)) + (setf (cffi:mem-aref ptr '(:struct %mesh-pipeline-template)) template) + (%insert-mesh-pipeline ptr)))) -(cffi:defcfun ("remove_graphics_pipeline" remove-graphics-pipeline) :boolean +(cffi:defcfun ("remove_mesh_pipeline" remove-mesh-pipeline) :boolean (name :string)) -(cffi:defcfun ("change_graphics_pipeline_mode" change-graphics-pipeline-mode) :boolean +(cffi:defcfun ("change_mesh_pipeline_mode" change-mesh-pipeline-mode) :boolean (name :string) - (mode graphics-pipeline-mode)) + (mode mesh-pipeline-mode)) (cffi:defcfun ("insert_mesh" insert-mesh) :boolean (pipeline-name :string) (mesh-name :string) - (geometry (:pointer (:struct %mesh-geometry)))) + (geometry (:pointer (:struct %mesh-geometry))) + (instance-data (:pointer (:struct %mesh-instance-data)))) (cffi:defcfun ("remove_mesh" remove-mesh) :boolean (pipeline-name :string) @@ -191,18 +234,17 @@ You should have received a copy of the GNU General Public License along with Sha (when (init-window name width height) (when (init-vulkan) t))) - (insert-graphics-pipeline "pos2color3" (cffi:foreign-enum-value 'vertex-type :vertex-type-pos2-color3)) + (insert-mesh-pipeline + "ui-pane" + (cffi:foreign-enum-value 'vertex-input-type :vertex-input-type-pos2) + (cffi:foreign-enum-value 'vertex-input-type :vertex-input-type-pos2-pos2-color4)) - (cffi:with-foreign-object (quad-vertices '(:struct %pos2-color3-vertex) 4) + (cffi:with-foreign-object (quad-vertices '(:struct %pos2) 4) (setf - (cffi:mem-aref quad-vertices '(:struct %pos2-color3-vertex) 0) - (make-pos2-color3-vertex :pos (vector -0.5 -0.5) :color (vector 1.0 0.0 0.0)) - (cffi:mem-aref quad-vertices '(:struct %pos2-color3-vertex) 1) - (make-pos2-color3-vertex :pos (vector 0.5 0.5) :color (vector 0.0 0.0 1.0)) - (cffi:mem-aref quad-vertices '(:struct %pos2-color3-vertex) 2) - (make-pos2-color3-vertex :pos (vector 0.5 -0.5) :color (vector 0.0 1.0 0.0)) - (cffi:mem-aref quad-vertices '(:struct %pos2-color3-vertex) 3) - (make-pos2-color3-vertex :pos (vector -0.5 0.5) :color (vector 1.0 1.0 1.0))) + (cffi:mem-aref quad-vertices '(:struct %pos2) 0) (make-pos2 :pos (vector 0.0 0.0)) + (cffi:mem-aref quad-vertices '(:struct %pos2) 1) (make-pos2 :pos (vector 1.0 1.0)) + (cffi:mem-aref quad-vertices '(:struct %pos2) 2) (make-pos2 :pos (vector 1.0 0.0)) + (cffi:mem-aref quad-vertices '(:struct %pos2) 3) (make-pos2 :pos (vector 0.0 1.0))) (cffi:with-foreign-object (quad-indices :uint32 6) (setf (cffi:mem-aref quad-indices :uint32 0) 0 @@ -212,14 +254,24 @@ You should have received a copy of the GNU General Public License along with Sha (cffi:mem-aref quad-indices :uint32 4) 3 (cffi:mem-aref quad-indices :uint32 5) 1) (cffi:with-foreign-object (geometry '(:struct %mesh-geometry)) - (cffi:with-foreign-slots ((vertices vert-type vertex-count indices index-count) geometry (:struct %mesh-geometry)) + (cffi:with-foreign-slots ((vertices vertex-count indices index-count) geometry (:struct %mesh-geometry)) (setf vertices quad-vertices - vert-type (cffi:foreign-enum-value 'vertex-type :vertex-type-pos2-color3) vertex-count 4 indices quad-indices index-count 6) - (insert-mesh "pos2color3" "quad" geometry)))))) + (cffi:with-foreign-object (quad-instances '(:struct %pos2-pos2-color4) 2) + (setf + (cffi:mem-aref quad-instances '(:struct %pos2-pos2-color4) 0) + (make-pos2-pos2-color4 :posa (vector -0.5 0.5) :posb (vector 0.25 0.25) :color (vector 0.7 0.0 0.0 1.0)) + (cffi:mem-aref quad-instances '(:struct %pos2-pos2-color4) 1) + (make-pos2-pos2-color4 :posa (vector 0.5 0.5) :posb (vector 0.4 0.4) :color (vector 0.0 0.5 0.5 0.6))) + (cffi:with-foreign-object (instance-data '(:struct %mesh-instance-data)) + (cffi:with-foreign-slots ((instances instance-count) instance-data (:struct %mesh-instance-data)) + (setf + instances quad-instances + instance-count 2) + (insert-mesh "ui-pane" "quad" geometry instance-data))))))))) (defun shutdown-game () (shutdown-vulkan) @@ -230,7 +282,7 @@ You should have received a copy of the GNU General Public License along with Sha (defun render-game (l) (declare (ignore l)) (when (begin-render-frame) - (when (draw-graphics-pipeline "pos2color3") + (when (draw-mesh-pipeline "ui-pane") (when (end-render-frame) t)))) ;; Only compile this ONCE!