From 80cdd4f2b1c2a3355926b59a85e14100b3daa7b7 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 27 Mar 2024 21:05:04 +1100 Subject: simple shaders for testing --- assets/shaders/triangle.vert | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 assets/shaders/triangle.vert (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert new file mode 100644 index 0000000..0518c62 --- /dev/null +++ b/assets/shaders/triangle.vert @@ -0,0 +1,8 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 in_position; + +void main() { + gl_Position = vec4(in_position, 1.0); +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 765a6d0f36a9f16189efc449bde815a6c0938584 Mon Sep 17 00:00:00 2001 From: omnisci3nce <17525998+omnisci3nce@users.noreply.github.com> Date: Fri, 29 Mar 2024 21:11:02 +1100 Subject: triangle --- assets/shaders/triangle.frag | 4 +- assets/shaders/triangle.vert | 3 + src/core.c | 4 +- src/platform/file.c | 50 ++-- src/renderer/backends/backend_vulkan.c | 439 +++++++++++++++++++++++++++++++-- src/renderer/render.c | 4 +- xmake.lua | 1 + 7 files changed, 458 insertions(+), 47 deletions(-) (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag index d26e5c4..dd6d148 100644 --- a/assets/shaders/triangle.frag +++ b/assets/shaders/triangle.frag @@ -1,8 +1,10 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +layout(location = 0) in vec3 in_position; + layout(location = 0) out vec4 out_colour; void main() { - out_colour = vec4(1.0); + out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index 0518c62..3dcf931 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -3,6 +3,9 @@ layout(location = 0) in vec3 in_position; +layout(location = 0) out vec3 out_position; + void main() { gl_Position = vec4(in_position, 1.0); + out_position = in_position; } \ No newline at end of file diff --git a/src/core.c b/src/core.c index 024b2d7..a0dc3b6 100644 --- a/src/core.c +++ b/src/core.c @@ -7,8 +7,8 @@ #include "render_types.h" #include "threadpool.h" -#define SCR_WIDTH 1080 -#define SCR_HEIGHT 800 +#define SCR_WIDTH 2160 +#define SCR_HEIGHT 1080 core* core_bringup() { INFO("Initiate Core bringup"); diff --git a/src/platform/file.c b/src/platform/file.c index ac5014d..6030620 100644 --- a/src/platform/file.c +++ b/src/platform/file.c @@ -63,31 +63,31 @@ str8_opt str8_from_file(arena *a, str8 path) { } FileData load_spv_file(const char *path) { - FILE *f = fopen(path, "rb"); - if (f == NULL) { - perror("Error opening file"); - return (FileData){NULL, 0}; - } - - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - rewind(f); - - char *data = (char *)malloc(fsize); - if (data == NULL) { - perror("Memory allocation failed"); - fclose(f); - return (FileData){NULL, 0}; - } - - size_t bytesRead = fread(data, 1, fsize, f); - if (bytesRead < fsize) { - perror("Failed to read the entire file"); - free(data); - fclose(f); - return (FileData){NULL, 0}; - } + FILE *f = fopen(path, "rb"); + if (f == NULL) { + perror("Error opening file"); + return (FileData){ NULL, 0 }; + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + char *data = (char *)malloc(fsize); + if (data == NULL) { + perror("Memory allocation failed"); fclose(f); - return (FileData){data, bytesRead}; + return (FileData){ NULL, 0 }; + } + + size_t bytesRead = fread(data, 1, fsize, f); + if (bytesRead < fsize) { + perror("Failed to read the entire file"); + free(data); + fclose(f); + return (FileData){ NULL, 0 }; + } + + fclose(f); + return (FileData){ data, bytesRead }; } \ No newline at end of file diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index c57da9d..ac64429 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,12 +1,16 @@ +#define CDEBUG +#define CEL_PLATFORM_LINUX +// ^ Temporary + +#include +#include #include #include #include -#include "colours.h" -#define CEL_PLATFORM_LINUX -#include #include #include #include +#include "colours.h" #include "str.h" #include "darray.h" @@ -21,8 +25,8 @@ #include -#define SCR_WIDTH 1080 -#define SCR_HEIGHT 800 +#define SCR_WIDTH 2160 +#define SCR_HEIGHT 1080 #if CEL_REND_BACKEND_VULKAN @@ -137,6 +141,16 @@ typedef struct vulkan_shader { vulkan_pipeline pipeline; } vulkan_shader; +typedef struct vulkan_buffer { + u64 total_size; + VkBuffer handle; + VkBufferUsageFlagBits usage; + bool is_locked; + VkDeviceMemory memory; + i32 memory_index; + u32 memory_property_flags; +} vulkan_buffer; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -146,6 +160,11 @@ typedef struct vulkan_context { u32 framebuffer_height; vulkan_swapchain swapchain; vulkan_renderpass main_renderpass; + vulkan_buffer object_vertex_buffer; + vulkan_buffer object_index_buffer; + u64 geometry_vertex_offset; + u64 geometry_index_offset; + vulkan_command_buffer_darray* gfx_command_buffers; VkSemaphore* image_available_semaphores; @@ -168,25 +187,188 @@ typedef struct vulkan_context { static vulkan_context context; +static i32 find_memory_index(vulkan_context* context, u32 type_filter, u32 property_flags) { + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(context->device.physical_device, &memory_properties); + + for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) { + // Check each memory type to see if its bit is set to 1. + if (type_filter & (1 << i) && + (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) { + return i; + } + } + + WARN("Unable to find suitable memory type!"); + return -1; +} + /** @brief Internal backend state */ typedef struct vulkan_state { } vulkan_state; +typedef struct vertex_pos { + vec3 pos; +} vertex_pos; + // pipeline stuff -bool vulkan_graphics_pipeline_create( - vulkan_context* context, - vulkan_renderpass* renderpass, - u32 attribute_count, - VkVertexInputAttributeDescription* attributes, - // ... https://youtu.be/OmPmftW7Kjg?si=qn_777v_ppHKzswK&t=568 -) { +bool vulkan_graphics_pipeline_create(vulkan_context* context, vulkan_renderpass* renderpass, + u32 attribute_count, + VkVertexInputAttributeDescription* attributes, + u32 descriptor_set_layout_count, + VkDescriptorSetLayout* descriptor_set_layouts, u32 stage_count, + VkPipelineShaderStageCreateInfo* stages, VkViewport viewport, + VkRect2D scissor, bool is_wireframe, + vulkan_pipeline* out_pipeline) { + VkPipelineViewportStateCreateInfo viewport_state = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO + }; + viewport_state.viewportCount = 1; + viewport_state.pViewports = &viewport; + viewport_state.scissorCount = 1; + viewport_state.pScissors = &scissor; + + // Rasterizer + VkPipelineRasterizationStateCreateInfo rasterizer_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO + }; + rasterizer_create_info.depthClampEnable = VK_FALSE; + rasterizer_create_info.rasterizerDiscardEnable = VK_FALSE; + rasterizer_create_info.polygonMode = is_wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL; + rasterizer_create_info.lineWidth = 1.0f; + rasterizer_create_info.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer_create_info.depthBiasEnable = VK_FALSE; + rasterizer_create_info.depthBiasConstantFactor = 0.0; + rasterizer_create_info.depthBiasClamp = 0.0; + rasterizer_create_info.depthBiasSlopeFactor = 0.0; + + // Multisampling + VkPipelineMultisampleStateCreateInfo ms_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO + }; + ms_create_info.sampleShadingEnable = VK_FALSE; + ms_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + ms_create_info.minSampleShading = 1.0; + ms_create_info.pSampleMask = 0; + ms_create_info.alphaToCoverageEnable = VK_FALSE; + ms_create_info.alphaToOneEnable = VK_FALSE; + + // Depth and stencil testing + VkPipelineDepthStencilStateCreateInfo depth_stencil = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + }; + depth_stencil.depthTestEnable = VK_TRUE; + depth_stencil.depthWriteEnable = VK_TRUE; + depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthBoundsTestEnable = VK_FALSE; + depth_stencil.stencilTestEnable = VK_FALSE; + depth_stencil.pNext = 0; + + VkPipelineColorBlendAttachmentState color_blend_attachment_state; + color_blend_attachment_state.blendEnable = VK_TRUE; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo color_blend = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO + }; + color_blend.logicOpEnable = VK_FALSE; + color_blend.logicOp = VK_LOGIC_OP_COPY; + color_blend.attachmentCount = 1; + color_blend.pAttachments = &color_blend_attachment_state; + + const u32 dynamic_state_count = 3; + VkDynamicState dynamic_states[3] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + }; + + VkPipelineDynamicStateCreateInfo dynamic_state = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO + }; + dynamic_state.dynamicStateCount = dynamic_state_count; + dynamic_state.pDynamicStates = dynamic_states; + + // Vertex input + VkVertexInputBindingDescription binding_desc; + binding_desc.binding = 0; + binding_desc.stride = sizeof(vertex_pos); + binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + VkPipelineVertexInputStateCreateInfo vertex_input_info = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO + }; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_desc; + vertex_input_info.vertexAttributeDescriptionCount = attribute_count; + vertex_input_info.pVertexAttributeDescriptions = attributes; + + VkPipelineInputAssemblyStateCreateInfo input_assembly = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO + }; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly.primitiveRestartEnable = VK_FALSE; + + VkPipelineLayoutCreateInfo pipeline_layout_create_info = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO + }; + pipeline_layout_create_info.setLayoutCount = descriptor_set_layout_count; + pipeline_layout_create_info.pSetLayouts = descriptor_set_layouts; + + vkCreatePipelineLayout(context->device.logical_device, &pipeline_layout_create_info, + context->allocator, &out_pipeline->layout); + + VkGraphicsPipelineCreateInfo pipeline_create_info = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO + }; + pipeline_create_info.stageCount = stage_count; + pipeline_create_info.pStages = stages; + pipeline_create_info.pVertexInputState = &vertex_input_info; + pipeline_create_info.pInputAssemblyState = &input_assembly; + + pipeline_create_info.pViewportState = &viewport_state; + pipeline_create_info.pRasterizationState = &rasterizer_create_info; + pipeline_create_info.pMultisampleState = &ms_create_info; + pipeline_create_info.pDepthStencilState = &depth_stencil; + pipeline_create_info.pColorBlendState = &color_blend; + pipeline_create_info.pDynamicState = &dynamic_state; + pipeline_create_info.pTessellationState = 0; + + pipeline_create_info.layout = out_pipeline->layout; + + pipeline_create_info.renderPass = renderpass->handle; + pipeline_create_info.subpass = 0; + pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_create_info.basePipelineIndex = -1; + + VkResult result = + vkCreateGraphicsPipelines(context->device.logical_device, VK_NULL_HANDLE, 1, + &pipeline_create_info, context->allocator, &out_pipeline->handle); + if (result != VK_SUCCESS) { + FATAL("graphics pipeline creation failed. its fked mate"); + ERROR_EXIT("Doomed"); + } + + return true; +} + +void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindPoint bind_point, + vulkan_pipeline* pipeline) { + vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle); } bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, VkShaderStageFlagBits flag, u32 stage_index, vulkan_shader_stage* shader_stages) { - memset(&shader_stages[stage_index].create_info, 0, sizeof(VkShaderModuleCreateInfo)); memset(&shader_stages[stage_index].stage_create_info, 0, sizeof(VkPipelineShaderStageCreateInfo)); @@ -225,9 +407,63 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha create_shader_module(context, stage_filenames[i], stage_type_strs[i], stage_types[i], i, out_shader->stages); } + + // TODO: descriptors + + // Pipeline creation + VkViewport viewport; + viewport.x = 0; + viewport.y = (f32)context->framebuffer_height; + viewport.width = (f32)context->framebuffer_width; + viewport.height = -(f32)context->framebuffer_height; + viewport.minDepth = 0.0; + viewport.maxDepth = 1.0; + + VkRect2D scissor; + scissor.offset.x = scissor.offset.y = 0; + scissor.extent.width = context->framebuffer_width; + scissor.extent.height = context->framebuffer_height; + + // Attributes + u32 offset = 0; + const i32 attribute_count = 1; + VkVertexInputAttributeDescription attribute_descs[1]; + // Position + VkFormat formats[1] = { VK_FORMAT_R32G32B32_SFLOAT }; + + u64 sizes[1] = { sizeof(vec3) }; + + for (u32 i = 0; i < attribute_count; i++) { + attribute_descs[i].binding = 0; + attribute_descs[i].location = i; + attribute_descs[i].format = formats[i]; + attribute_descs[i].offset = offset; + offset += sizes[i]; + } + + // TODO: Descriptor set + + // Stages + VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT]; + memset(stage_create_infos, 0, sizeof(stage_create_infos)); + for (u32 i = 0; i < SHADER_STAGE_COUNT; i++) { + stage_create_infos[i].sType = out_shader->stages[i].stage_create_info.sType; + stage_create_infos[i] = out_shader->stages[i].stage_create_info; + } + + vulkan_graphics_pipeline_create(context, &context->main_renderpass, attribute_count, + attribute_descs, 0, 0, SHADER_STAGE_COUNT, stage_create_infos, + viewport, scissor, false, &out_shader->pipeline); + INFO("Graphics pipeline created!"); + + return true; } void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} -void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) {} +void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) { + u32 image_index = context->image_index; + vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index], + VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); +} bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; @@ -482,6 +718,68 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // TODO: vulkan_image_destroy +void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { + vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); +} + +bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, + u32 memory_property_flags, bool bind_on_create, + vulkan_buffer* out_buffer) { + memset(out_buffer, 0, sizeof(vulkan_buffer)); + out_buffer->total_size = size; + out_buffer->usage = usage; + out_buffer->memory_property_flags = memory_property_flags; + + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = usage; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, + &out_buffer->handle); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); + out_buffer->memory_index = + find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); + + // Allocate + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; + + vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, + &out_buffer->memory); + + if (bind_on_create) { + vulkan_buffer_bind(context, out_buffer, 0); + } + + return true; +} + +// lock and unlock? + +void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, + u64 size, u32 flags) { + void* data; + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); + return data; +} +void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, + u32 flags, const void* data) { + void* data_ptr = 0; + VK_CHECK(vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); + memcpy(data_ptr, data, size); + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +// TODO: destroy + void vulkan_framebuffer_create(vulkan_context* context, vulkan_renderpass* renderpass, u32 width, u32 height, u32 attachment_count, VkImageView* attachments, vulkan_framebuffer* out_framebuffer) { @@ -577,6 +875,24 @@ void vulkan_command_buffer_end_oneshot(vulkan_context* context, VkCommandPool po vulkan_command_buffer_free(context, pool, command_buffer); } +void vulkan_buffer_copy_to(vulkan_context* context, VkCommandPool pool, VkFence fence, + VkQueue queue, VkBuffer source, u64 source_offset, VkBuffer dest, + u64 dest_offset, u64 size) { + vkQueueWaitIdle(queue); + + vulkan_command_buffer temp_cmd_buf; + vulkan_command_buffer_allocate_and_begin_oneshot(context, pool, &temp_cmd_buf); + + VkBufferCopy copy_region; + copy_region.srcOffset = source_offset; + copy_region.dstOffset = dest_offset; + copy_region.size = size; + + vkCmdCopyBuffer(temp_cmd_buf.handle, source, dest, 1, ©_region); + + vulkan_command_buffer_end_oneshot(context, pool, &temp_cmd_buf, queue); +} + void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, vulkan_swapchain* out_swapchain) { VkExtent2D swapchain_extent = { width, height }; @@ -837,6 +1153,33 @@ void vulkan_renderpass_end(vulkan_command_buffer* command_buffer, vulkan_renderp command_buffer->state = COMMAND_BUFFER_STATE_RECORDING; } +bool create_buffers(vulkan_context* context) { + VkMemoryPropertyFlagBits mem_prop_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + const u64 vertex_buffer_size = sizeof(vertex_pos) * 1024 * 1024; + if (!vulkan_buffer_create(context, vertex_buffer_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + mem_prop_flags, true, &context->object_vertex_buffer)) { + ERROR("couldnt create vertex buffer"); + return false; + } + + context->geometry_vertex_offset = 0; + + const u64 index1_buffer_size = sizeof(u32) * 1024 * 1024; + if (!vulkan_buffer_create(context, index1_buffer_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + mem_prop_flags, true, &context->object_index_buffer)) { + ERROR("couldnt create vertex buffer"); + return false; + } + context->geometry_index_offset = 0; + + return true; +} + void create_command_buffers(renderer* ren) { if (!context.gfx_command_buffers) { context.gfx_command_buffers = vulkan_command_buffer_darray_new(context.swapchain.image_count); @@ -848,6 +1191,25 @@ void create_command_buffers(renderer* ren) { } } +void upload_data_range(vulkan_context* context, VkCommandPool pool, VkFence fence, VkQueue queue, + vulkan_buffer* buffer, u64 offset, u64 size, void* data) { + VkBufferUsageFlags flags = + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + vulkan_buffer staging; + vulkan_buffer_create(context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, flags, true, &staging); + TRACE("HERE"); + // load data into staging buffer + printf("Size: %ld\n", size); + vulkan_buffer_load_data(context, &staging, 0, size, 0, data); + TRACE("here"); + + // copy + vulkan_buffer_copy_to(context, pool, fence, queue, staging.handle, 0, buffer->handle, offset, + size); + + vkDestroyBuffer(context->device.logical_device, staging.handle, context->allocator); +} + void regenerate_framebuffers(renderer* ren, vulkan_swapchain* swapchain, vulkan_renderpass* renderpass) { for (u32 i = 0; i < swapchain->image_count; i++) { @@ -929,7 +1291,7 @@ bool gfx_backend_init(renderer* ren) { plat_get_required_extension_names(required_extensions); -#if defined(DEBUG) +#if defined(CDEBUG) cstr_darray_push(required_extensions, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); DEBUG("Required extensions:"); @@ -944,7 +1306,7 @@ bool gfx_backend_init(renderer* ren) { // Validation layers create_info.enabledLayerCount = 0; create_info.ppEnabledLayerNames = 0; -#if defined(DEBUG) +#if defined(CDEBUG) INFO("Validation layers enabled"); cstr_darray* desired_validation_layers = cstr_darray_new(1); cstr_darray_push(desired_validation_layers, "VK_LAYER_KHRONOS_validation"); @@ -984,7 +1346,7 @@ bool gfx_backend_init(renderer* ren) { } // Debugger -#if defined(DEBUG) +#if defined(CDEBUG) DEBUG("Creating Vulkan debugger") u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; @@ -1064,6 +1426,36 @@ bool gfx_backend_init(renderer* ren) { vulkan_object_shader_create(&context, &context.object_shader); INFO("Compiled shader modules") + create_buffers(&context); + INFO("Created buffers"); + + // TODO: temporary test code + const u32 vert_count = 4; + vertex_pos verts[4] = { 0 }; + + verts[0].pos.x = 0.0; + verts[0].pos.y = -0.5; + + verts[1].pos.x = 0.5; + verts[1].pos.y = 0.5; + + verts[2].pos.x = 0.0; + verts[2].pos.y = 0.5; + + verts[3].pos.x = 0.5; + verts[3].pos.y = -0.5; + + const u32 index_count = 6; + u32 indices[6] = { 0, 1, 2, 0, 3, 1 }; + + upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + &context.object_vertex_buffer, 0, sizeof(vertex_pos) * vert_count, verts); + TRACE("Uploaded vertex data"); + upload_data_range(&context, context.device.gfx_command_pool, 0, context.device.graphics_queue, + &context.object_index_buffer, 0, sizeof(u32) * index_count, indices); + TRACE("Uploaded index data"); + // --- End test code + INFO("Vulkan renderer initialisation succeeded"); return true; } @@ -1121,6 +1513,19 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { vulkan_renderpass_begin(command_buffer, &context.main_renderpass, context.swapchain.framebuffers->data[context.image_index].handle); + + // TODO: temp test code + vulkan_object_shader_use(&context, &context.object_shader); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + (VkDeviceSize*)offsets); + + vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, + VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); + // --- End temp test code } void backend_end_frame(renderer* ren, f32 delta_time) { diff --git a/src/renderer/render.c b/src/renderer/render.c index 45762d4..de1a775 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -17,8 +17,8 @@ // FIXME: get rid of these and store dynamic screen realestate // in renderer -#define SCR_WIDTH 1080 -#define SCR_HEIGHT 800 +#define SCR_WIDTH 2160 +#define SCR_HEIGHT 1080 material DEFAULT_MATERIAL = { 0 }; diff --git a/xmake.lua b/xmake.lua index 5457ccb..3005713 100644 --- a/xmake.lua +++ b/xmake.lua @@ -14,6 +14,7 @@ add_cflags("-Wall", "-Wextra", "-Wundef", "-Wdouble-promotion") if is_mode("debug") then add_cflags("-g") -- Add debug symbols in debug mode + add_defines("CDEBUG") elseif is_mode("release") then add_defines("CRELEASE") end -- cgit v1.2.3-70-g09d2 From c5176c9c001c7d32cc2c658e09be8a4b5237685b Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 10:52:15 +1100 Subject: chore format lint --- assets/shaders/triangle.frag | 2 +- assets/shaders/triangle.vert | 4 ++-- src/core.c | 4 ++-- src/platform/file.h | 6 +++--- src/std/containers/darray.h | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag index dd6d148..8455d04 100644 --- a/assets/shaders/triangle.frag +++ b/assets/shaders/triangle.frag @@ -6,5 +6,5 @@ layout(location = 0) in vec3 in_position; layout(location = 0) out vec4 out_colour; void main() { - out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); + out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index 3dcf931..e34112d 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -6,6 +6,6 @@ layout(location = 0) in vec3 in_position; layout(location = 0) out vec3 out_position; void main() { - gl_Position = vec4(in_position, 1.0); - out_position = in_position; + gl_Position = vec4(in_position, 1.0); + out_position = in_position; } \ No newline at end of file diff --git a/src/core.c b/src/core.c index a0dc3b6..4b3bd1b 100644 --- a/src/core.c +++ b/src/core.c @@ -7,8 +7,8 @@ #include "render_types.h" #include "threadpool.h" -#define SCR_WIDTH 2160 -#define SCR_HEIGHT 1080 +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 core* core_bringup() { INFO("Initiate Core bringup"); diff --git a/src/platform/file.h b/src/platform/file.h index 83d1317..a8aa8ea 100644 --- a/src/platform/file.h +++ b/src/platform/file.h @@ -19,8 +19,8 @@ const char* string_from_file(const char* path); str8_opt str8_from_file(arena* a, str8 path); typedef struct { - char *data; - size_t size; + char* data; + size_t size; } FileData; -FileData load_spv_file(const char *path); \ No newline at end of file +FileData load_spv_file(const char* path); \ No newline at end of file diff --git a/src/std/containers/darray.h b/src/std/containers/darray.h index 45d92e2..b15d269 100644 --- a/src/std/containers/darray.h +++ b/src/std/containers/darray.h @@ -6,7 +6,8 @@ // COPIED FROM KITC WITH SOME MINOR ADJUSTMENTS /* TODO: - - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a new function?) + - a 'find' function that takes a predicate (maybe wrap with a macro so we dont have to define a + new function?) */ #ifndef KITC_TYPED_ARRAY_H -- cgit v1.2.3-70-g09d2 From f07e87a86e386ba0f65c5a1e962b6a90cfe26ced Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 30 Mar 2024 17:42:15 +1100 Subject: uniform with descriptor set. fix image_index being 4 when expoected to be 3 --- assets/shaders/object.frag | 6 + assets/shaders/object.vert | 12 ++ assets/shaders/triangle.frag | 10 -- assets/shaders/triangle.vert | 11 -- examples/main_loop/ex_main_loop.c | 1 + src/renderer/backends/backend_vulkan.c | 293 +++++++++++++++++++++++---------- src/renderer/render_backend.h | 1 + xmake.lua | 10 +- 8 files changed, 233 insertions(+), 111 deletions(-) create mode 100644 assets/shaders/object.frag create mode 100644 assets/shaders/object.vert delete mode 100644 assets/shaders/triangle.frag delete mode 100644 assets/shaders/triangle.vert (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/object.frag b/assets/shaders/object.frag new file mode 100644 index 0000000..44c1eb3 --- /dev/null +++ b/assets/shaders/object.frag @@ -0,0 +1,6 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec4 out_colour; + +void main() { out_colour = vec4(1.0); } \ No newline at end of file diff --git a/assets/shaders/object.vert b/assets/shaders/object.vert new file mode 100644 index 0000000..9aaefed --- /dev/null +++ b/assets/shaders/object.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 in_position; + +layout(set = 0, binding = 0) uniform global_object_uniform { + mat4 projection; + mat4 view; +} +global_ubo; + +void main() { gl_Position = global_ubo.projection * global_ubo.view * vec4(in_position, 1.0); } \ No newline at end of file diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag deleted file mode 100644 index 8455d04..0000000 --- a/assets/shaders/triangle.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) in vec3 in_position; - -layout(location = 0) out vec4 out_colour; - -void main() { - out_colour = vec4(in_position.r + 0.5, in_position.g + 0.5, in_position.b + 0.5, 1.0); -} \ No newline at end of file diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert deleted file mode 100644 index e34112d..0000000 --- a/assets/shaders/triangle.vert +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(location = 0) in vec3 in_position; - -layout(location = 0) out vec3 out_position; - -void main() { - gl_Position = vec4(in_position, 1.0); - out_position = in_position; -} \ No newline at end of file diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 728290f..9a6f98c 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -1,6 +1,7 @@ #include #include "core.h" +#include "maths.h" #include "render.h" #include "render_backend.h" diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 3e5137e..759da2f 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -133,13 +133,11 @@ typedef struct vulkan_pipeline { VkPipelineLayout layout; } vulkan_pipeline; -#define SHADER_STAGE_COUNT 2 - -typedef struct vulkan_shader { - // vertex, fragment - vulkan_shader_stage stages[SHADER_STAGE_COUNT]; - vulkan_pipeline pipeline; -} vulkan_shader; +typedef struct global_object_uniform { + mat4 projection; // 64 bytes + mat4 view; // 64 bytes + f32 padding[32]; +} global_object_uniform; typedef struct vulkan_buffer { u64 total_size; @@ -151,6 +149,24 @@ typedef struct vulkan_buffer { u32 memory_property_flags; } vulkan_buffer; +#define SHADER_STAGE_COUNT 2 + +typedef struct vulkan_shader { + // vertex, fragment + vulkan_shader_stage stages[SHADER_STAGE_COUNT]; + vulkan_pipeline pipeline; + + // descriptors + VkDescriptorPool descriptor_pool; + VkDescriptorSetLayout descriptor_set_layout; + VkDescriptorSet descriptor_sets[3]; // one for each in-flight frame + + vulkan_buffer global_uniforms_buffer; + + // Data that's global for all objects drawn + global_object_uniform global_ubo; +} vulkan_shader; + typedef struct vulkan_context { VkInstance instance; VkAllocationCallbacks* allocator; @@ -366,6 +382,69 @@ void vulkan_pipeline_bind(vulkan_command_buffer* command_buffer, VkPipelineBindP vkCmdBindPipeline(command_buffer->handle, bind_point, pipeline->handle); } +void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { + vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); +} + +bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, + u32 memory_property_flags, bool bind_on_create, + vulkan_buffer* out_buffer) { + memset(out_buffer, 0, sizeof(vulkan_buffer)); + out_buffer->total_size = size; + out_buffer->usage = usage; + out_buffer->memory_property_flags = memory_property_flags; + + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = usage; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, + &out_buffer->handle); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); + out_buffer->memory_index = + find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); + + // Allocate + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; + + vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, + &out_buffer->memory); + + if (bind_on_create) { + vulkan_buffer_bind(context, out_buffer, 0); + } + + return true; +} + +// lock and unlock? + +void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, + u64 size, u32 flags) { + void* data; + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); + return data; +} +void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, + u32 flags, const void* data) { + void* data_ptr = 0; + VK_CHECK( + vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); + memcpy(data_ptr, data, size); + vkUnmapMemory(context->device.logical_device, buffer->memory); +} + +// TODO: destroy + bool create_shader_module(vulkan_context* context, const char* filename, const char* type_str, VkShaderStageFlagBits flag, u32 stage_index, vulkan_shader_stage* shader_stages) { @@ -398,8 +477,8 @@ bool create_shader_module(vulkan_context* context, const char* filename, const c bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_shader) { char stage_type_strs[SHADER_STAGE_COUNT][5] = { "vert", "frag" }; - char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/triangle.vert.spv", - "build/linux/x86_64/debug/triangle.frag.spv" }; + char stage_filenames[SHADER_STAGE_COUNT][256] = { "build/linux/x86_64/debug/object.vert.spv", + "build/linux/x86_64/debug/object.frag.spv" }; VkShaderStageFlagBits stage_types[SHADER_STAGE_COUNT] = { VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT }; for (u8 i = 0; i < SHADER_STAGE_COUNT; i++) { @@ -408,7 +487,34 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha out_shader->stages); } - // TODO: descriptors + // descriptors + VkDescriptorSetLayoutBinding global_ubo_layout_binding; + global_ubo_layout_binding.binding = 0; + global_ubo_layout_binding.descriptorCount = 1; + global_ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + global_ubo_layout_binding.pImmutableSamplers = 0; + global_ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo global_layout_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO + }; + global_layout_info.bindingCount = 1; + global_layout_info.pBindings = &global_ubo_layout_binding; + + VK_CHECK(vkCreateDescriptorSetLayout(context->device.logical_device, &global_layout_info, + context->allocator, &out_shader->descriptor_set_layout)); + + VkDescriptorPoolSize global_pool_size; + global_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + global_pool_size.descriptorCount = 3; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &global_pool_size; + pool_info.maxSets = 3; + + VK_CHECK(vkCreateDescriptorPool(context->device.logical_device, &pool_info, context->allocator, + &out_shader->descriptor_pool)); // Pipeline creation VkViewport viewport; @@ -441,7 +547,8 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha offset += sizes[i]; } - // TODO: Descriptor set + // Descriptor set layouts + VkDescriptorSetLayout layouts[1] = { out_shader->descriptor_set_layout }; // Stages VkPipelineShaderStageCreateInfo stage_create_infos[SHADER_STAGE_COUNT]; @@ -451,11 +558,35 @@ bool vulkan_object_shader_create(vulkan_context* context, vulkan_shader* out_sha stage_create_infos[i] = out_shader->stages[i].stage_create_info; } - vulkan_graphics_pipeline_create(context, &context->main_renderpass, attribute_count, - attribute_descs, 0, 0, SHADER_STAGE_COUNT, stage_create_infos, - viewport, scissor, false, &out_shader->pipeline); + vulkan_graphics_pipeline_create( + context, &context->main_renderpass, attribute_count, attribute_descs, 1, layouts, + SHADER_STAGE_COUNT, stage_create_infos, viewport, scissor, false, &out_shader->pipeline); INFO("Graphics pipeline created!"); + // Uniform buffer + if (!vulkan_buffer_create(context, sizeof(global_object_uniform), + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + true, &out_shader->global_uniforms_buffer)) { + ERROR("Couldnt create uniforms buffer"); + return false; + } + + VkDescriptorSetLayout global_layouts[3] = { + out_shader->descriptor_set_layout, + out_shader->descriptor_set_layout, + out_shader->descriptor_set_layout, + }; + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = out_shader->descriptor_pool; + alloc_info.descriptorSetCount = 3; + alloc_info.pSetLayouts = global_layouts; + VK_CHECK(vkAllocateDescriptorSets(context->device.logical_device, &alloc_info, + out_shader->descriptor_sets)); + return true; } void vulkan_object_shader_destroy(vulkan_context* context, vulkan_shader* shader) {} @@ -464,6 +595,36 @@ void vulkan_object_shader_use(vulkan_context* context, vulkan_shader* shader) { vulkan_pipeline_bind(&context->gfx_command_buffers->data[image_index], VK_PIPELINE_BIND_POINT_GRAPHICS, &shader->pipeline); } +void vulkan_object_shader_update_global_state(vulkan_context* context, vulkan_shader* shader) { + u32 image_index = context->image_index; + VkCommandBuffer cmd_buffer = context->gfx_command_buffers->data[image_index].handle; + VkDescriptorSet global_descriptors = shader->descriptor_sets[image_index]; + + vkCmdBindDescriptorSets(cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shader->pipeline.layout, 0, + 1, &global_descriptors, 0, 0); + + u32 range = sizeof(global_object_uniform); + u64 offset = 0; + + // copy data to buffer + vulkan_buffer_load_data(context, &shader->global_uniforms_buffer, offset, range, 0, + &shader->global_ubo); + + VkDescriptorBufferInfo buffer_info; + buffer_info.buffer = shader->global_uniforms_buffer.handle; + buffer_info.offset = offset; + buffer_info.range = range; + + VkWriteDescriptorSet descriptor_write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descriptor_write.dstSet = shader->descriptor_sets[image_index]; + descriptor_write.dstBinding = 0; + descriptor_write.dstArrayElement = 0; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.descriptorCount = 1; + descriptor_write.pBufferInfo = &buffer_info; + + vkUpdateDescriptorSets(context->device.logical_device, 1, &descriptor_write, 0, 0); +} bool select_physical_device(vulkan_context* ctx) { u32 physical_device_count = 0; @@ -734,69 +895,6 @@ void vulkan_image_create(vulkan_context* context, VkImageType image_type, u32 wi // TODO: vulkan_image_destroy -void vulkan_buffer_bind(vulkan_context* context, vulkan_buffer* buffer, u64 offset) { - vkBindBufferMemory(context->device.logical_device, buffer->handle, buffer->memory, offset); -} - -bool vulkan_buffer_create(vulkan_context* context, u64 size, VkBufferUsageFlagBits usage, - u32 memory_property_flags, bool bind_on_create, - vulkan_buffer* out_buffer) { - memset(out_buffer, 0, sizeof(vulkan_buffer)); - out_buffer->total_size = size; - out_buffer->usage = usage; - out_buffer->memory_property_flags = memory_property_flags; - - VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - buffer_info.size = size; - buffer_info.usage = usage; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(context->device.logical_device, &buffer_info, context->allocator, - &out_buffer->handle); - - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(context->device.logical_device, out_buffer->handle, &requirements); - out_buffer->memory_index = - find_memory_index(context, requirements.memoryTypeBits, out_buffer->memory_property_flags); - - // Allocate - VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - allocate_info.allocationSize = requirements.size; - allocate_info.memoryTypeIndex = (u32)out_buffer->memory_index; - - vkAllocateMemory(context->device.logical_device, &allocate_info, context->allocator, - &out_buffer->memory); - - if (bind_on_create) { - vulkan_buffer_bind(context, out_buffer, 0); - } - - return true; -} - -// lock and unlock? - -void* vulkan_buffer_lock_memory(vulkan_context* context, vulkan_buffer* buffer, u64 offset, - u64 size, u32 flags) { - void* data; - vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data); - return data; -} -void* vulkan_buffer_unlock_memory(vulkan_context* context, vulkan_buffer* buffer) { - vkUnmapMemory(context->device.logical_device, buffer->memory); -} - -void vulkan_buffer_load_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset, u64 size, - u32 flags, const void* data) { - void* data_ptr = 0; - VK_CHECK( - vkMapMemory(context->device.logical_device, buffer->memory, offset, size, flags, &data_ptr)); - memcpy(data_ptr, data, size); - vkUnmapMemory(context->device.logical_device, buffer->memory); -} - -// TODO: destroy - void vulkan_framebuffer_create(vulkan_context* context, vulkan_renderpass* renderpass, u32 width, u32 height, u32 attachment_count, VkImageView* attachments, vulkan_framebuffer* out_framebuffer) { @@ -935,7 +1033,7 @@ void vulkan_swapchain_create(vulkan_context* context, u32 width, u32 height, // TODO: requery swapchain support - u32 image_count = context->device.swapchain_support.capabilities.minImageCount + 1; + u32 image_count = context->device.swapchain_support.capabilities.minImageCount; VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swapchain_create_info.surface = context->surface; @@ -1537,16 +1635,16 @@ void backend_begin_frame(renderer* ren, f32 delta_time) { context.swapchain.framebuffers->data[context.image_index].handle); // TODO: temp test code - vulkan_object_shader_use(&context, &context.object_shader); + // vulkan_object_shader_use(&context, &context.object_shader); - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, - (VkDeviceSize*)offsets); + // VkDeviceSize offsets[1] = { 0 }; + // vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + // (VkDeviceSize*)offsets); - vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, - VK_INDEX_TYPE_UINT32); + // vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, + // VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); + // vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0); // --- End temp test code } @@ -1591,9 +1689,34 @@ void backend_end_frame(renderer* ren, f32 delta_time) { void gfx_backend_draw_frame(renderer* ren) { backend_begin_frame(ren, 16.0); + gfx_backend_update_global_state(mat4_ident(), mat4_ident(), VEC3_ZERO, vec4(1.0, 1.0, 1.0, 1.0), + 0); + backend_end_frame(ren, 16.0); } +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, + i32 mode) { + vulkan_command_buffer* cmd_buffer = &context.gfx_command_buffers->data[context.image_index]; + vulkan_object_shader_use(&context, &context.object_shader); + + vulkan_object_shader_update_global_state(&context, &context.object_shader); + context.object_shader.global_ubo.projection = projection; + context.object_shader.global_ubo.view = view; + // TODO: other UBO properties + + // vulkan_object_shader_use(&context, &context.object_shader); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(cmd_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, + (VkDeviceSize*)offsets); + + vkCmdBindIndexBuffer(cmd_buffer->handle, context.object_index_buffer.handle, 0, + VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(cmd_buffer->handle, 6, 1, 0, 0, 0); +} + void clear_screen(vec3 colour) {} void bind_texture(shader s, texture* tex, u32 slot) {} diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h index 041f412..69d14d8 100644 --- a/src/renderer/render_backend.h +++ b/src/renderer/render_backend.h @@ -13,6 +13,7 @@ bool gfx_backend_init(renderer* ren); void gfx_backend_shutdown(renderer* ren); void gfx_backend_draw_frame(renderer* ren); +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, i32 mode); void clear_screen(vec3 colour); diff --git a/xmake.lua b/xmake.lua index 3005713..cb6d98a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -69,7 +69,7 @@ rule("compile_glsl_vert_shaders") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".vert.spv") - print("Compiling shader: %s", sourcefile) + print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) @@ -78,7 +78,7 @@ rule("compile_glsl_frag_shaders") on_buildcmd_file(function (target, batchcmds, sourcefile, opt) local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".frag.spv") - print("Compiling shader: %s", sourcefile) + print("Compiling shader: %s to %s", sourcefile, targetfile) batchcmds:vrunv('glslc', {sourcefile, "-o", targetfile}) batchcmds:add_depfiles(sourcefile) end) @@ -104,11 +104,11 @@ target("core_config") add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) + add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error add_rules("compile_glsl_vert_shaders") add_rules("compile_glsl_frag_shaders") - add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error - add_files("assets/shaders/triangle.vert") - add_files("assets/shaders/triangle.frag") + add_files("assets/shaders/object.vert") + add_files("assets/shaders/object.frag") -- add_files("assets/shaders/*.frag") set_default(false) -- prevents standalone building of this target -- cgit v1.2.3-70-g09d2 From a51ef12d8583522ee229a0195a4132652f0f9cd8 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 4 May 2024 15:47:54 +1000 Subject: finish swapchain creation --- assets/shaders/triangle.frag | 0 assets/shaders/triangle.vert | 0 src/renderer/backends/backend_vulkan.c | 74 +++++++++++++++++----------------- src/renderer/backends/backend_vulkan.h | 6 +++ src/renderer/backends/vulkan_helpers.h | 19 ++++++++- src/renderer/ral.h | 2 +- src/std/utils.h | 4 ++ src/systems/terrain.h | 2 +- 8 files changed, 66 insertions(+), 41 deletions(-) create mode 100644 assets/shaders/triangle.frag create mode 100644 assets/shaders/triangle.vert create mode 100644 src/std/utils.h (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag new file mode 100644 index 0000000..e69de29 diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert new file mode 100644 index 0000000..e69de29 diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 08e62bf..028cde8 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -13,7 +13,7 @@ #include "defines.h" #include "log.h" #include "ral.h" -#include "ral_types.h" +#include "utils.h" // TEMP #define SCREEN_WIDTH 1000 @@ -182,32 +182,8 @@ bool gpu_device_create(gpu_device* out_device) { } TRACE("Physical device selected"); - // vulkan_device_query_swapchain_support(out_device->physical_device, context.surface, - // &context.swapchain_support); - - // Logical device + // Logical device & Queues create_logical_device(out_device); - // VkDeviceQueueCreateInfo queue_create_info = {}; - - // queue_family_indices indices = find_queue_families(context.device->physical_device); - // //.. - // VkDeviceCreateInfo device_create_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; - // device_create_info.queueCreateInfoCount = VULKAN_QUEUES_COUNT; - // device_create_info.pQueueCreateInfos = queue_create_info; - // device_create_info.pEnabledFeatures = &device_features; - // device_create_info.enabledExtensionCount = 1; - // const char* extension_names = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - // device_create_info.ppEnabledExtensionNames = &extension_names; - - // VkResult result = vkCreateDevice(out_device->physical_device, &device_create_info, - // context.allocator, &out_device->logical_device); - // if (result != VK_SUCCESS) { - // FATAL("Error creating logical device with status %u\n", result); - // exit(1); - // } - // TRACE("Logical device created"); - - // Queues // Create the command pool @@ -216,29 +192,55 @@ bool gpu_device_create(gpu_device* out_device) { } bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { - VkExtent2D swapchain_extent = { context.screen_width, context.screen_height }; + out_swapchain->swapchain_arena = arena_create(malloc(1024), 1024); + vulkan_swapchain_support_info swapchain_support = context.swapchain_support; - // find a format + // TODO: custom swapchain extents VkExtent2D swapchain_extent = { width, height }; + VkSurfaceFormatKHR image_format = choose_swapchain_format(&swapchain_support); + out_swapchain->image_format = image_format; VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; // guaranteed to be implemented + out_swapchain->present_mode = present_mode; + + u32 image_count = swapchain_support.capabilities.minImageCount + 1; + out_swapchain->image_count = image_count; VkSwapchainCreateInfoKHR swapchain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swapchain_create_info.surface = context.surface; - swapchain_create_info.minImageCount = 2; - // TODO: image_ fields + swapchain_create_info.minImageCount = image_count; + swapchain_create_info.imageFormat = image_format.format; + swapchain_create_info.imageColorSpace = image_format.colorSpace; + swapchain_create_info.imageExtent = swapchain_support.capabilities.currentExtent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.queueFamilyIndexCount = 0; - swapchain_create_info.pQueueFamilyIndices = 0; + swapchain_create_info.pQueueFamilyIndices = NULL; - // TODO: preTransform + swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = present_mode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = 0; + swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; + + out_swapchain->extent = swapchain_support.capabilities.currentExtent; VK_CHECK(vkCreateSwapchainKHR(context.device->logical_device, &swapchain_create_info, context.allocator, &out_swapchain->handle)); TRACE("Vulkan Swapchain created"); + + // Retrieve Images + out_swapchain->images = + arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + VK_CHECK(vkGetSwapchainImagesKHR(context.device->logical_device, out_swapchain->handle, + &image_count, out_swapchain->images)); + + return true; +} + +void gpu_swapchain_destroy(gpu_swapchain* swapchain) { + arena_free_storage(&swapchain->swapchain_arena); + vkDestroySwapchainKHR(context.device, swapchain->handle, context.allocator); } gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc description) { @@ -482,7 +484,7 @@ queue_family_indices find_queue_families(VkPhysicalDevice device) { VkBool32 present_support = false; vkGetPhysicalDeviceSurfaceSupportKHR(device, q_fam_i, context.surface, &present_support); - if (present_support) { + if (present_support && !indices.has_present) { indices.present_family_index = q_fam_i; indices.has_present = true; } @@ -491,8 +493,6 @@ queue_family_indices find_queue_families(VkPhysicalDevice device) { return indices; } -const char* bool_str(bool input) { return input ? "True" : "False"; } - bool create_logical_device(gpu_device* out_device) { queue_family_indices indices = find_queue_families(out_device->physical_device); INFO(" %s | %s | %s | %s | %s", bool_str(indices.has_graphics), bool_str(indices.has_present), diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 8c6b772..0114d7a 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -28,6 +28,12 @@ typedef struct queue_family_indices { typedef struct gpu_swapchain { VkSwapchainKHR handle; + arena swapchain_arena; + VkExtent2D extent; + VkSurfaceFormatKHR image_format; + VkPresentModeKHR present_mode; + VkImage* images; + u32 image_count; } gpu_swapchain; typedef struct gpu_device { diff --git a/src/renderer/backends/vulkan_helpers.h b/src/renderer/backends/vulkan_helpers.h index 03ee814..55d8846 100644 --- a/src/renderer/backends/vulkan_helpers.h +++ b/src/renderer/backends/vulkan_helpers.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -54,8 +55,8 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback( VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT flags, const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data); -void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, - vulkan_swapchain_support_info* out_support_info) { +static void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR surface, + vulkan_swapchain_support_info* out_support_info) { // TODO: add VK_CHECK to these calls! // Surface capabilities @@ -78,6 +79,20 @@ void vulkan_device_query_swapchain_support(VkPhysicalDevice device, VkSurfaceKHR } } +static VkSurfaceFormatKHR choose_swapchain_format( + vulkan_swapchain_support_info* swapchain_support) { + assert(swapchain_support->format_count > 0); + // find a format + for (u32 i = 0; i < swapchain_support->format_count; i++) { + VkSurfaceFormatKHR format = swapchain_support->formats[i]; + if (format.format == VK_FORMAT_B8G8R8A8_SRGB && + format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return format; + } + } + return swapchain_support->formats[0]; +} + // static bool physical_device_meets_requirements( // VkPhysicalDevice device, VkSurfaceKHR surface, const VkPhysicalDeviceProperties* properties, // const VkPhysicalDeviceFeatures* features, diff --git a/src/renderer/ral.h b/src/renderer/ral.h index 7c143f2..f202e51 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -77,7 +77,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip void gpu_pipeline_destroy(gpu_pipeline* pipeline); bool gpu_swapchain_create(gpu_swapchain* out_swapchain); -void gpu_swapchain_destroy(); +void gpu_swapchain_destroy(gpu_swapchain* swapchain); void gpu_cmd_encoder_begin(); void gpu_cmd_encoder_begin_render(); diff --git a/src/std/utils.h b/src/std/utils.h new file mode 100644 index 0000000..c9827a3 --- /dev/null +++ b/src/std/utils.h @@ -0,0 +1,4 @@ +#pragma once +#include + +const char* bool_str(bool input) { return input ? "True" : "False"; } \ No newline at end of file diff --git a/src/systems/terrain.h b/src/systems/terrain.h index 745ca22..bfd90b5 100644 --- a/src/systems/terrain.h +++ b/src/systems/terrain.h @@ -18,8 +18,8 @@ Future: #include "defines.h" #include "maths_types.h" #include "mem.h" -#include "str.h" #include "render_types.h" +#include "str.h" typedef struct heightmap { str8 filepath; -- cgit v1.2.3-70-g09d2 From 509dd53c645b4f917bd83defb7c485a71be15f46 Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 4 May 2024 16:06:55 +1000 Subject: compile glsl to spirv for triangle shader --- assets/shaders/triangle.frag | 6 ++++++ assets/shaders/triangle.vert | 12 ++++++++++++ src/renderer/backends/backend_vulkan.c | 1 - xmake.lua | 8 ++++---- 4 files changed, 22 insertions(+), 5 deletions(-) (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.frag b/assets/shaders/triangle.frag index e69de29..2151162 100644 --- a/assets/shaders/triangle.frag +++ b/assets/shaders/triangle.frag @@ -0,0 +1,6 @@ +#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/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index e69de29..e160d39 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -0,0 +1,12 @@ +#version 450 + +vec2 positions[3] = vec2[](vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5)); + +vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); + +layout(location = 0) out vec3 fragColor; + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 0616a53..45bb0e7 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -14,7 +14,6 @@ #include "log.h" #include "ral.h" #include "utils.h" -#include "utils.h" // TEMP #define SCREEN_WIDTH 1000 diff --git a/xmake.lua b/xmake.lua index 949dd76..882535d 100644 --- a/xmake.lua +++ b/xmake.lua @@ -110,10 +110,10 @@ target("core_config") add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) add_files("src/empty.c") -- for some reason we need this on Mac so it doesnt call 'ar' with no files and error - -- add_rules("compile_glsl_vert_shaders") - -- add_rules("compile_glsl_frag_shaders") - -- add_files("assets/shaders/object.vert") - -- add_files("assets/shaders/object.frag") + add_rules("compile_glsl_vert_shaders") + add_rules("compile_glsl_frag_shaders") + add_files("assets/shaders/triangle.vert") + add_files("assets/shaders/triangle.frag") -- add_files("assets/shaders/*.frag") if is_plat("windows") then add_includedirs("$(env VULKAN_SDK)/Include", {public = true}) -- cgit v1.2.3-70-g09d2 From f1b48b0bbbebb92b9600dac41848304b82f0b3dd Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Wed, 8 May 2024 11:56:25 +1000 Subject: we are so triangle --- assets/shaders/triangle.vert | 2 +- examples/triangle/ex_triangle.c | 4 +-- src/renderer/backends/backend_vulkan.c | 48 ++++++++++++++++++---------------- 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index e160d39..ee3675d 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -1,6 +1,6 @@ #version 450 -vec2 positions[3] = vec2[](vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5)); +vec2 positions[3] = vec2[](vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(0.0, -0.5)); vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 50f135a..4aa9e96 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -45,6 +45,7 @@ int main() { // Main loop while (!should_exit(core)) { + glfwPollEvents(); input_update(&core->input); render_frame_begin(&core->renderer); @@ -72,8 +73,7 @@ int main() { gpu_backend_end_frame(); render_frame_end(&core->renderer); - glfwSwapBuffers(core->renderer.window); - glfwPollEvents(); + // glfwSwapBuffers(core->renderer.window); } gpu_backend_shutdown(); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 7140d45..e693da3 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -261,15 +261,16 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain) { TRACE("Vulkan Swapchain created"); // Retrieve Images - out_swapchain->images = - arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + // out_swapchain->images = + // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImage)); + out_swapchain->images = malloc(image_count * sizeof(VkImage)); VK_CHECK(vkGetSwapchainImagesKHR(context.device->logical_device, out_swapchain->handle, &image_count, out_swapchain->images)); // Create ImageViews // TODO: Move this to a separate function - out_swapchain->image_views = - arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImageView)); + out_swapchain->image_views = malloc(image_count * sizeof(VkImageView)); + // arena_alloc(&out_swapchain->swapchain_arena, image_count * sizeof(VkImageView)); for (u32 i = 0; i < image_count; i++) { VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; view_create_info.image = out_swapchain->images[i]; @@ -306,6 +307,8 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip gpu_pipeline* pipeline = malloc(sizeof(gpu_pipeline)); // Shaders + printf("Vertex shader: %s\n", description.vs.filepath.buf); + printf("Fragment shader: %s\n", description.fs.filepath.buf); VkShaderModule vertex_shader = create_shader_module(description.vs.code); VkShaderModule fragment_shader = create_shader_module(description.fs.code); @@ -358,9 +361,9 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; + // viewport_state.pViewports = &viewport; viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; + // viewport_state.pScissors = &scissor; // Rasterizer VkPipelineRasterizationStateCreateInfo rasterizer_create_info = { @@ -402,13 +405,13 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip // Blending VkPipelineColorBlendAttachmentState color_blend_attachment_state; - color_blend_attachment_state.blendEnable = VK_TRUE; - color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.blendEnable = VK_FALSE; + // color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + // color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + // color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + // color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + // color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + // color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; @@ -606,12 +609,13 @@ void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass) { VkRenderPassBeginInfo begin_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; begin_info.renderPass = renderpass->handle; + printf("Current img: %d\n", context.current_img_index); begin_info.framebuffer = context.swapchain_framebuffers[context.current_img_index]; begin_info.renderArea.offset = (VkOffset2D){ 0, 0 }; begin_info.renderArea.extent = context.swapchain->extent; // VkClearValue clear_values[2]; - VkClearValue clear_color = { { { 0.0f, 0.0f, 0.0f, 1.0f } } }; + VkClearValue clear_color = { { { 0.2f, 0.2f, 0.2f, 1.0f } } }; // clear_values[1].depthStencil.depth = renderpass->depth; // clear_values[1].depthStencil.stencil = renderpass->stencil; @@ -657,21 +661,22 @@ void encode_set_default_settings(gpu_cmd_encoder* encoder) { // --- Drawing void gpu_backend_begin_frame() { - TRACE("gpu_backend_begin_frame"); + // TRACE("gpu_backend_begin_frame"); vkWaitForFences(context.device->logical_device, 1, &context.in_flight_fence, VK_TRUE, UINT64_MAX); vkResetFences(context.device->logical_device, 1, &context.in_flight_fence); u32 image_index; - vkAcquireNextImageKHR(context.device->logical_device, context.swapchain->handle, UINT64_MAX, - context.image_available_semaphore, VK_NULL_HANDLE, &image_index); + VK_CHECK(vkAcquireNextImageKHR(context.device->logical_device, context.swapchain->handle, + UINT64_MAX, context.image_available_semaphore, VK_NULL_HANDLE, + &image_index)); context.current_img_index = image_index; - DEBUG("Current image_index = %d", image_index); - vkResetCommandBuffer(context.main_cmd_buf.cmd_buffer, 0); + printf("Current img: %d\n", context.current_img_index); + VK_CHECK(vkResetCommandBuffer(context.main_cmd_buf.cmd_buffer, 0)); } void gpu_temp_draw() { gpu_cmd_encoder* encoder = &context.main_cmd_buf; - + TRACE("Draw call"); vkCmdDraw(encoder->cmd_buffer, 3, 1, 0, 0); } @@ -709,8 +714,7 @@ void gpu_queue_submit(gpu_cmd_buffer* buffer) { submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &buffer->cmd_buffer; - VK_CHECK( - vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, context.in_flight_fence);); + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, context.in_flight_fence)); } inline void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count) { -- cgit v1.2.3-70-g09d2 From eedd332680dbdd367197616658903f00252f5a9c Mon Sep 17 00:00:00 2001 From: Omniscient <17525998+omnisci3nce@users.noreply.github.com> Date: Sat, 11 May 2024 00:22:13 +1000 Subject: upload data using staging buffer. use vertex buffer data --- assets/shaders/triangle.vert | 11 ++- examples/triangle/ex_triangle.c | 23 ++++- src/core.c | 9 +- src/core.h | 2 +- src/maths/maths.h | 5 +- src/renderer/backends/backend_vulkan.c | 170 +++++++++++++++++++++++++++++++-- src/renderer/backends/backend_vulkan.h | 8 +- src/renderer/ral.h | 7 +- src/renderer/ral_types.h | 22 ++++- src/renderer/render.c | 43 ++++----- src/scene.h | 2 +- 11 files changed, 250 insertions(+), 52 deletions(-) (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index ee3675d..b8c8f63 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -1,12 +1,13 @@ #version 450 -vec2 positions[3] = vec2[](vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(0.0, -0.5)); - -vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec3 inColor; +// layout(location = 1) in vec3 inNormal; +// layout(location = 2) in vec2 inTexCoords; layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; + gl_Position = vec4(inPos, 0.0, 1.0); + fragColor = inColor; } diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 7b8a1d0..c4f90f2 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -1,6 +1,7 @@ #include #include "backend_vulkan.h" +#include "buf.h" #include "camera.h" #include "core.h" #include "file.h" @@ -8,12 +9,20 @@ #include "maths.h" #include "mem.h" #include "ral.h" +#include "ral_types.h" #include "render.h" // Example setting up a renderer extern core g_core; +const custom_vertex vertices[] = { + (custom_vertex){ .pos = vec2(-0.5, 0.5), .color = vec3(0.0, 0.0, 1.0) }, + (custom_vertex){ .pos = vec2(0.5, 0.5), .color = vec3(0.0, 1.0, 0.0) }, + (custom_vertex){ .pos = vec2(0.0, -0.5), .color = vec3(1.0, 0.0, 0.0) }, +}; +_Static_assert(sizeof(vertices) == (5 * 3 * sizeof(float)), ""); + int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); @@ -47,12 +56,19 @@ int main() { }; gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); + buffer_handle triangle_vert_buf = gpu_buffer_create( + 3 * sizeof(custom_vertex), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, + vertices); // gpu_buffer_create(3 * sizeof(custom_vertex), CEL_BUFFER_VERTEX); + /* buffer_upload_bytes(triangle_vert_buf, (bytebuffer){ .buf = vertices, .size = sizeof(vertices) + * }, */ + /* 0, sizeof(vertices)); */ + // Main loop while (!should_exit(&g_core)) { glfwPollEvents(); input_update(&g_core.input); - render_frame_begin(&g_core.renderer); + // render_frame_begin(&g_core.renderer); static f64 x = 0.0; x += 0.01; @@ -68,7 +84,8 @@ int main() { encode_set_default_settings(enc); // Record draw calls - gpu_temp_draw(); + encode_set_vertex_buffer(enc, triangle_vert_buf); + gpu_temp_draw(3); // End recording gpu_cmd_encoder_end_render(enc); @@ -78,7 +95,7 @@ int main() { // Submit gpu_backend_end_frame(); - render_frame_end(&g_core.renderer); + // render_frame_end(&g_core.renderer); // glfwSwapBuffers(core->renderer.window); } diff --git a/src/core.c b/src/core.c index 26e7613..84c9cae 100644 --- a/src/core.c +++ b/src/core.c @@ -59,9 +59,7 @@ void core_bringup() { #include /* bool should_window_close(core* core) { glfwWindowShouldClose(core->renderer.window); } */ -void core_input_update() { - input_update(&g_core.input); -} +void core_input_update() { input_update(&g_core.input); } void core_frame_begin(core* core) { render_frame_begin(&core->renderer); } void core_frame_end(core* core) { render_frame_end(&core->renderer); } @@ -76,7 +74,8 @@ bool should_exit() { } void frame_begin() { - glfwPollEvents(); - render_frame_begin(&g_core.renderer); } + glfwPollEvents(); + render_frame_begin(&g_core.renderer); +} void frame_draw() {} void frame_end() { render_frame_end(&g_core.renderer); } diff --git a/src/core.h b/src/core.h index db711d0..1031868 100644 --- a/src/core.h +++ b/src/core.h @@ -1,8 +1,8 @@ #pragma once #include "input.h" -#include "screenspace.h" #include "scene.h" +#include "screenspace.h" #include "terrain.h" #include "text.h" // #include "threadpool.h" diff --git a/src/maths/maths.h b/src/maths/maths.h index 88a5215..217f2e0 100644 --- a/src/maths/maths.h +++ b/src/maths/maths.h @@ -21,7 +21,7 @@ // Dimension 3 static inline vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; } -#define vec3(x, y, z) (vec3_create(x, y, z)) +#define vec3(x, y, z) ((vec3){ x, y, z }) static inline vec3 vec3_add(vec3 a, vec3 b) { return (vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; } static inline vec3 vec3_sub(vec3 a, vec3 b) { return (vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; } static inline vec3 vec3_mult(vec3 a, f32 s) { return (vec3){ a.x * s, a.y * s, a.z * s }; } @@ -53,6 +53,7 @@ static inline void print_vec3(vec3 v) { printf("{ x: %f, y: %f, z: %f )\n", v.x, // TODO: Dimension 2 static inline vec2 vec2_create(f32 x, f32 y) { return (vec2){ x, y }; } +#define vec2(x, y) ((vec2){ x, y }) static inline vec2 vec2_div(vec2 a, f32 s) { return (vec2){ a.x / s, a.y / s }; } // TODO: Dimension 4 @@ -320,4 +321,4 @@ static inline mat4 transform_to_mat(transform *tf) { _Static_assert(alignof(vec3) == 4, "vec3 is 4 byte aligned"); _Static_assert(sizeof(vec3) == 12, "vec3 is 12 bytes so has no padding"); -_Static_assert(alignof(vec4) == 4, "vec4 is 4 byte aligned"); \ No newline at end of file +_Static_assert(alignof(vec4) == 4, "vec4 is 4 byte aligned"); diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 5390f1f..e30d3c1 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,8 +9,10 @@ #include #include "backend_vulkan.h" +#include "buf.h" #include "maths_types.h" #include "mem.h" +#include "ral_types.h" #include "str.h" #include "vulkan_helpers.h" @@ -54,6 +57,10 @@ typedef struct vulkan_context { bool is_resizing; GLFWwindow* window; + // Storage + gpu_buffer buffers[1024]; + size_t buffer_count; + VkDebugUtilsMessengerEXT vk_debugger; } vulkan_context; @@ -366,17 +373,31 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, frag_shader_stage_info }; - // Vertex Input - // TODO: Attributes + VkVertexInputAttributeDescription attribute_descs[2]; + attribute_descs[0].binding = 0; + attribute_descs[0].location = 0; + attribute_descs[0].format = VK_FORMAT_R32G32_SFLOAT; + attribute_descs[0].offset = offsetof(custom_vertex, pos); + + attribute_descs[1].binding = 0; + attribute_descs[1].location = 1; + attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descs[1].offset = offsetof(custom_vertex, color); + + // Vertex input + VkVertexInputBindingDescription binding_desc; + binding_desc.binding = 0; + binding_desc.stride = sizeof(custom_vertex); + binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; - vertex_input_info.vertexBindingDescriptionCount = 0; - vertex_input_info.pVertexBindingDescriptions = NULL; - vertex_input_info.vertexAttributeDescriptionCount = 0; - vertex_input_info.pVertexAttributeDescriptions = NULL; + vertex_input_info.vertexBindingDescriptionCount = 1; + vertex_input_info.pVertexBindingDescriptions = &binding_desc; + vertex_input_info.vertexAttributeDescriptionCount = 2; + vertex_input_info.pVertexAttributeDescriptions = attribute_descs; // Input Assembly VkPipelineInputAssemblyStateCreateInfo input_assembly = { @@ -633,6 +654,10 @@ gpu_cmd_encoder gpu_cmd_encoder_create() { return encoder; } +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder) { + vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, + &encoder->cmd_buffer); +} void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder) { VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; @@ -674,6 +699,12 @@ gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder) { void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipeline* pipeline) { vkCmdBindPipeline(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle); } +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { + gpu_buffer buffer = context.buffers[buf.raw]; + VkBuffer vbs[] = { buffer.handle }; + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(encoder->cmd_buffer, 0, 1, vbs, offsets); +} // TEMP void encode_set_default_settings(gpu_cmd_encoder* encoder) { @@ -720,9 +751,9 @@ bool gpu_backend_begin_frame() { return true; } -void gpu_temp_draw() { +void gpu_temp_draw(size_t n_verts) { gpu_cmd_encoder* encoder = gpu_get_default_cmd_encoder(); // &context.main_cmd_buf; - vkCmdDraw(encoder->cmd_buffer, 3, 1, 0, 0); + vkCmdDraw(encoder->cmd_buffer, n_verts, 1, 0, 0); } void gpu_backend_end_frame() { @@ -971,3 +1002,126 @@ void create_sync_objects() { &context.in_flight_fences[i])); } } + +static i32 find_memory_index(u32 type_filter, u32 property_flags) { + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(context.device->physical_device, &memory_properties); + + for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) { + // Check each memory type to see if its bit is set to 1. + if (type_filter & (1 << i) && + (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags) { + return i; + } + } + + WARN("Unable to find suitable memory type!"); + return -1; +} + +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data) { + VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + buffer_info.size = size; + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + switch (buf_type) { + case CEL_BUFFER_DEFAULT: + buffer_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + break; + case CEL_BUFFER_VERTEX: + buffer_info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + break; + case CEL_BUFFER_COUNT: + WARN("Incorrect gpu_buffer_type provided. using default"); + break; + } + + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // "allocating" the cpu-side buffer struct + gpu_buffer buffer; + buffer.size = size; + buffer_handle handle = { .raw = (u32)context.buffer_count }; + + VK_CHECK(vkCreateBuffer(context.device->logical_device, &buffer_info, context.allocator, + &buffer.handle)); + + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(context.device->logical_device, buffer.handle, &requirements); + + // Just make them always need all of them for now + i32 memory_index = + find_memory_index(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + // Allocate the actual VRAM + VkMemoryAllocateInfo allocate_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocate_info.allocationSize = requirements.size; + allocate_info.memoryTypeIndex = (u32)memory_index; + + vkAllocateMemory(context.device->logical_device, &allocate_info, context.allocator, + &buffer.memory); + vkBindBufferMemory(context.device->logical_device, buffer.handle, buffer.memory, 0); + + /* Now there are two options: + * 1. create CPU-accessible memory -> map memory -> memcpy -> unmap + * 2. use a staging buffer thats CPU-accessible and copy its contents to a + * GPU-only buffer + */ + + context.buffers[context.buffer_count] = buffer; + context.buffer_count++; + + if (data) { + if (flags & CEL_BUFFER_FLAG_CPU) { + buffer_upload_bytes(handle, (bytebuffer){ .buf = (u8*)data, .size = size }, 0, size); + } else if (flags & CEL_BUFFER_FLAG_GPU) { + TRACE("Uploading data to buffer using staging buffer"); + buffer_handle staging = + gpu_buffer_create(size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, data); + gpu_cmd_encoder temp_encoder = gpu_cmd_encoder_create(); + gpu_cmd_encoder_begin(temp_encoder); + encode_buffer_copy(&temp_encoder, handle, 0, staging, 0, size); + gpu_cmd_buffer copy_cmd_buffer = gpu_cmd_encoder_finish(&temp_encoder); + + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &temp_encoder.cmd_buffer; + vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, VK_NULL_HANDLE); + + vkQueueWaitIdle(context.device->graphics_queue); + gpu_cmd_encoder_destroy(&temp_encoder); + gpu_buffer_destroy(staging); + } + } + + return handle; +} + +void gpu_buffer_destroy(buffer_handle buffer) { + gpu_buffer b = context.buffers[buffer.raw]; + vkDestroyBuffer(context.device->logical_device, b.handle, context.allocator); + vkFreeMemory(context.device->logical_device, b.memory, context.allocator); +} + +// Upload data to a +void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { + gpu_buffer buffer = context.buffers[gpu_buf.raw]; + void* data_ptr; + vkMapMemory(context.device->logical_device, buffer.memory, 0, size, 0, &data_ptr); + memcpy(data_ptr, cpu_buf.buf, size); + vkUnmapMemory(context.device->logical_device, buffer.memory); +} + +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size) { + VkBufferCopy copy_region; + copy_region.srcOffset = src_offset; + copy_region.dstOffset = dst_offset; + copy_region.size = copy_size; + + vkCmdCopyBuffer(encoder->cmd_buffer, context.buffers[src.raw].handle, + context.buffers[dst.raw].handle, 1, ©_region); +} diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 330ba18..0b0a492 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -75,4 +75,10 @@ typedef struct gpu_cmd_encoder { typedef struct gpu_cmd_buffer { VkCommandBuffer cmd_buffer; -} gpu_cmd_buffer; \ No newline at end of file +} gpu_cmd_buffer; + +typedef struct gpu_buffer { + VkBuffer handle; + VkDeviceMemory memory; + u64 size; +} gpu_buffer; diff --git a/src/renderer/ral.h b/src/renderer/ral.h index ec9793e..2fb0166 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -28,6 +28,7 @@ typedef struct gpu_pipeline gpu_pipeline; typedef struct gpu_renderpass gpu_renderpass; typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission +typedef struct gpu_buffer gpu_buffer; /** @brief A*/ // typedef struct gpu_bind_group @@ -85,6 +86,7 @@ bool gpu_swapchain_create(gpu_swapchain* out_swapchain); void gpu_swapchain_destroy(gpu_swapchain* swapchain); gpu_cmd_encoder gpu_cmd_encoder_create(); +void gpu_cmd_encoder_destroy(gpu_cmd_encoder* encoder); void gpu_cmd_encoder_begin(gpu_cmd_encoder encoder); void gpu_cmd_encoder_begin_render(gpu_cmd_encoder* encoder, gpu_renderpass* renderpass); void gpu_cmd_encoder_end_render(gpu_cmd_encoder* encoder); @@ -117,7 +119,8 @@ gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder); void gpu_queue_submit(gpu_cmd_buffer* buffer); // Buffers -void gpu_buffer_create(u64 size); +buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_flags flags, + const void* data); void gpu_buffer_destroy(buffer_handle buffer); void gpu_buffer_upload(); void gpu_buffer_bind(buffer_handle buffer); @@ -137,4 +140,4 @@ bytebuffer vertices_as_bytebuffer(arena* a, vertex_format format, vertex_darray* // TEMP -void gpu_temp_draw(); +void gpu_temp_draw(size_t n_verts); diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index ae54b53..7dd254e 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -55,6 +55,20 @@ typedef struct texture_desc { u32x2 extents; } texture_desc; +typedef enum gpu_buffer_type { + CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? + CEL_BUFFER_VERTEX, + CEL_BUFFER_COUNT +} gpu_buffer_type; + +typedef enum gpu_buffer_flag { + CEL_BUFFER_FLAG_CPU = 1 << 0, + CEL_BUFFER_FLAG_GPU = 1 << 1, + CEL_BUFFER_FLAG_STORAGE = 1 << 2, + CEL_BUFFER_FLAG_COUNT +} gpu_buffer_flag; +typedef u32 gpu_buffer_flags; + typedef enum vertex_format { VERTEX_STATIC_3D, VERTEX_SPRITE, @@ -99,6 +113,12 @@ KITC_DECL_TYPED_ARRAY(u32) #define TYPED_VERTEX_ARRAY #endif +// TEMP +typedef struct custom_vertex { + vec2 pos; + vec3 color; +} custom_vertex; + typedef enum gpu_cull_mode { CULL_BACK_FACE, CULL_FRONT_FACE, CULL_COUNT } gpu_cull_mode; // ? How to tie together materials and shaders @@ -110,4 +130,4 @@ typedef enum gpu_cull_mode { CULL_BACK_FACE, CULL_FRONT_FACE, CULL_COUNT } gpu_c // 3 - you don't need to know how the renderer works at all // 2 - you need to know how the overall renderer is designed -// 1 - you need to understand graphics API specifics \ No newline at end of file +// 1 - you need to understand graphics API specifics diff --git a/src/renderer/render.c b/src/renderer/render.c index 10589e5..9f5b21a 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -55,7 +55,7 @@ bool renderer_init(renderer* ren) { // default_material_init(); // Create default rendering pipeline - default_pipelines_init(ren); + /* default_pipelines_init(ren); */ return true; } @@ -67,9 +67,6 @@ void renderer_shutdown(renderer* ren) { void default_pipelines_init(renderer* ren) { // Static opaque geometry - // graphics_pipeline_desc gfx = { - // }; - // ren->static_opaque_pipeline = gpu_graphics_pipeline_create(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); gpu_renderpass_desc pass_description = {}; @@ -77,8 +74,8 @@ void default_pipelines_init(renderer* ren) { ren->default_renderpass = *renderpass; - str8 vert_path = str8lit("celeritas-core/build/linux/x86_64/debug/triangle.vert.spv"); - str8 frag_path = str8lit("celeritas-core/build/linux/x86_64/debug/triangle.frag.spv"); + str8 vert_path = str8lit("build/linux/x86_64/debug/triangle.vert.spv"); + str8 frag_path = str8lit("build/linux/x86_64/debug/triangle.frag.spv"); str8_opt vertex_shader = str8_from_file(&scratch, vert_path); str8_opt fragment_shader = str8_from_file(&scratch, frag_path); if (!vertex_shader.has_value || !fragment_shader.has_value) { @@ -104,28 +101,28 @@ void default_pipelines_init(renderer* ren) { } void render_frame_begin(renderer* ren) { - ren->frame_aborted = false; - if (!gpu_backend_begin_frame()) { - ren->frame_aborted = true; - return; - } - gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); - // begin recording - gpu_cmd_encoder_begin(*enc); - gpu_cmd_encoder_begin_render(enc, &ren->default_renderpass); - encode_bind_pipeline(enc, PIPELINE_GRAPHICS, &ren->static_opaque_pipeline); - encode_set_default_settings(enc); + ren->frame_aborted = false; + if (!gpu_backend_begin_frame()) { + ren->frame_aborted = true; + return; + } + gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); + // begin recording + gpu_cmd_encoder_begin(*enc); + gpu_cmd_encoder_begin_render(enc, &ren->default_renderpass); + encode_bind_pipeline(enc, PIPELINE_GRAPHICS, &ren->static_opaque_pipeline); + encode_set_default_settings(enc); } void render_frame_end(renderer* ren) { if (ren->frame_aborted) { return; } - gpu_temp_draw(); - gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); - gpu_cmd_encoder_end_render(enc); - gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); - gpu_queue_submit(&buf); - gpu_backend_end_frame(); + gpu_temp_draw(3); + gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder(); + gpu_cmd_encoder_end_render(enc); + gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc); + gpu_queue_submit(&buf); + gpu_backend_end_frame(); } void render_frame_draw(renderer* ren) {} diff --git a/src/scene.h b/src/scene.h index 5399ab7..24429b3 100644 --- a/src/scene.h +++ b/src/scene.h @@ -11,8 +11,8 @@ #pragma once #include "camera.h" #include "defines.h" -#include "render_types.h" #include "maths_types.h" +#include "render_types.h" typedef struct scene { // camera -- cgit v1.2.3-70-g09d2 From d79a8aa200bd64b14b85d2ec0c207601ba5c7922 Mon Sep 17 00:00:00 2001 From: Omniscient Date: Sat, 18 May 2024 23:53:11 +1000 Subject: working on image creation --- assets/shaders/triangle.vert | 2 - examples/cube/ex_cube.c | 5 + examples/triangle/ex_triangle.c | 18 ++- src/renderer/backends/backend_vulkan.c | 224 ++++++++++++++++++++++++++++----- src/renderer/backends/backend_vulkan.h | 8 ++ src/renderer/ral.c | 21 ---- src/renderer/ral.h | 7 ++ src/renderer/ral_types.h | 3 - src/renderer/render.c | 44 ++++++- src/renderer/render.h | 16 ++- src/renderer/render_types.h | 15 +-- 11 files changed, 289 insertions(+), 74 deletions(-) (limited to 'assets/shaders/triangle.vert') diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert index b8c8f63..8030561 100644 --- a/assets/shaders/triangle.vert +++ b/assets/shaders/triangle.vert @@ -2,8 +2,6 @@ layout(location = 0) in vec2 inPos; layout(location = 1) in vec3 inColor; -// layout(location = 1) in vec3 inNormal; -// layout(location = 2) in vec2 inTexCoords; layout(location = 0) out vec3 fragColor; diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 7c7831d..264bf71 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -86,9 +86,14 @@ int main() { }; gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description); + // Geometry geometry_data cube_data = geo_create_cuboid(f32x3(1, 1, 1)); mesh cube = mesh_create(&cube_data, false); + // Texture + texture_data tex_data = texture_data_load("assets/textures/texture.jpg", false); + texture_handle texture = texture_data_upload(tex_data, true); + // Main loop while (!should_exit(&g_core)) { input_update(&g_core.input); diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c index 5d8f0cf..886637a 100644 --- a/examples/triangle/ex_triangle.c +++ b/examples/triangle/ex_triangle.c @@ -16,17 +16,22 @@ extern core g_core; const custom_vertex vertices[] = { + (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.0) }, + (custom_vertex){ .pos = vec2(0.5, -0.5), .color = vec3(1.0, 0.0, 0.0) }, (custom_vertex){ .pos = vec2(-0.5, 0.5), .color = vec3(0.0, 0.0, 1.0) }, (custom_vertex){ .pos = vec2(0.5, 0.5), .color = vec3(0.0, 1.0, 0.0) }, - (custom_vertex){ .pos = vec2(0.5, -0.5), .color = vec3(1.0, 0.0, 0.0) }, - (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.0) }, }; -const u16 indices[] = { 0, 1, 2, 2, 3, 0 }; +const u32 indices[] = { 2, 1, 0, 1, 2, 3}; int main() { core_bringup(); arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024); + vertex_description vertex_input = {0}; + vertex_input.debug_label = "Hello"; + vertex_desc_add(&vertex_input, "inPos", ATTR_F32x2); + vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3); + gpu_renderpass_desc pass_description = {}; gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); @@ -40,6 +45,9 @@ int main() { struct graphics_pipeline_desc pipeline_description = { .debug_name = "Basic Pipeline", + .vertex_desc = vertex_input, + // .data_layouts = {0}, + // .data_layouts_count = 0, .vs = { .debug_name = "Triangle Vertex Shader", .filepath = vert_path, .code = vertex_shader.contents, @@ -56,13 +64,13 @@ int main() { // Load triangle vertex and index data buffer_handle triangle_vert_buf = - gpu_buffer_create(sizeof(vertices), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); + gpu_buffer_create(4 * sizeof(vertex) , CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices); buffer_handle triangle_index_buf = gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices); // Main loop - while (!should_exit(&g_core)) { + while (!should_exit()) { input_update(&g_core.input); if (!gpu_backend_begin_frame()) { diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 2dc11b5..208aef0 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -414,37 +414,39 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info, frag_shader_stage_info }; - // TODO: Attributes - VkVertexInputAttributeDescription attribute_descs[2] = { 0 }; - /* u32 offset = 0; */ - /* for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { */ - /* attribute_descs[i].binding = 0; */ - /* attribute_descs[i].location = i; */ - /* attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); - */ - /* attribute_descs[i].offset = offset; */ - /* size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); */ - /* printf("offset total %d this attr %ld\n", offset, this_offset); */ - /* printf("sizeof vertex %ld\n", sizeof(vertex)); */ - /* printf("%d \n", offsetof(vertex, static_3d)); */ - /* offset += this_offset; */ - /* } */ - printf("Vertex attributes\n"); - attribute_descs[0].binding = 0; - attribute_descs[0].location = 0; - attribute_descs[0].format = VK_FORMAT_R32G32B32_SFLOAT; - attribute_descs[0].offset = 0; // offsetof(custom_vertex, pos); - - attribute_descs[1].binding = 0; - attribute_descs[1].location = 1; - attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; - attribute_descs[1].offset = 12; // offsetof(custom_vertex, color); + // Attributes + u32 attr_count = description.vertex_desc.attributes_count; + printf("N attributes %d\n", attr_count); + VkVertexInputAttributeDescription attribute_descs[attr_count]; + memset(attribute_descs, 0, attr_count * sizeof(VkVertexInputAttributeDescription)); + u32 offset = 0; + for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { + attribute_descs[i].binding = 0; + attribute_descs[i].location = i; + attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]); + attribute_descs[i].offset = offset; + size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); + printf("offset total %d this attr %ld\n", offset, this_offset); + printf("sizeof vertex %ld\n", sizeof(vertex)); + /* printf("%d \n", offsetof(vertex, static_3d)); */ + offset += this_offset; + } + /* printf("Vertex attributes\n"); */ + /* attribute_descs[0].binding = 0; */ + /* attribute_descs[0].location = 0; */ + /* attribute_descs[0].format = VK_FORMAT_R32G32B32_SFLOAT; */ + /* attribute_descs[0].offset = 0; // offsetof(custom_vertex, pos); */ + + /* attribute_descs[1].binding = 0; */ + /* attribute_descs[1].location = 1; */ + /* attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; */ + /* attribute_descs[1].offset = 12; // offsetof(custom_vertex, color); */ // Vertex input // TODO: Generate this from descroiption now VkVertexInputBindingDescription binding_desc; binding_desc.binding = 0; - binding_desc.stride = sizeof(vertex); // description.vertex_desc.stride; + binding_desc.stride = description.vertex_desc.stride; binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkPipelineVertexInputStateCreateInfo vertex_input_info = { @@ -453,7 +455,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip vertex_input_info.vertexBindingDescriptionCount = 1; vertex_input_info.pVertexBindingDescriptions = &binding_desc; vertex_input_info.vertexAttributeDescriptionCount = - 2; // description.vertex_desc.attributes_count; + attr_count; // description.vertex_desc.attributes_count; vertex_input_info.pVertexAttributeDescriptions = attribute_descs; // Input Assembly @@ -558,10 +560,15 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip malloc(description.data_layouts_count * sizeof(VkDescriptorSetLayout)); pipeline->desc_set_layouts = desc_set_layouts; pipeline->desc_set_layouts_count = description.data_layouts_count; + if (description.data_layouts_count > 0) { pipeline->uniform_pointers = malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer)); + } else { + pipeline->uniform_pointers = NULL; + } // assert(description.data_layouts_count == 1); + printf("data layouts %d\n", description.data_layouts_count); for (u32 i = 0; i < description.data_layouts_count; i++) { shader_data_layout sdl = description.data_layouts[i].shader_data_get_layout(NULL); @@ -1343,15 +1350,15 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f void gpu_buffer_destroy(buffer_handle buffer) { gpu_buffer* b = - buffer_pool_get(&context.resource_pools->buffers, buffer); // context.buffers[buffer.raw]; + buffer_pool_get(&context.resource_pools->buffers, buffer); vkDestroyBuffer(context.device->logical_device, b->handle, context.allocator); vkFreeMemory(context.device->logical_device, b->memory, context.allocator); + buffer_pool_dealloc(&context.resource_pools->buffers, buffer); } // Upload data to a void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) { gpu_buffer* buffer = buffer_pool_get(&context.resource_pools->buffers, gpu_buf); - /* gpu_buffer buffer = context.buffers[gpu_buf.raw]; */ void* data_ptr; vkMapMemory(context.device->logical_device, buffer->memory, 0, size, 0, &data_ptr); DEBUG("Uploading %d bytes to buffer", size); @@ -1371,6 +1378,80 @@ void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_off vkCmdCopyBuffer(encoder->cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); } +// one-shot command buffers +VkCommandBuffer vulkan_command_buffer_create_oneshot() { + VkCommandBufferAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + alloc_info.commandPool = context.device->pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + alloc_info.pNext = 0; + + VkCommandBuffer cmd_buffer; + vkAllocateCommandBuffers(context.device->logical_device, &alloc_info, &cmd_buffer); + + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(cmd_buffer, &begin_info); + + return cmd_buffer; +} + +void vulkan_command_buffer_finish_oneshot(VkCommandBuffer cmd_buffer) { + VK_CHECK(vkEndCommandBuffer(cmd_buffer)); + + // submit to queue + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmd_buffer; + VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, 0)); + VK_CHECK(vkQueueWaitIdle(context.device->graphics_queue)); + + vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, &cmd_buffer); +} + +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, + u64 dst_offset, u64 copy_size) { + VkBufferCopy copy_region; + copy_region.srcOffset = src_offset; + copy_region.dstOffset = dst_offset; + copy_region.size = copy_size; + + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst); + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + vkCmdCopyBuffer(temp_cmd_buffer, src_buf->handle, dst_buf->handle, 1, ©_region); + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) { + gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src); + gpu_texture* dst_tex = texture_pool_get(&context.resource_pools->textures, dst); + + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + + VkBufferImageCopy region; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + printf("Image details width: %d height %d\n", dst_tex->desc.extents.x, dst_tex->desc.extents.y); + region.imageOffset.x = 0; + region.imageOffset.y = 0; + region.imageOffset.z = 0; + region.imageExtent.width = dst_tex->desc.extents.x; + region.imageExtent.height = dst_tex->desc.extents.y; + region.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(temp_cmd_buffer, src_buf->handle, dst_tex->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); +} + texture_handle gpu_texture_create(texture_desc desc, const void* data) { VkDeviceSize image_size = desc.extents.x * desc.extents.y * 4; @@ -1380,6 +1461,91 @@ texture_handle gpu_texture_create(texture_desc desc, const void* data) { gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL); // Copy data into it buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, image_size); + + VkImage image; + VkDeviceMemory image_memory; + + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.extent.width = desc.extents.x; + image_create_info.extent.height = desc.extents.y; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.format = VK_FORMAT_R8G8B8A8_SRGB; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + + VK_CHECK( + vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image)); + + VkMemoryRequirements memory_reqs; + vkGetImageMemoryRequirements(context.device->logical_device, image, &memory_reqs); + + VkMemoryAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + alloc_info.allocationSize = memory_reqs.size; + alloc_info.memoryTypeIndex = + find_memory_index(memory_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(context.device->logical_device, &alloc_info, context.allocator, &image_memory); + + vkBindImageMemory(context.device->logical_device, image, image_memory, 0); + +gpu_buffer_destroy(staging); + + texture_handle handle; + gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); + texture->handle = image; + texture->memory = image_memory; + texture->size = image_size; + return handle; +} + +void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout) { + VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot(); + + VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; + barrier.dstQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index; + barrier.image = texture->handle; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.srcAccessMask = 0; // TODO + barrier.dstAccessMask = 0; // TODO + + VkPipelineStageFlags source_stage; + VkPipelineStageFlags dest_stage; + + if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && + new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + + } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { + FATAL("Unsupported image layout transition"); + return; + } + + vkCmdPipelineBarrier(temp_cmd_buffer, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier); + + vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); } size_t vertex_attrib_size(vertex_attrib_type attr) { diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 77b9f94..1e36ca3 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -6,6 +6,7 @@ #include "defines.h" #include "mem.h" #include "ral.h" +#include "ral_types.h" #define MAX_FRAMES_IN_FLIGHT 2 #define GPU_SWAPCHAIN_IMG_COUNT 2 @@ -102,3 +103,10 @@ typedef struct gpu_buffer { VkDeviceMemory memory; u64 size; } gpu_buffer; + +typedef struct gpu_texture { + VkImage handle; + VkDeviceMemory memory; + u64 size; + texture_desc desc; +} gpu_texture; diff --git a/src/renderer/ral.c b/src/renderer/ral.c index 6a417dd..304017d 100644 --- a/src/renderer/ral.c +++ b/src/renderer/ral.c @@ -1,22 +1 @@ #include "ral.h" - -/* typedef struct foo { */ -/* u32 a; */ -/* f32 b; */ -/* char c; */ -/* } foo; */ - -/* TYPED_POOL(gpu_buffer, buffer); */ - -/* typedef struct buffer_handle { */ -/* u32 raw; */ -/* } buffer_handle; */ - -/* typedef struct gpu_buffer gpu_buffer; */ -/* TYPED_POOL(gpu_buffer, buffer); */ -/* TYPED_POOL(gpu_texture, texture); */ - -/* struct resource_pools { */ -/* buffer_pool buffers; */ -/* texture_pool textures; */ -/* }; */ diff --git a/src/renderer/ral.h b/src/renderer/ral.h index da9eb93..48be83a 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -30,6 +30,7 @@ typedef struct gpu_renderpass gpu_renderpass; typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission typedef struct gpu_buffer gpu_buffer; +typedef struct gpu_texture gpu_texture; #define MAX_SHADER_DATA_LAYOUTS 5 #define MAX_BUFFERS 256 @@ -174,3 +175,9 @@ struct resource_pools { // Must be implemented by backends void resource_pools_init(arena* a, struct resource_pools* res_pools); + +void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, u64 dst_offset, + u64 copy_size); +void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst); + +// --- Helpers diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 5d4e88a..fc8bb8b 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -66,9 +66,6 @@ typedef struct texture_desc { u32x2 extents; } texture_desc; -typedef struct gpu_texture { -} gpu_texture; - typedef enum gpu_buffer_type { CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer? CEL_BUFFER_VERTEX, diff --git a/src/renderer/render.c b/src/renderer/render.c index b06620b..fc45093 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,11 +1,15 @@ -#include "render.h" #include +#include "maths_types.h" +#define STB_IMAGE_IMPLEMENTATION +#include + #include "camera.h" #include "file.h" #include "log.h" #include "mem.h" #include "ral.h" #include "ral_types.h" +#include "render.h" /** @brief Creates the pipelines built into Celeritas such as rendering static opaque geometry, debug visualisations, immediate mode UI, etc */ @@ -194,3 +198,41 @@ mesh mesh_create(geometry_data* geometry, bool free_on_upload) { return m; } + +// --- Textures + +texture_data texture_data_load(const char* path, bool invert_y) { + TRACE("Load texture %s", path); + + // load the file data + int width, height, num_channels; + stbi_set_flip_vertically_on_load(invert_y); + +#pragma GCC diagnostic ignored "-Wpointer-sign" + char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); + if (data) { + DEBUG("loaded texture: %s", path); + } else { + WARN("failed to load texture"); + } + + unsigned int channel_type; + if (num_channels == 4) { + channel_type = GL_RGBA; + } else { + channel_type = GL_RGB; + } + texture_desc desc = { .extents = { width, height }, + .format = CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, + .tex_type = CEL_TEXTURE_TYPE_2D }; + + return (texture_data){ .description = desc, .image_data = data }; +} + +texture_handle texture_data_upload(texture_data data, bool free_on_upload) { + texture_handle handle = gpu_texture_create(data.description, data.image_data); + if (free_on_upload) { + stbi_image_free(data.image_data); + } + return handle; +} diff --git a/src/renderer/render.h b/src/renderer/render.h index 5657fc1..9a7ff2f 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -34,9 +34,17 @@ typedef struct render_ctx { texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data); // Frontend Resources -// TODO: void texture_data_upload(texture_handle texture); -void texture_data_upload(texture* tex); -texture texture_data_load(const char* path, bool invert_y); +texture_data texture_data_load(const char* path, bool invert_y); + +/** + * @brief + * + * @param data + * @param free_on_upload frees the CPU-side pixel data stored in `data` + * @return texture_handle + */ +texture_handle texture_data_upload(texture_data data, bool free_on_upload); + buffer_handle buffer_create(const char* debug_name, u64 size); bool buffer_destroy(buffer_handle buffer); sampler_handle sampler_create(); @@ -49,7 +57,7 @@ void shader_hot_reload(const char* filepath); * @brief Creates buffers and returns a struct that holds handles to our resources * * @param geometry - * @param free_on_upload frees the CPU-side vertex/index data stored in geometry_data when we + * @param free_on_upload frees the CPU-side vertex/index data stored in `geometry` when we successfully upload that data to the GPU-side buffer * @return mesh */ diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index bd9ef3c..c6aec8e 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -69,16 +69,13 @@ typedef struct model { u32 mesh_count; } model; -typedef struct texture { - u32 texture_id; - char name[256]; +typedef struct texture {} texture; + +typedef struct texture_data { + texture_desc description; void* image_data; - void* backend_data; - u32 width; - u32 height; - u8 channel_count; - u32 channel_type; -} texture; +} texture_data; + typedef struct blinn_phong_material { char name[256]; -- cgit v1.2.3-70-g09d2