diff --git a/dependencies/HPML b/dependencies/HPML index 240d9beb..3aff354b 160000 --- a/dependencies/HPML +++ b/dependencies/HPML @@ -1 +1 @@ -Subproject commit 240d9beb5b6709fa50f3bbcd9a8a308ade1f86cc +Subproject commit 3aff354b3e5b1c3afbbd8fb553202457536fd39a diff --git a/dependencies/MeshLib b/dependencies/MeshLib index ca22bca2..d182e6cf 160000 --- a/dependencies/MeshLib +++ b/dependencies/MeshLib @@ -1 +1 @@ -Subproject commit ca22bca25f658d4e94ea96e171b8e4d6000fcca7 +Subproject commit d182e6cff004f61a7490c9b8fee28989a2f2046e diff --git a/include/renderer/Serialization.h b/include/renderer/Serialization.h new file mode 100644 index 00000000..b5fd90d2 --- /dev/null +++ b/include/renderer/Serialization.h @@ -0,0 +1,172 @@ +#ifndef _SERIALIZATION_H_ +#define _SERIALIZATION_H_ +#include +#include + +#define serialized_struct_set_property_int8(struct_name, property_name, value, object_ptr)\ +{\ + int8_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_int16(struct_name, property_name, value, object_ptr)\ +{\ + int16_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_int32(struct_name, property_name, value, object_ptr)\ +{\ + int32_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_int64(struct_name, property_name, value, object_ptr)\ +{\ + int64_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_uint8(struct_name, property_name, value, object_ptr)\ +{\ + uint8_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_uint16(struct_name, property_name, value, object_ptr)\ +{\ + uint16_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_uint32(struct_name, property_name, value, object_ptr)\ +{\ + uint32_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_uint64(struct_name, property_name, value, object_ptr)\ +{\ + uint64_t _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_float(struct_name, property_name, value, object_ptr)\ +{\ + float _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_double(struct_name, property_name, value, object_ptr)\ +{\ + double _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value, object_ptr);\ +} +#define serialized_struct_set_property_long_double(struct_name, property_name, value, object_ptr)\ +{\ + long double _value = value;\ + serialized_struct_set_property_value(struct_name, property_name,&_value);\ +} + +#define serialized_struct_get_property_int8(struct_name, property_name, object_ptr) (*(int8_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_int16(struct_name, property_name, object_ptr) (*(int16_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_int32(struct_name, property_name, object_ptr) (*(int32_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_int64(struct_name, property_name, object_ptr) (*(int64_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_uint8(struct_name, property_name, object_ptr) (*(uint8_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_uint16(struct_name, property_name, object_ptr) (*(uint16_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_uint32(struct_name, property_name, object_ptr) (*(uint32_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_uint64(struct_name, property_name, object_ptr) (*(uint64_t*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_float(struct_name, property_name, object_ptr) (*(float*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_double(struct_name, property_name, object_ptr) (*(double*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) +#define serialized_struct_get_property_long_double(struct_name, property_name, object_ptr) (*(long double*)serialized_struct_get_property_value(struct_name, property_name, object_ptr)) + +#define serialized_property_set_int8(property, value)\ +{\ + int8_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_int16(property, value)\ +{\ + int16_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_int32(property, value)\ +{\ + int32_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_int64(property, _value)\ +{\ + int64_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_uint8(property, value)\ +{\ + uint8_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_uint16(property, value)\ +{\ + uint16_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_uint32(property, value)\ +{\ + uint32_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_uint64(property, value)\ +{\ + uint64_t _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_float(property, value)\ +{\ + float _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_double(property, value)\ +{\ + double _value = value;\ + serialized_property_set_value(property, &_value);\ +} +#define serialized_property_set_long_double(property, value)\ +{\ + long double _value = value;\ + serialized_property_set_value(property, &_value);\ +} + +#define serialized_property_get_int8(property) (*(int8_t*)serialized_property_get_value(property)) +#define serialized_property_get_int16(property) (*(int16_t*)serialized_property_get_value(property)) +#define serialized_property_get_int32(property) (*(int32_t*)serialized_property_get_value(property)) +#define serialized_property_get_int64(property) (*(int64_t*)serialized_property_get_value(property)) +#define serialized_property_get_uint8(property) (*(uint8_t*)serialized_property_get_value(property)) +#define serialized_property_get_uint16(property) (*(uint16_t*)serialized_property_get_value(property)) +#define serialized_property_get_uint32(property) (*(uint32_t*)serialized_property_get_value(property)) +#define serialized_property_get_uint64(property) (*(uint64_t*)serialized_property_get_value(property)) +#define serialized_property_get_float(property) (*(float*)serialized_property_get_value(property)) +#define serialized_property_get_double(property) (*(double*)serialized_property_get_vaule(property)) +#define serialized_property_get_long_double(property) (*(long double*)serialized_property_get_value(property)) + +//loads the source file from secondary storage to the main memory for further parsing and compiling +void load_serialization_source_file(const char* name); +//sets the internal source buffer +//NOTE: if this buffer is allocated in the heap then it will not be automatically freed, you must have to free it explicitly +void set_serialization_source_buffer(const char* buffer); +//destoyes the allocated buffers for the serialized objects and properties +void destroy_serialization_data(); +//prints the details of a serialized property +void serialized_property_print(SerializedProperty* property); +//prints the details of a serialized struct along with its all property details +void serialized_struct_print(const char* name); +//serializes a struct and stores the retrieved (serialized information) information into a buffer of SerializedStructs +void struct_serialize(const char* struct_name); +//instantiates a new object of type typeof('serialized_struct_name') +//NOTE: that struct must be serialized first +void* instantiate_object(const char* struct_name); +//returns a pointer to the memory bock which corresponds to the property +void* serialized_property_get_value(SerializedProperty* property); +//sets a value of a memory block which corresponds to the property +void serialized_property_set_value(SerializedProperty* property, void* value); +//sets a value to a property in the serialized struct named as 'struct_name' +void serialized_struct_set_property_value(const char* struct_name, const char* property_name, void* value, void* object_ptr); +//returns a pointer to the memory block of property of the struct named as 'struct_name' +void* serialized_struct_get_property_value(const char* struct_name, const char* property_name, void* object_ptr); +//returns the property with name 'property_name' and you have to pass the base address of an object (struct) +SerializedProperty serialized_struct_get_property(const char* serialized_struct_name, const char* property_name, void* object_ptr); + +SerializedStruct* serialized_struct_get(const char* name); + + +#endif \ No newline at end of file diff --git a/include/renderer/assert.h b/include/renderer/assert.h index 0241f9d0..d40445d1 100644 --- a/include/renderer/assert.h +++ b/include/renderer/assert.h @@ -11,12 +11,22 @@ #endif #if defined(GLOBAL_DEBUG) +# define ASSERT_WRN(boolean, ...)\ + do\ + {\ + if(!(boolean))\ + {\ + printf("[Warning] Assertion Failed: ");\ + printf(__VA_ARGS__);\ + puts(calltrace_string());\ + }\ + } while(0) # define ASSERT(boolean, ...)\ do\ {\ if(!(boolean))\ {\ - printf("Assertion Failed: ");\ + printf("[Fetal Error] Assertion Failed: ");\ printf(__VA_ARGS__);\ puts(calltrace_string());\ exit(0);\ @@ -28,17 +38,25 @@ #if defined(GLOBAL_DEBUG) # define assert(condition) ASSERT((condition) != false, "\"%s\" is found to be false\n", #condition) +# define assert_wrn(condition) ASSERT_WRN((condition) != false, "\"%s\" is found to be false\n", #condition) # define ASSERT_NOT_NULL(ptr) assert(ptr != NULL) #else # define assert(condition) +# define assert_wrn(condition) # define ASSERT_NOT_NULL(ptr) #endif #if defined(GLOBAL_DEBUG) # define LOG_MSG(...) log_msg(__VA_ARGS__) # define LOG_ERR(...) log_err(__VA_ARGS__) +# define LOG_WRN(...) log_wrn(__VA_ARGS__) # define LOG_FETAL_ERR(...) log_fetal_err(__VA_ARGS__) #else +# define LOG_WRN(...)\ + {\ + printf("[Warning]: ");\ + printf(__VA_ARGS__);\ + } # define LOG_MSG(...)\ {\ printf("[Log]: ");\ diff --git a/include/renderer/defines.h b/include/renderer/defines.h index aebfb8fd..735872e3 100644 --- a/include/renderer/defines.h +++ b/include/renderer/defines.h @@ -17,3 +17,8 @@ typedef int8_t s8; typedef float f32; typedef double f64; +typedef u32 uint; + + + +#define INTERNAL diff --git a/include/renderer/defs.h b/include/renderer/defs.h new file mode 100644 index 00000000..82f7fcdb --- /dev/null +++ b/include/renderer/defs.h @@ -0,0 +1,96 @@ +#ifndef _DEFS_H_ +#define _DEFS_H_ +#include +#include +#include +#include +#include +#include +#include +#include + +#define TOKEN_BUFFER_SIZE 80 +#define SINGLE_LINE_COMMENT "\\" +#define MULTIPLE_LINE_COMMENT "/**/" +#define VERSION(__version__) + +#define _sizeof(serialized_property) __sizeof(serialized_property) + +#ifdef DEBUG +#define GOTO(label) { printf("Returned from %d\n", __LINE__); goto label; } +#else +#define GOTO(label) { goto label; } +#endif + +#define INCREMENT_CHAR_PTR(ch, amount)\ +do {\ + if((ch == NULL) || (*ch == 0)) { exit(0); puts("FILE ENDED"); }\ + ch += amount;\ + if(*ch == 0) { exit(0); puts("FILE ENDED");} } while (false) + +#ifdef DEBUG +#define throw_error(error_str, line_no, discription)\ +do{\ + printf("[ERROR]: Parsing error at line no %d \n%s: %s\n", line_no, error_str, discription);\ + exit(0);\ +}while(false) +#else +#define throw_error(error_str, line_no, description) +#endif + +typedef enum +{ + STSP_STATIC = 0, + STSP_REGISTER = 1, + STSP_EXTERN = 2, + STSP_NONE = 3 +} _storage_specifiers; + +typedef enum +{ + TYPE_SIGNED_INT8 = 0, //char, signed char + TYPE_SIGNED_INT16 = 1, //short, signed short, short int, signed short int + TYPE_SIGNED_INT32 = 2, //int, signed int, long, long int + TYPE_SIGNED_INT64 = 3, //long long int + + TYPE_UNSIGNED_INT8 = 4, //unsigned char + TYPE_UNSIGNED_INT16 = 5, //unsigned short, unsigned short int + TYPE_UNSIGNED_INT32 = 6, //unsigned int, unsigned long, unsigned long int + TYPE_UNSIGNED_INT64 = 7, //unsigned long long, unsigned long long int + + TYPE_FLOAT = 8, //float + TYPE_DOUBLE = 9, //double + TYPE_LONG_DOUBLE = 10, //long double + TYPE_STRING = 11, + TYPE_NONE = 12, + TYPE_INCOMPLETE = 13, + TYPE_VOID = 14 +} _type_specifiers; + +typedef struct +{ + bool is_pointer; //true if this property is a pointer + bool is_const; //true if this property is a constant property + _storage_specifiers storage; //extern, static, register + _type_specifiers type; //int, short, long ...etc + intptr_t address; //address of the property + char name[TOKEN_BUFFER_SIZE]; //name of the property +} SerializedProperty; + +typedef struct +{ + char name[TOKEN_BUFFER_SIZE]; //name of this struct + bool is_valid; //true, if this SerializedStruct is a valid serialized struct + uint32_t size; //size of the serialized struct in bytes + BUFFER* properties; //list of properties +} SerializedStruct; + +char* defs_load_text_from_file(const char* file_name); +char* defs_load_text_from_file_exclude_comments(const char* file_name); + +int __sizeof(SerializedProperty* property); +bool isstorage(const char* string, _storage_specifiers* storage); +bool istype(const char* string, _type_specifiers* type); + + +#endif \ No newline at end of file diff --git a/include/renderer/internal/vulkan/vulkan_buffer.h b/include/renderer/internal/vulkan/vulkan_buffer.h index e3f80c1a..1f406d6c 100644 --- a/include/renderer/internal/vulkan/vulkan_buffer.h +++ b/include/renderer/internal/vulkan/vulkan_buffer.h @@ -8,8 +8,9 @@ typedef struct renderer_t renderer_t; typedef struct vulkan_buffer_create_info_t { void* data; - uint32_t stride; uint32_t count; + uint32_t stride; + uint32_t size; VkBufferUsageFlags usage_flags; VkSharingMode sharing_mode; VkMemoryPropertyFlags memory_property_flags; @@ -19,6 +20,7 @@ typedef struct vulkan_buffer_t { VkBuffer handle; VkDeviceMemory memory; + uint32_t size; uint32_t stride; uint32_t count; } vulkan_buffer_t; @@ -29,3 +31,7 @@ vulkan_buffer_t* vulkan_buffer_create(renderer_t* renderer, vulkan_buffer_create void vulkan_buffer_create_no_alloc(renderer_t* renderer, vulkan_buffer_create_info_t* create_info, vulkan_buffer_t* buffer); void vulkan_buffer_destroy(vulkan_buffer_t* buffer, renderer_t* renderer); void vulkan_buffer_release_resources(vulkan_buffer_t* buffer); + +void vulkan_buffer_copy_data(vulkan_buffer_t* buffer, renderer_t* renderer, void* data, u32 start_offset, u32 size); +void* vulkan_buffer_map(vulkan_buffer_t* buffer, renderer_t* renderer); +void vulkan_buffer_unmap(vulkan_buffer_t* buffer, renderer_t* renderer); diff --git a/include/renderer/internal/vulkan/vulkan_descriptor_set.h b/include/renderer/internal/vulkan/vulkan_descriptor_set.h new file mode 100644 index 00000000..3a086f0b --- /dev/null +++ b/include/renderer/internal/vulkan/vulkan_descriptor_set.h @@ -0,0 +1,35 @@ + + +#pragma once + +#include +#include + +typedef struct renderer_t renderer_t; +typedef struct vulkan_texture_t vulkan_texture_t; +typedef struct vulkan_buffer_t vulkan_buffer_t; +typedef struct vulkan_pipeline_layout_t vulkan_pipeline_layout_t; + +typedef struct vulkan_descriptor_set_create_info_t +{ + VkDescriptorPool pool; + VkDescriptorSetLayout layout; +} vulkan_descriptor_set_create_info_t; + +typedef struct vulkan_descriptor_set_t +{ + VkDescriptorSet handle; + VkDescriptorPool pool; //the pool from it has been allocated +} vulkan_descriptor_set_t; + + + +vulkan_descriptor_set_t* vulkan_descriptor_set_new(); +vulkan_descriptor_set_t* vulkan_descriptor_set_create(renderer_t* renderer, vulkan_descriptor_set_create_info_t* create_info); +void vulkan_descriptor_set_create_no_alloc(renderer_t* renderer, vulkan_descriptor_set_create_info_t* create_info, vulkan_descriptor_set_t* set); +void vulkan_descriptor_set_destroy(vulkan_descriptor_set_t* set, renderer_t* renderer); +void vulkan_descriptor_set_release_resources(vulkan_descriptor_set_t* set); + +void vulkan_descriptor_set_bind(vulkan_descriptor_set_t* set, renderer_t* renderer, vulkan_pipeline_layout_t* pipeline_layout); +void vulkan_descriptor_set_write_texture(vulkan_descriptor_set_t* set, renderer_t* renderer, u32 binding_index, vulkan_texture_t* texture); +void vulkan_descriptor_set_write_uniform_buffer(vulkan_descriptor_set_t* set, renderer_t* renderer, u32 binding_index, vulkan_buffer_t* buffer); diff --git a/include/renderer/internal/vulkan/vulkan_graphics_pipeline.h b/include/renderer/internal/vulkan/vulkan_graphics_pipeline.h index fe3c6244..fc60d790 100644 --- a/include/renderer/internal/vulkan/vulkan_graphics_pipeline.h +++ b/include/renderer/internal/vulkan/vulkan_graphics_pipeline.h @@ -12,10 +12,10 @@ typedef struct vulkan_pipeline_layout_t vulkan_pipeline_layout_t; typedef struct vulkan_graphics_pipeline_create_info_t { - vulkan_shader_t** shaders; - u32 shader_count; + vulkan_shader_t* shader; uint32_t vertex_info_count; vulkan_vertex_info_t* vertex_infos; + VkDescriptorSetLayout vk_set_layout; } vulkan_graphics_pipeline_create_info_t; typedef struct vulkan_graphics_pipeline_t diff --git a/include/renderer/internal/vulkan/vulkan_material.h b/include/renderer/internal/vulkan/vulkan_material.h index a455b63d..703b8c75 100644 --- a/include/renderer/internal/vulkan/vulkan_material.h +++ b/include/renderer/internal/vulkan/vulkan_material.h @@ -9,13 +9,15 @@ typedef struct renderer_t renderer_t; typedef struct vulkan_graphics_pipeline_t vulkan_graphics_pipeline_t; typedef struct vulkan_shader_t vulkan_shader_t; typedef struct vulkan_texture_t vulkan_texture_t; +typedef struct vulkan_descriptor_set_t vulkan_descriptor_set_t; +typedef struct vulkan_buffer_t vulkan_buffer_t; typedef struct vulkan_material_create_info_t { - vulkan_shader_t** shaders; - u64 shader_count; + vulkan_shader_t* shader; uint32_t vertex_info_count; vulkan_vertex_info_t* vertex_infos; + VkDescriptorSetLayout vk_set_layout; } vulkan_material_create_info_t; typedef struct vulkan_material_t @@ -25,10 +27,10 @@ typedef struct vulkan_material_t void* self_reference; //self_reference //For recreating the graphics pipeline on render window resize - vulkan_material_create_info_t create_info; - - uint32_t descriptor_set_count; - VkDescriptorSet* descriptor_sets; + uint32_t vertex_info_count; + vulkan_vertex_info_t* vertex_infos; + + vulkan_shader_t* shader; vulkan_graphics_pipeline_t* graphics_pipeline; } vulkan_material_t; @@ -39,4 +41,5 @@ void vulkan_material_destroy(vulkan_material_t* material, renderer_t* renderer); void vulkan_material_release_resources(vulkan_material_t* material); void vulkan_material_bind(vulkan_material_t* material, renderer_t* renderer); void vulkan_material_push_constants(vulkan_material_t* material, renderer_t* renderer, void* bytes); -void vulkan_material_set_texture(vulkan_material_t* material, renderer_t* renderer, vulkan_texture_t* texture); +void vulkan_material_set_texture(vulkan_material_t* material, renderer_t* renderer, u32 binding_index, vulkan_texture_t* texture); +void vulkan_material_set_uniform_buffer(vulkan_material_t* material, renderer_t* renderer, u32 binding_index, vulkan_buffer_t* buffer); diff --git a/include/renderer/internal/vulkan/vulkan_pipeline_layout.h b/include/renderer/internal/vulkan/vulkan_pipeline_layout.h index 0e7355bc..4bc88426 100644 --- a/include/renderer/internal/vulkan/vulkan_pipeline_layout.h +++ b/include/renderer/internal/vulkan/vulkan_pipeline_layout.h @@ -2,19 +2,25 @@ #pragma once #include +#include typedef struct renderer_t renderer_t; +typedef struct vulkan_pipeline_layout_create_info_t +{ + /* For now, we will be using only one descriptor set layout per pipeline layout */ + VkDescriptorSetLayout vk_set_layout; +} vulkan_pipeline_layout_create_info_t; + typedef struct vulkan_pipeline_layout_t { - VkPipelineLayout pipeline_layout; - VkDescriptorSetLayout descriptor_set_layout; + VkPipelineLayout handle; } vulkan_pipeline_layout_t; vulkan_pipeline_layout_t* vulkan_pipeline_layout_new(); -vulkan_pipeline_layout_t* vulkan_pipeline_layout_create(renderer_t* renderer); -void vulkan_pipeline_layout_create_no_alloc(renderer_t* renderer, vulkan_pipeline_layout_t* pipeline_layout); +vulkan_pipeline_layout_t* vulkan_pipeline_layout_create(renderer_t* renderer, vulkan_pipeline_layout_create_info_t* create_info); +void vulkan_pipeline_layout_create_no_alloc(renderer_t* renderer, vulkan_pipeline_layout_create_info_t* create_info, vulkan_pipeline_layout_t* pipeline_layout); void vulkan_pipeline_layout_destroy(vulkan_pipeline_layout_t* pipeline_layout, renderer_t* renderer); void vulkan_pipeline_layout_release_resources(vulkan_pipeline_layout_t* pipeline_layout); diff --git a/include/renderer/internal/vulkan/vulkan_shader.h b/include/renderer/internal/vulkan/vulkan_shader.h index 13e2aab8..9cdf32ab 100644 --- a/include/renderer/internal/vulkan/vulkan_shader.h +++ b/include/renderer/internal/vulkan/vulkan_shader.h @@ -2,21 +2,38 @@ #pragma once #include +#include +#include +#include -typedef struct renderer_t renderer_t; +typedef struct vulkan_descriptor_set_t vulkan_descriptor_set_t; + +typedef struct vulkan_shader_resource_descriptor_t +{ + struct_descriptor_t handle; + bool is_opaque; + bool is_uniform; + u8 binding_number; + u8 set_number; + //NOTE: These bit descriptions are based on the vulkan_vulkan_shader_stage_t and vulkan_shader_stage_t enums + u8 stage_flags; // BIT(0) = vertex shader, BIT(1) = fragment shader, BIT(2) = geometry shader, BIT(3) = tessellation shader +} vulkan_shader_resource_descriptor_t; typedef struct vulkan_shader_t { - VkShaderModule module; - VkPipelineShaderStageCreateInfo stage; + vulkan_stage_shader_t** stage_shaders; + u8 stage_count; + //For now we will be using only one descriptor set and descriptor layout + vulkan_descriptor_set_t* vk_set; + VkDescriptorSetLayout vk_set_layout; + vulkan_shader_resource_descriptor_t* descriptors; + u16 descriptor_count; } vulkan_shader_t; +#define vulkan_shader_load(renderer, file_path) vulkan_shader_load_and_create(renderer, file_path) vulkan_shader_t* vulkan_shader_new(); -vulkan_shader_t* vulkan_shader_create(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t vulkan_shader_type); -void vulkan_shader_create_no_alloc(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t vulkan_shader_type, vulkan_shader_t* shader); -vulkan_shader_t* vulkan_shader_load_and_create(renderer_t* renderer, const char* file_name, vulkan_shader_type_t vulkan_shader_type); -void vulkan_shader_load_and_create_no_alloc(renderer_t* renderer, const char* file_name, vulkan_shader_type_t vulkan_shader_type, vulkan_shader_t* shader); - +vulkan_shader_t* vulkan_shader_create(renderer_t* renderer, BUFFER* vulkan_shader_binary); +vulkan_shader_t* vulkan_shader_load_and_create(renderer_t* renderer, const char* file_path); void vulkan_shader_destroy(vulkan_shader_t* shader, renderer_t* renderer); void vulkan_shader_release_resources(vulkan_shader_t* shader); diff --git a/include/renderer/internal/vulkan/vulkan_stage_shader.h b/include/renderer/internal/vulkan/vulkan_stage_shader.h new file mode 100644 index 00000000..0a8cdd41 --- /dev/null +++ b/include/renderer/internal/vulkan/vulkan_stage_shader.h @@ -0,0 +1,22 @@ + +#pragma once + +#include + +typedef struct renderer_t renderer_t; + +typedef struct vulkan_stage_shader_t +{ + VkShaderModule module; + VkPipelineShaderStageCreateInfo stage; +} vulkan_stage_shader_t; + + +vulkan_stage_shader_t* vulkan_stage_shader_new(); +vulkan_stage_shader_t* vulkan_stage_shader_create(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t shader_type); +void vulkan_stage_shader_create_no_alloc(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t shader_type, vulkan_stage_shader_t* shader); +vulkan_stage_shader_t* vulkan_stage_shader_load_and_create(renderer_t* renderer, const char* file_name, vulkan_shader_type_t shader_type); +void vulkan_stage_shader_load_and_create_no_alloc(renderer_t* renderer, const char* file_name, vulkan_shader_type_t shader_type, vulkan_stage_shader_t* shader); + +void vulkan_stage_shader_destroy(vulkan_stage_shader_t* shader, renderer_t* renderer); +void vulkan_stage_shader_release_resources(vulkan_stage_shader_t* shader); diff --git a/include/renderer/material.h b/include/renderer/material.h index 6b5546db..a4b96628 100644 --- a/include/renderer/material.h +++ b/include/renderer/material.h @@ -2,13 +2,13 @@ #pragma once typedef struct renderer_t renderer_t; -typedef struct shader_t shader_t; +typedef struct material_t material_t; #ifdef RENDERER_VULKAN_DRIVER -typedef struct vulkan_material_t vulkan_material_t; typedef struct vulkan_texture_t vulkan_texture_t; +typedef struct vulkan_shader_t vulkan_shader_t; typedef vulkan_texture_t texture_t; -typedef vulkan_material_t material_t; +typedef vulkan_shader_t shader_t; #endif #ifdef RENDERER_OPENGL_DRIVER @@ -23,35 +23,47 @@ typedef vulkan_material_t material_t; #error "Metal is not supported yet!" #endif -#define BIT64(x) (1ULL << (x)) -#define MATERIAL_TYPE_BITS_MASK (~(0xFFFFFFFFFFFFFFFFULL >> 3)) -#define MATERIAL_TYPE_BITS(value) (((~(0xFFFFFFFFFFFFFFFFULL >> 3)) & (value)) >> 61) -#define MATERIAL_ALIGN(value, index) (MATERIAL_TYPE_BITS_MASK & (value)) | (((0xFFFFFFFFFFFFFFFFULL >> 3) & (value)) << ((index) * MATERIAL_TYPE_BITS(value))) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MATERIAL_ALIGN(value, index) ((value) << ((index) * 5)) enum { - MATERIAL_U8 = BIT64(63) | 1, - MATERIAL_U16 = BIT64(63) | 2, - MATERIAL_U32 = BIT64(63) | 3, - MATERIAL_U64 = BIT64(63) | 4, - MATERIAL_S8 = BIT64(63) | 5, - MATERIAL_S16 = BIT64(63) | 6, - MATERIAL_S32 = BIT64(63) | 7, - MATERIAL_S64 = BIT64(63) | 8, - MATERIAL_F32 = BIT64(63) | 9, - MATERIAL_VEC2 = BIT64(63) | 10, - MATERIAL_VEC3 = BIT64(63) | 11, - MATERIAL_VEC4 = BIT64(63) | 12, - MATERIAL_MAT2 = BIT64(63) | 13, - MATERIAL_MAT3 = BIT64(63) | 14, - MATERIAL_MAT4 = BIT64(63) | 15, - - MATERIAL_IVEC2 = BIT64(63) | BIT64(61) | 16, - MATERIAL_IVEC3 = BIT64(63) | BIT64(61) | 17, - MATERIAL_IVEC4 = BIT64(63) | BIT64(61) | 18, - MATERIAL_UVEC2 = BIT64(63) | BIT64(61) | 19, - MATERIAL_UVEC3 = BIT64(63) | BIT64(61) | 20, - MATERIAL_UVEC4 = BIT64(63) | BIT64(61) | 21, + MATERIAL_U8 = 1ULL, + MATERIAL_U16 = 2ULL, + MATERIAL_U32 = 3ULL, + MATERIAL_U64 = 4ULL, + MATERIAL_S8 = 5ULL, + MATERIAL_S16 = 6ULL, + MATERIAL_S32 = 7ULL, + MATERIAL_S64 = 8ULL, + MATERIAL_F32 = 9ULL, + MATERIAL_VEC2 = 10ULL, + MATERIAL_VEC3 = 11ULL, + MATERIAL_VEC4 = 12ULL, + MATERIAL_MAT2 = 13ULL, + MATERIAL_MAT3 = 14ULL, + MATERIAL_MAT4 = 15ULL, + + MATERIAL_IVEC2 = 16ULL, + MATERIAL_IVEC3 = 17ULL, + MATERIAL_IVEC4 = 18ULL, + MATERIAL_UVEC2 = 19ULL, + MATERIAL_UVEC3 = 20ULL, + MATERIAL_UVEC4 = 21ULL, MATERIAL_POSITION = MATERIAL_ALIGN(MATERIAL_VEC3, 0), MATERIAL_NORMAL = MATERIAL_ALIGN(MATERIAL_VEC3, 1), @@ -74,4 +86,51 @@ void material_release_resources(material_t* material); void material_bind(material_t* material, renderer_t* renderer); void material_push_constants(material_t* material, renderer_t* renderer, void* bytes); -void material_set_texture(material_t* material, renderer_t* renderer, texture_t* texture); + +typedef struct material_field_handle_t +{ + u16 descriptor_index; + struct_field_handle_t field_handle; +} material_field_handle_t; + +material_field_handle_t material_get_field_handle(material_t* material, const char* name); +void material_set_floatH(material_t* material, material_field_handle_t handle, float value); +void material_set_intH(material_t* material, material_field_handle_t handle, int value); +void material_set_uintH(material_t* material, material_field_handle_t handle, uint value); +void material_set_vec2H(material_t* material, material_field_handle_t handle, vec2_t(float) v); +void material_set_vec3H(material_t* material, material_field_handle_t handle, vec3_t(float) v); +void material_set_vec4H(material_t* material, material_field_handle_t handle, vec4_t(float) v); +void material_set_mat2H(material_t* material, material_field_handle_t handle, mat2_t(float) m); +void material_set_mat4H(material_t* material, material_field_handle_t handle, mat4_t(float) m); +void material_set_texture2dH(material_t* material, material_field_handle_t handle, texture_t* texture); + +void material_set_float(material_t* material, const char* name, float value); +void material_set_int(material_t* material, const char* name, int value); +void material_set_uint(material_t* material, const char* name, uint value); +void material_set_vec2(material_t* material, const char* name, vec2_t(float) v); +void material_set_vec3(material_t* material, const char* name, vec3_t(float) v); +void material_set_vec4(material_t* material, const char* name, vec4_t(float) v); +void material_set_mat2(material_t* material, const char* name, mat2_t(float) m); +void material_set_mat4(material_t* material, const char* name, mat4_t(float) m); +void material_set_texture2d(material_t* material, const char* name, texture_t* texture); + + +float material_get_floatH(material_t* material, material_field_handle_t handle); +int material_get_intH(material_t* material, material_field_handle_t handle); +uint material_get_uintH(material_t* material, material_field_handle_t handle); +vec2_t(float) material_get_vec2H(material_t* material, material_field_handle_t handle); +vec3_t(float) material_get_vec3H(material_t* material, material_field_handle_t handle); +vec4_t(float) material_get_vec4H(material_t* material, material_field_handle_t handle); +mat2_t(float) material_get_mat2H(material_t* material, material_field_handle_t handle); +mat4_t(float) material_get_mat4H(material_t* material, material_field_handle_t handle); +texture_t* material_get_texture2dH(material_t* material, material_field_handle_t handle); + +float material_get_float(material_t* material, const char* name); +int material_get_int(material_t* material, const char* name); +uint material_get_uint(material_t* material, const char* name); +vec2_t(float) material_get_vec2(material_t* material, const char* name); +vec3_t(float) material_get_vec3(material_t* material, const char* name); +vec4_t(float) material_get_vec4(material_t* material, const char* name); +mat2_t(float) material_get_mat2(material_t* material, const char* name); +mat4_t(float) material_get_mat4(material_t* material, const char* name); +texture_t* material_get_texture2d(material_t* material, const char* name); diff --git a/include/renderer/shader.h b/include/renderer/shader.h index af90ef42..5dc3bdc9 100644 --- a/include/renderer/shader.h +++ b/include/renderer/shader.h @@ -1,17 +1,30 @@ #pragma once -#include -#include +typedef struct renderer_t renderer_t; + +#ifdef RENDERER_VULKAN_DRIVER +typedef struct vulkan_shader_t vulkan_shader_t; +typedef vulkan_shader_t shader_t; +#endif + +#ifdef RENDERER_OPENGL_DRIVER +#error "OpenGL is not supported yet!" +#endif -typedef struct shader_t -{ - stage_shader_t** stage_shaders; - u8 stage_count; -} shader_t; +#ifdef RENDERER_DIRECTX_DRIVER +#error "DirectX is not supported yet!" +#endif +#ifdef RENDERER_METAL_DRIVER +#error "Metal is not supported yet!" +#endif + +#include +#include -shader_t* shader_create(renderer_t* renderer, stage_shader_t** stage_shaders, u8 stage_count); -shader_t* shader_load(renderer_t* renderer, const char* file_path); +#define shader_load(renderer, file_path) shader_load_and_create(renderer, file_path) +shader_t* shader_create(renderer_t* renderer, BUFFER* shader_binary); +shader_t* shader_load_and_create(renderer_t* renderer, const char* file_path); void shader_destroy(shader_t* shader, renderer_t* renderer); void shader_release_resources(shader_t* shader); diff --git a/include/renderer/stage_shader.h b/include/renderer/stage_shader.h deleted file mode 100644 index 152ad3d6..00000000 --- a/include/renderer/stage_shader.h +++ /dev/null @@ -1,42 +0,0 @@ - -#pragma once - -typedef struct renderer_t renderer_t; - -#ifdef RENDERER_VULKAN_DRIVER - -typedef struct vulkan_shader_t vulkan_shader_t; -typedef vulkan_shader_t stage_shader_t; - -#endif - -#ifdef RENDERER_OPENGL_DRIVER -#error "OpenGL is not supported yet!" -#endif - -#ifdef RENDERER_DIRECTX_DRIVER -#error "DirectX is not supported yet!" -#endif - -#ifdef RENDERER_METAL_DRIVER -#error "Metal is not supported yet!" -#endif - -#include - -/*This enumeration should be in sync with vulkan_shader_type_t*/ -typedef enum shader_stage_t -{ - SHADER_STAGE_VERTEX, - SHADER_STAGE_FRAGMENT, - SHADER_STAGE_GEOMETRY, - SHADER_STAGE_TESSELLATION -} shader_stage_t; - -stage_shader_t* stage_shader_new(); -stage_shader_t* stage_shader_create(renderer_t*, void* spirv, u32 length, shader_stage_t shader_stage); -void stage_shader_create_no_alloc(renderer_t*, void* spirv, u32 length, shader_stage_t shader_stage, stage_shader_t* shader); -stage_shader_t* stage_shader_load_and_create(renderer_t*, const char* file_name, shader_stage_t shader_stage); -void stage_shader_load_and_create_no_alloc(renderer_t*, const char* file_name, shader_stage_t shader_stage, stage_shader_t* shader); -void stage_shader_destroy(stage_shader_t* shader, renderer_t*); -void stage_shader_release_resources(stage_shader_t* shader); diff --git a/include/renderer/struct_descriptor.h b/include/renderer/struct_descriptor.h new file mode 100644 index 00000000..80267a17 --- /dev/null +++ b/include/renderer/struct_descriptor.h @@ -0,0 +1,356 @@ +/* + *----------------------- CPU LOW LEVEL STUFFS -----------------------------* + + NOT 0111 (decimal 7) 10101011 (decimal 171) + = 1000 (decimal 8) = 01010100 (decimal 84) + For unsigned integers, the bitwise complement of a number is the "mirror reflection" of the number across the half-way + point of the unsigned integer's range. For example, for 8-bit unsigned integers, NOT x = 255 - x, which can be visualized + on a graph as a downward line that effectively "flips" an increasing range from 0 to 255, to a decreasing range from 255 to 0. + A simple but illustrative example use is to invert a grayscale image where each pixel is stored as an unsigned integer + + + AND 0110 (decimal 6) + 0001 (decimal 1) + = 0000 (decimal 0) + Because 6 AND 1 is zero, 6 is divisible by two and therefore even. + + + XOR 0101 (decimal 5) + 0011 (decimal 3) + = 0110 (decimal 6) + The bitwise XOR may be used to invert selected bits in a register (also called toggle or flip). + Any bit may be toggled by XORing it with 1. + Assembly language programmers and optimizing compilers sometimes use XOR as a short-cut to setting the value of a + register to zero. Performing XOR on a value against itself always yields zero, and on many architectures this + operation requires fewer clock cycles and memory than loading a zero value and saving it to the register. + + + Little-endian ordering: a left shift by 8 positions increases the byte address by 1, + a right shift by 8 positions decreases the byte address by 1. + Big-endian ordering: a left shift by 8 positions decreases the byte address by 1, + a right shift by 8 positions increases the byte address by 1. + + + A left arithmetic shift by n is equivalent to multiplying by 2n (provided the value does not overflow), + while a right arithmetic shift by n of a two's complement value is equivalent to taking the floor of division by 2n. + If the binary number is treated as ones' complement, then the same right-shift operation results in division by 2n + and rounding toward zero. + + + In a logical shift, zeros are shifted in to replace the discarded bits. Therefore, the logical and arithmetic left-shifts are exactly the same. + However, as the logical right-shift inserts value 0 bits into the most significant bit, instead of copying the sign bit, + it is ideal for unsigned binary numbers, while the arithmetic right-shift is ideal for signed two's complement binary numbers. + + + In C-family languages, the logical shift operators are "<<" for left shift and ">>" for right shift. + + In C#, the right-shift is an arithmetic shift when the first operand is an int or long. + If the first operand is of type uint or ulong, the right-shift is a logical shift + + @https://bits.stephan-brumme.com/ + CIRCULAR SHIFTS: + + Left-Rotate: uint32_t y = (x << n) | (x >> (32 - n)); + However, a shift by 0 bits results in undefined behavior in the right-hand expression (x >> (32 - n)) because 32 - 0 is 32, + and 32 is outside the range 0–31 inclusive. A second try might result in: + uint32_t y = n ? (x << n) | (x >> (32 - n)) : x; + where the shift amount is tested to ensure that it does not introduce undefined behavior. + However, the branch adds an additional code path and presents an opportunity for timing analysis and attack, + which is often not acceptable in high-integrity software. + In addition, the code compiles to multiple machine instructions, which is often less efficient than the processor's + native instruction. + To avoid the undefined behavior and branches under GCC and Clang, the following is recommended. + The pattern is recognized by many compilers, and the compiler will emit a single rotate instruction: + uint32_t y = (x << n) | (x >> (-n & 31)); + + Powers of two have one and only one bit set in their binary representation. + + ABSOLUTE VALUE OF A FLOAT (IEEE 754): + + 01: float myAbs(float x) + 02: { + 03: // copy and re-interpret as 32 bit integer + 04: int casted = *(int*) &x; + 05: // clear highest bit + 06: casted &= 0x7FFFFFFF; + 07: + 08: // re-interpret as float + 09: return *(float*)&casted; + 10: } + IEEE 754 floats' highest bit is the so-called sign bit: set to 1 for negative and 0 for positive numbers (incl. zero). + We just always set it to 0 − and we are done ! + The data type "float" requires 32 bits. Unfortunately, C does not allow any bit operations on floats. + To work around this issue, these 32 bits are re-interpreted as a 32 bit integer (line 4). + Then clearing the sign bit becomes simple and easy (line 6), however, the required code looks a bit nasty. + The built-in C function fabs() is translated into its FABS intrinsic when the data value is already on the FPU stack. + When data is stored in main memory and will remain there after fabs, the above trick outperforms the FPU by far + because one FPU load and one store operation can be saved. + These FPU load/store can vastly skew the performance chart, so please be careful with interpreting the results. + + ABSOLUTE VALUE OF A INTEGER: + + 01: int myAbs(int x) + 02: { + 03: const int bit31 = x >> 31; + 04: return (x ^ bit31) - bit31; + 05: } + All major processors represent negative numbers using the two's-complement which is defined as: + for x ≥ 0 → x + for x < 0 → NOT(x) + 1 + On the lowest level, computers provide logical bit shifts and arithmetic bit shifts. + Both shifts differ in handling how to fill the empty bits on the left side. + Logical shifts insert zeros while arithmetic shifts replicate the formerly highest bit. + Whereas signed integers are arithmetically shifted in C, unsigned integers are logically shifted. + In our case x is shifted arithmetically 31 times to the right which basically erases its value + and spreads the highest bit. That means, line 3 evaluates either to 0x00000000 (→ 0) or + 0xFFFFFFFF (→ −1). + Note: 32 bit systems require a shift by 31, 64 bit systems require a shift by 63 accordingly. + Consequently, line 4 turns out to be (x XOR 0) − 0 for positive values of x (including x=0). + x XOR 0 is still x and x − 0 remains x, too. So for positive x we get x ≥ 0 → x. + We saw that for negative values of x, bit31 is set to 0xFFFFFFFF. + Line 4 is then (x XOR 0xFFFFFFFF) − 0xFFFFFFFF. The bracketed XOR is equivalent to NOT(x) and + the constant −0xFFFFFFFF turns out to be −(-1) = +1. + In the end, the whole term is NOT(x) + 1, exactly what we wanted: for x < 0 → NOT(x) + 1 + Note: Current C++ compilers (Microsoft, GCC and Intel) implemented a special assembler code sequence + for abs which runs faster than the shown algorithm on x86 CPUs (see below for its source code). + + APPROXIMATE INVERSE OF A FLOAT: + + 01: float inverse(float x) + 02: { + 03: // re-interpret as a 32 bit integer + 04: unsigned int *i = (unsigned int*)&x; + 05: + 06: // adjust exponent + 07: *i = 0x7F000000 - *i; + 08: //*i = 0x7EEEEEEE - *i; + 09: + 10: return x; + 11: } + The standard IEEE-754 defines the binary layout of floating point numbers. + All major CPUs (or better to say: FPUs) follow this standard. + The data type "float" is a 32 bit wide floating point number consisting of a 23 bit mantissa, + an 8 bit exponent and a sign bit. Because the exponent can be negative, too, it is implemented using + a bias of 28-1 = 127. That means, 127 is added to the actual exponent to keep it always positive. + Written in a formula: x = sign * mantissa * 2exponent . + Note: To save one bit, the most significant bit of the mantissa is omitted because it is by definition always set to one. + Note, too: Binary exponents below −127 or above +127 cannot be represented by "float" (≈ ±1038 decimal). + The inverse can be written as: inverse(a) → a-1 or more specific: inverse(ab) → a-b . + If speed is more important than precision, we can approximate x-1 by computing sign * mantissa * 2-exponent . + The only difference to the original formula is the minus in front of exponent. + Because the mantissa remains unadjusted, the result will slightly deviate from the true inverse value. + In the end, a simple subtraction of the exponent bits, often performed in merely one CPU cycle, + does the trick (line 7): exponent → 127 − exponent + The constant 0x7F000000 represents 127 shifted left by 23 bits. + A brute force search revealed that a few constants expose a better overall accuracy and cut down the + error to about 4%. So far, 0x7EEEEEEE (line 8) seems to be the best candidate. + My brute force search didn't analyze all possible numbers, that means, there might be even better constants. + But you should keep in mind that only for 0x7F000000 we get inverse(1) = 1, which might be important for + many algorithms. No other constant can produce the same result for inverse(1). + + BIT COUNT: + + 01: unsigned int countBits(unsigned int x) + 02: { + 03: // count bits of each 2-bit chunk + 04: x = x - ((x >> 1) & 0x55555555); + 05: // count bits of each 4-bit chunk + 06: x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + 07: // count bits of each 8-bit chunk + 08: x = x + (x >> 4); + 09: // mask out junk + 10: x &= 0xF0F0F0F; + 11: // add all four 8-bit chunks + 12: return (x * 0x01010101) >> 24; + 13: } + + DETECTS ZERO BYTES INSIDE A 32 BIT INTEGER: + + 01: bool hasZeroByte(unsigned int x) + 02: { + 03: return ((x - 0x01010101) & ~x & 0x80808080) != 0; + 04: } + 05: + One of the most prominent example of detecting zeroes is strlen. To improve performance many bytes are examined in parallel. + The expression x − 0x01010101 sets the highest bit of a byte if a single input byte is within the input set + { 0x00, 0x81, 0x82, 0x83, ..., 0xFF } because the result will be { 0xFF, 0x80, 0x81, 0x82, ..., 0xFE } + On the other hand, ~x sets the highest bit of a byte if a single input byte is within the input set + { 0x00, 0x01, 0x02, 0x03, ..., 0x7F } because the result will be { 0xFF, 0xFE, 0xFD, 0xFC, ..., 0x80 } + The only value contained in both input sets is 0x00, exactly what we are looking for. + That means, only for x = 0 the highest bit is still set after ANDing: (x − 0x01010101) & ~x + Please do not be confused by the fact that a result ≠ 0 actually indicates a zero byte. + Then, all bits except for the highest bit of each byte are reset to zero using AND 0x80808080. + The resulting value is equal to zero if all (!) of these highest bits are zero. + If at least one is still set to 1, caused by a zero byte, the comparison ≠ 0 gives "true". + + ENDIANESS: + + 01: bool isLittleEndian() + 02: { + 03: // 16 bit value, represented as 0x0100 on Intel, and 0x0001 else + 04: short pattern = 0x0001; + 05: // access first byte, will be 1 on Intel, and 0 else + 06: return *(char*) &pattern == 0x01; + 07: } + Intel's x86 chips (and of cause compatible chips from AMD etc.) rely on "little endian": + Numeric values consisting of multiple bytes have increasing numeric significance with increasing memory addresses. + The opposite, called big endian, is true for Motorola chips, PowerPC and various other designs. + A few CPUs can even switch at runtime like ARM or newer PowerPC or x64. + The programming language C itself usually takes care of the endianness but whenever direct memory access is + requires by the software, it might be important to know the endianness of the system. + + + @https://en.wikipedia.org/wiki/Data_structure_alignment + DATA STRUCTURE ALIGNMENT + + A memory address a is said to be n-byte aligned when a is a multiple of n bytes (where n is a power of 2). + An n-byte aligned address would have a minimum of log2(n) least-significant zeros when expressed in binary. + A memory access is said to be aligned when the data being accessed is n bytes long and the datum address is n-byte aligned. + + COMPUTING PADDING + The following formulas provide the number of padding bytes required to align the start of a data structure + (where mod is the modulo operator): + padding = (align - (offset mod align)) mod align + aligned = offset + padding + = offset + ((align - (offset mod align)) mod align) + Since the alignment is by definition a power of two,[a] the modulo operation can be reduced to a bitwise boolean AND operation. + padding = (align - (offset & (align - 1))) & (align - 1) + = (-offset & (align - 1)) + aligned = (offset + (align - 1)) & ~(align - 1) + = (offset + (align - 1)) & -align + + + ALIGNMENTS WHEN COMPILING FOR 32 BIT X86 + + A char (one byte) will be 1-byte aligned. + A short (two bytes) will be 2-byte aligned. + An int (four bytes) will be 4-byte aligned. + A long (four bytes) will be 4-byte aligned. + A float (four bytes) will be 4-byte aligned. + A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option). + A long long (eight bytes) will be 4-byte aligned. + A long double (ten bytes with C++Builder and DMC, eight bytes with Visual C++, twelve bytes with GCC) will be 8-byte aligned with C++Builder, 2-byte aligned with DMC, 8-byte aligned with Visual C++, and 4-byte aligned with GCC. + Any pointer (four bytes) will be 4-byte aligned. (e.g.: char*, int*) + + ALIGNMENT DIFFERENCES WHEN COMPILING FOR 64 BIT X64 + + A long (eight bytes) will be 8-byte aligned. + A double (eight bytes) will be 8-byte aligned. + A long long (eight bytes) will be 8-byte aligned. + A long double (eight bytes with Visual C++, sixteen bytes with GCC) will be 8-byte aligned with Visual C++ and 16-byte aligned with GCC. + Any pointer (eight bytes) will be 8-byte aligned. + + struct MixedData //After compilation in 32-bit x86 machine + { + char Data1; //1 byte + char Padding1[1]; //1 byte for the following 'short' to be aligned on a 2 byte boundary + //assuming that the address where structure begins is an even number + short Data2; //2 bytes + int Data3; //4 bytes - largest structure member + char Data4; //1 byte + char Padding2[3]; //3 bytes to make total size of the structure 12 bytes + }; + + struct FinalPadShort + { + short s; + char n[3]; + }; //sizeof(FilePadShort) = 6 bytes on 32 bit machine + + For memory alignment and performance -> https://fylux.github.io/2017/07/11/Memory_Alignment/ + For portable data alignment -> https://www.codesynthesis.com/~boris/blog/2009/04/06/cxx-data-alignment-portability/ + + + *----------------------- GPU LOW LEVEL STUFFS -----------------------------* + + */ + +#pragma once + +#include +#define STRUCT_FIELD_MAX_NAME_SIZE 32 +#define STRUCT_DESCRIPTOR_MAX_NAME_SIZE 32 +#define STRUCT_FIELD_INVALID_HANDLE 0xFFFF + +enum +{ + // 0 = UNDEFINED + STRUCT_FIELD_FLOAT = 1, + STRUCT_FIELD_INT, + STRUCT_FIELD_UINT, + STRUCT_FIELD_VEC4, + STRUCT_FIELD_VEC3, + STRUCT_FIELD_VEC2, + STRUCT_FIELD_IVEC4, + STRUCT_FIELD_IVEC3, + STRUCT_FIELD_IVEC2, + STRUCT_FIELD_UVEC4, + STRUCT_FIELD_UVEC3, + STRUCT_FIELD_UVEC2, + STRUCT_FIELD_MAT4, + STRUCT_FIELD_MAT3, + STRUCT_FIELD_MAT2, + STRUCT_FIELD_MAX +}; + +typedef struct struct_field_t +{ + char name[STRUCT_FIELD_MAX_NAME_SIZE]; + u8 type; + u16 size; + u16 alignment; + + INTERNAL u16 offset; +} struct_field_t; + +typedef struct struct_descriptor_t +{ + char name[STRUCT_DESCRIPTOR_MAX_NAME_SIZE]; + u8 type; + u16 field_count; + struct_field_t* fields; + + INTERNAL void* ptr; + INTERNAL u32 size; +} struct_descriptor_t; + +typedef u16 struct_field_handle_t; + +void struct_descriptor_map(struct_descriptor_t* descriptor, void* ptr); +void struct_descriptor_unmap(struct_descriptor_t* descriptor); +void struct_descriptor_recalculate(struct_descriptor_t* descriptor); +u32 struct_descriptor_sizeof(struct_descriptor_t* descriptor); +struct_field_handle_t struct_descriptor_get_field_handle(struct_descriptor_t* descriptor, const char* field_name); +void struct_descriptor_set_value(struct_descriptor_t* descriptor, struct_field_handle_t handle, const void* const in); +void struct_descriptor_set_float(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); +void struct_descriptor_set_int(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in); +void struct_descriptor_set_uint(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in); +void struct_descriptor_set_vec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); +void struct_descriptor_set_vec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); +void struct_descriptor_set_vec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); +void struct_descriptor_set_ivec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in); +void struct_descriptor_set_ivec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in); +void struct_descriptor_set_ivec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in); +void struct_descriptor_set_uvec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in); +void struct_descriptor_set_uvec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in); +void struct_descriptor_set_uvec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in); +void struct_descriptor_set_mat4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); +void struct_descriptor_set_mat3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); +void struct_descriptor_set_mat2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in); + +void struct_descriptor_get_value(struct_descriptor_t* descriptor, struct_field_handle_t handle, void* const in); +void struct_descriptor_get_float(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); +void struct_descriptor_get_int(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out); +void struct_descriptor_get_uint(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out); +void struct_descriptor_get_vec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); +void struct_descriptor_get_vec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); +void struct_descriptor_get_vec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); +void struct_descriptor_get_ivec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out); +void struct_descriptor_get_ivec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out); +void struct_descriptor_get_ivec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out); +void struct_descriptor_get_uvec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out); +void struct_descriptor_get_uvec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out); +void struct_descriptor_get_uvec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out); +void struct_descriptor_get_mat4(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); +void struct_descriptor_get_mat3(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); +void struct_descriptor_get_mat2(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out); diff --git a/include/vulkan/vulkan_wrapper.h b/include/vulkan/vulkan_wrapper.h index 969a4928..a6c1c1e8 100644 --- a/include/vulkan/vulkan_wrapper.h +++ b/include/vulkan/vulkan_wrapper.h @@ -123,7 +123,7 @@ function_signature(VkDevice, vk_get_device, VkPhysicalDevice physicalDevice); function_signature(uint32_t, vk_get_graphics_queue_family_index, VkPhysicalDevice physicalDevice); function_signature(VkQueue, vk_get_device_queue, VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex); function_signature(VkSwapchainKHR, vk_get_swapchain, VkDevice device, VkSwapchainCreateInfoKHR* createInfo); -function_signature(VkShaderModule, vk_get_shader_module, VkDevice device, void* spirv, uint32_t length, vulkan_shader_type_t shader_type); +function_signature(VkShaderModule, vk_get_shader_module, VkDevice device, void* spirv, uint32_t length); function_signature(VkShaderModule, vk_get_shader_module_load, VkDevice device, const char* file_name); function_signature(VkPipelineShaderStageCreateInfo, vk_get_pipeline_shader_stage_create_info, VkShaderModule shader_module, vulkan_shader_type_t vulkan_shader_type, const char* entry_point); function_signature(VkPipelineVertexInputStateCreateInfo, vk_get_pipeline_vertex_input_state_create_info, uint32_t binding_count, uint32_t* strides, VkVertexInputRate* input_rates, vertex_attribute_binding_info_t* attribute_infos); @@ -143,7 +143,8 @@ function_signature(VkPipeline, vk_get_graphics_pipeline, VkDevice device, VkPipe VkPipelineMultisampleStateCreateInfo* multisampleState, VkPipelineColorBlendStateCreateInfo* colorBlendState); -function_signature(VkDescriptorPool, vk_get_descripter_pool, VkDevice device); +function_signature(VkDescriptorSetLayout, vk_get_descriptor_set_layout, VkDevice device, VkDescriptorSetLayoutBinding* bindings, uint32_t binding_count); +function_signature(VkDescriptorPool, vk_get_descriptor_pool, VkDevice device); function_signature(VkCommandPool, vk_get_command_pool, VkDevice device, uint32_t queueFamilyIndex); function_signature_void(VkAttachmentReference, vk_get_attachment_reference); function_signature_void(VkSubpassDependency, vk_get_subpass_dependency); @@ -219,7 +220,8 @@ function_signature(void, vk_dump_physical_device_extensions, VkPhysicalDevice* p #define vk_get_pipeline_dynamic_state_create_info(...) define_alias_function_void_macro(vk_get_pipeline_dynamic_state_create_info) #define vk_get_graphics_pipeline(...) define_alias_function_macro(vk_get_graphics_pipeline, __VA_ARGS__) -#define vk_get_descripter_pool(...) define_alias_function_macro(vk_get_descripter_pool, __VA_ARGS__) +#define vk_get_descriptor_set_layout(...) define_alias_function_macro(vk_get_descriptor_set_layout, __VA_ARGS__) +#define vk_get_descriptor_pool(...) define_alias_function_macro(vk_get_descriptor_pool, __VA_ARGS__) #define vk_get_command_pool(...) define_alias_function_macro(vk_get_command_pool, __VA_ARGS__) #define vk_get_attachment_reference(...) define_alias_function_void_macro(vk_get_attachment_reference) #define vk_get_subpass_dependency(...) define_alias_function_macro(vk_get_subpass_dependency, __VA_ARGS__) diff --git a/shader_compiler/TDD.txt b/shader_compiler/TDD.txt index 4e8b6c72..44f2b1c2 100644 --- a/shader_compiler/TDD.txt +++ b/shader_compiler/TDD.txt @@ -33,7 +33,7 @@ Shader Binary(sb) Format: --------------------------------------------------- 13 bytes -> SHADER BINARY -1 byte -> shader mask [ 1 -> vertex, 2 -> tessellation, 3 -> geometry, 4 -> fragment ] +1 byte -> shader mask [ BIT(0) -> vertex, BIT(1) -> tessellation, BIT(2) -> geometry, BIT(3) -> fragment ] 4 bytes -> Vertex shader offset 4 bytes -> Vertex shader length 4 bytes -> fragment shader offset diff --git a/shader_compiler/include/shader_compiler/compiler.h b/shader_compiler/include/shader_compiler/compiler.h index 63a7d3e5..db29afd7 100644 --- a/shader_compiler/include/shader_compiler/compiler.h +++ b/shader_compiler/include/shader_compiler/compiler.h @@ -14,6 +14,29 @@ enum SHADER_COMPILER_SHADER_STAGE_MAX }; +enum +{ + SHADER_COMPILER_BLOCK = 0, + SHADER_COMPILER_FLOAT, + SHADER_COMPILER_INT, + SHADER_COMPILER_UINT, + SHADER_COMPILER_DOUBLE, + SHADER_COMPILER_VEC4, + SHADER_COMPILER_VEC3, + SHADER_COMPILER_VEC2, + SHADER_COMPILER_IVEC4, + SHADER_COMPILER_IVEC3, + SHADER_COMPILER_IVEC2, + SHADER_COMPILER_UVEC4, + SHADER_COMPILER_UVEC3, + SHADER_COMPILER_UVEC2, + SHADER_COMPILER_MAT4, + SHADER_COMPILER_MAT3, + SHADER_COMPILER_MAT2, + SHADER_COMPILER_SAMPLER2D, + SHADER_COMPILER_SAMPLER3D +}; + #define shader_compiler_compile(...) define_alias_function_macro(shader_compiler_compile, __VA_ARGS__) function_signature(BUFFER*, shader_compiler_compile, const char* source, buf_ucount_t length); diff --git a/shader_compiler/resource/shaders/diffuse.glsl b/shader_compiler/resource/shaders/diffuse.glsl new file mode 100644 index 00000000..eb366dca --- /dev/null +++ b/shader_compiler/resource/shaders/diffuse.glsl @@ -0,0 +1,91 @@ +#section SETTINGS DEFAULT +wireframe true +line_thickness 5 +blend true +winding clockwise + +#section LAYOUT +vertex fragment [1, 4] uniform Matrices +{ + mat4 projection_matrix; + mat4 view_matrix; + mat4 model_matrix; +} matrices; + +fragment[2, 6] uniform sampler2D albedo_texture[2]; +fragment vertex[12, 34] uniform SceneData +{ + float time; + vec3 light_dir; + float light_intensity; +} scene_data[3]; + + +#section SHADER +#stage vertex + +#version 450 + +layout(push_constant) uniform Push +{ + mat4 mvp_matrix; +}; + +layout(set = 0, binding = 1) uniform UBO +{ + float time; +} ubo; + +layout(set = 0, binding = 0) uniform Matrices +{ + mat4 projection_matrix; + mat4 view_matrix; + mat4 model_matrix; +} matrices; + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec3 inColor; +layout(location = 3) in vec2 inTexCoord; + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec3 normal; +layout(location = 2) out vec2 texCoord; + +void main() +{ + vec4 v = mvp_matrix * vec4(inPosition, 1.0); + gl_Position = v; + fragColor = inColor; + normal = inNormal; + texCoord = inTexCoord; +} + + +#stage fragment + +#version 450 + +layout(location = 0) out vec3 color; + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec3 normal; +layout(location = 2) in vec2 texCoord; + +layout(set = 0, binding = 0) uniform sampler2D texSampler; + +layout(set = 0, binding = 1) uniform UBO +{ + float time; + vec3 light_dir; + float light_intensity; +} ubo1; + +float dot_product(vec3 v1, vec3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } + +void main() { + vec3 lightDir = normalize(vec3(1, -1, 0.1)); + color = fragColor * (max(0, dot(lightDir, -normal)) + 0.1f); + color = color * texture(texSampler, texCoord).xyz; +} + diff --git a/shader_compiler/resource/shaders/diffuse.shader b/shader_compiler/resource/shaders/diffuse.shader deleted file mode 100644 index 08e6d5ca..00000000 --- a/shader_compiler/resource/shaders/diffuse.shader +++ /dev/null @@ -1,50 +0,0 @@ - - -#stage vertex - -#version 450 -layout(push_constant) uniform Push -{ - mat4 mvp_matrix; -} push; - -layout(location = 0) in vec3 inPosition; -layout(location = 1) in vec3 inColor; -layout(location = 2) in vec3 inNormal; -layout(location = 3) in vec2 inTexCoord; - -layout(location = 0) out vec3 fragColor; -layout(location = 1) out vec3 normal; -layout(location = 2) out vec2 texCoord; - - -void main() -{ - vec4 v = push.mvp_matrix * vec4(inPosition, 1.0); - gl_Position = v; - fragColor = inColor; - normal = inNormal; - texCoord = inTexCoord; -} - - - -#stage fragment - -#version 450 - -layout(location = 0) out vec3 color; - -layout(location = 0) in vec3 fragColor; -layout(location = 1) in vec3 normal; -layout(location = 2) in vec2 texCoord; - -layout(binding = 0) uniform sampler2D texSampler; - -float dot_product(vec3 v1, vec3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } - -void main() { - vec3 lightDir = normalize(vec3(1, -1, 0.1)); - color = fragColor * (max(0, dot(lightDir, -normal)) + 0.1f); - color = color * texture(texSampler, texCoord).xyz; -} diff --git a/shader_compiler/source/compiler.c b/shader_compiler/source/compiler.c index ce764d6a..7806bc0e 100644 --- a/shader_compiler/source/compiler.c +++ b/shader_compiler/source/compiler.c @@ -7,10 +7,17 @@ #include //strncmp, strchr, strlen #include //isspace +#define log_u32(value) LOG_MSG("%s: %u\n", #value, value) + #define SHADER_BINARY_HEADER "SHADER BINARY" #define PREPROCESSOR '#' #define STAGE_DIRECTIVE "stage" +#define SECTION_DIRECTIVE "section" + +#define SECTION_SETTINGS "SETTINGS" +#define SECTION_LAYOUT "LAYOUT" +#define SECTION_SHADER "SHADER" #define SHADER_STAGE_VERTEX_STR stage_strings[SHADER_COMPILER_SHADER_STAGE_VERTEX] #define SHADER_STAGE_GEOMETRY_STR stage_strings[SHADER_COMPILER_SHADER_STAGE_GEOMETRY] @@ -24,8 +31,53 @@ typedef struct shader_source_t uint8_t stage; } shader_source_t; -#define generate_shader_binary(...) define_alias_function_macro(generate_shader_binary, __VA_ARGS__) -function_signature(static BUFFER*, generate_shader_binary, const char* const* stage_strings, shader_source_t* sources, uint8_t shader_count); +#define serialize_shader(...) define_alias_function_macro(serialize_shader, __VA_ARGS__) +function_signature(static void, serialize_shader, const char* const* stage_strings, shader_source_t* sources, uint8_t shader_count, BUFFER* buffer, BUFFER* offsets_buffer); +#define parse_shader(...) define_alias_function_macro(parse_shader, __VA_ARGS__) +function_signature(static const char*, parse_shader, const char* _source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer); +#define parse_layout(...) define_alias_function_macro(parse_layout, __VA_ARGS__) +function_signature(static const char*, parse_layout, const char* _source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer); +#define parse_settings(...) define_alias_function_macro(parse_settings, __VA_ARGS__) +function_signature(static const char*, parse_settings, const char* _source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer); + +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_SETTINGS_SECTION_FOUND "More than one settings section found" +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_LAYOUT_SECTION_FOUND "More than one layout section found" +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_SHADER_SECTION_FOUND "More than one shader section found" +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_VERTEX_SHADER_FOUND "More than one vertex shader found" +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_TESSELLATION_SHADER_FOUND "More than one tessellation shader found" +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_GEOMETRY_SHADER_FOUND "More than one geometry shader found" +#define SHADER_PARSE_ERROR_MORE_THAN_ONE_FRAGMENT_SHADER_FOUND "More than one fragment shader found" + +inline static void shader_parse_error(const char* string) +{ + LOG_FETAL_ERR("shader parse error: %s\n", string); +} + +enum +{ + SHADER_DATA_LAYOUT_PARSE_ERROR_UNSUPPORTED_SHADER_STAGE, + SHADER_DATA_LAYOUT_PARSE_ERROR_UNSUPPORTED_DIRECTIVE, + SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_ARRAY_DECLARATION, + SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_ARRAY_SIZE_INVALID, + SHADER_DATA_LAYOUT_PARSE_ERROR_ARRAY_SIZE_ZERO, + SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_SYMBOLE_IN_ARRAY_SIZE, + SHADER_DATA_LAYOUT_PARSE_ERROR_UNRECOGNIZED_DATA_TYPE, + SHADER_DATA_LAYOUT_PARSE_ERROR_SHADER_STAGE_NOT_FOUND +}; +static void shader_data_layout_parse_error(u32 err, u32 len, const char* string); +static u32 get_word_length(const char* string, const char delimiter); +static const char* parse_shader_stage(const char* string, u16* out_mask); +static const char* parse_array_operator(const char* string, u32* out_data, u8 required); +static const char* parse_type(const char* string, u16 mask, BUFFER* buffer, BUFFER* offsets_buffer); +static const char* parse_storage_qualifiers(const char* string, u16* out_info); +static void buffer_write_string(BUFFER* buffer, const char* string, u32 len, bool null_terminate); +static void buffer_write_u8(BUFFER* buffer, u8 value); +static void buffer_write_u16(BUFFER* buffer, u16 value); +static void buffer_write_u32(BUFFER* buffer, u32 value); +static void buffer_insert_offset(BUFFER* buffer, BUFFER* offsets_buffer, buf_ucount_t index); +static void buffer_insert_bytes(BUFFER* buffer, BUFFER* offsets_buffer, buf_ucount_t index, const u8* bytes, u32 count); +static bool is_empty(const char* start, const char* const end); +static void remove_comments(char* start, buf_ucount_t length); function_signature(BUFFER*, shader_compiler_load_and_compile, const char* file_path) { @@ -36,29 +88,707 @@ function_signature(BUFFER*, shader_compiler_load_and_compile, const char* file_p CALLTRACE_RETURN(shader_binary); } +/* + *------------------------INPUT STRING FORMAT------------------------------* + +#section SETTINGS + +#section LAYOUT + +vertex[0, 0] uniform +{ + float time; +}; + +vertex[0, 1] uniform +{ + mat4 projection_matrix; + mat4 view_matrix; + mat4 model_matrix; +}; + +fragment[0, 0] uniform sampler2D albedo_texture; +fragment[0, 1] uniform +{ + float time; + vec3 light_dir; + float light_intensity; +}; + +#section SHADER + +#stage vertex + +// vertex shader code goes here + +#stage fragment + +//fragment shader code goes here + +#stage geometry + +//geometry shader code goes here + +#stage tessellation + +//tessellation shader code goes here + + 0b 0000 0000 0101 0100 + 0x 54 + + *-------------------------------OUTPUT BINARY FORMAT---------------------------* + + Byte Index | Interpretation | Description + ___________|___________________________|________________________________________ + 0 | string of length 13 bytes | "SHADER BINARY" + | u32, section masks | 32 bits are divided into 3 bits group with BIT(0) = settings, BIT(1) = layout, BIT(2) = shader + | u32, settings offset | settings section offset if BIT(0) is set + | u32, layout offset | layout section offset if BIT(1) is set + | u32, shader offset | shader section offset if BIT(2) is set + 13 | shader mask byte | BIT(0) = vertex shader, BIT(1) = tessellation shader, BIT(2) = geometry shader, BIT(3) = fragment shader + 14 | u32, contains a number | vertex shader offset if BIT(0) is set + 18 | u32, contains a number | vertex shader length if BIT(0) is set + 22 | u32, contains a number | tessellation shader offset if BIT(1) is set + 26 | u32, contains a number | tessellation shader length if BIT(1) is set + 30 | u32, contains a number | geometry shader offset if BIT(2) is set + 34 | u32, contains a number | geometry shader length if BIT(2) is set + 40 | u32, contains a number | fragment shader offset if BIT(3) is set + 44 | u32, contains a number | fragment shader length if BIT(3) is set + */ function_signature(BUFFER*, shader_compiler_compile, const char* _source, buf_ucount_t length) { CALLTRACE_BEGIN(); - //Parse the _source string to separate vertex, tessellation, geometry, and fragment shaders - const char* stage_strings[SHADER_COMPILER_SHADER_STAGE_MAX] = { "vertex", "tessellation", "geometry", "fragment" }; - shader_source_t sources[SHADER_COMPILER_SHADER_STAGE_MAX]; memset(sources, 0, sizeof(shader_source_t) * SHADER_COMPILER_SHADER_STAGE_MAX); + + remove_comments((char*)_source, length); + + BUFFER* buffer = BUFcreate(NULL, sizeof(uint8_t), 0, 0); + BUFFER* offsets_buffer = BUFcreate(NULL, sizeof(buf_ucount_t), 0, 0); + + //Write the shader binary header "SHADER BINARY" to the buffer, 13 BYTES + buffer_write_string(buffer, (char*)SHADER_BINARY_HEADER, strlen(SHADER_BINARY_HEADER), false); + + //Reserve 4 BYTES for section mask + buf_ucount_t section_mask_index = buf_get_element_count(buffer); + buf_push_pseudo(buffer, 4); + + //Store index for section offsets to insert at later + buf_resize(buffer, buf_get_element_count(buffer) + 1); + buf_ucount_t section_offsets_index = buf_get_element_count(buffer); + const char* source = _source; - const char* temp = NULL; - shader_source_t* previous_source = NULL; - uint8_t shader_count = 0; + const char* temp1 = source; + const char* temp2 = source; + func_ptr_sig(const char* , parse, const char* source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer) = NULL; + u8 shader_section_count = 0; + u8 layout_section_count = 0; + u8 settings_section_count = 0; + u32 section_mask = 0x00; + u8 section_count = 0; while((source = strchr(source, PREPROCESSOR)) != NULL) { - temp = source - 1; + temp2 = source; source += 1; while((*source == ' ') || (*source == '\t')) source++; - if(strncmp(source, STAGE_DIRECTIVE, strlen(STAGE_DIRECTIVE)) != 0) + if(strncmp(source, SECTION_DIRECTIVE, strlen(SECTION_DIRECTIVE)) != 0) continue; - source += strlen(STAGE_DIRECTIVE); + source += strlen(SECTION_DIRECTIVE); while((*source == ' ') || (*source == '\t')) source++; - uint8_t count = 0; + uint32_t count = 0; while(!isspace(*source)) { source++; count++; } - if(count > strlen(SHADER_STAGE_TESSELLATION_STR)) + source -= count; + + if(strncmp(source, SECTION_SETTINGS, count) == 0) + { + LOG_MSG("SETTINGS section found, parsing ...\n"); + if(settings_section_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_SETTINGS_SECTION_FOUND); + source += count; + source = strchr(source, '\n'); + if(source == NULL) break; //if the file ended + source++; + const char* __source = source; + if(func_ptr(parse) != NULL) + { + buffer_insert_offset(buffer, offsets_buffer, section_offsets_index); + func_ptr(parse) params(temp1, temp2 - temp1, buffer, offsets_buffer); + } + func_ptr(parse) = func_ptr(parse_settings); + temp1 = __source; + settings_section_count++; + section_mask |= (1UL << 0) << (section_count * 3); + section_count++; + continue; + } + else if(strncmp(source, SECTION_LAYOUT, count) == 0) + { + LOG_MSG("LAYOUT section found, parsing ...\n"); + if(layout_section_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_LAYOUT_SECTION_FOUND); + source += count; + source = strchr(source, '\n'); + if(source == NULL) break; //if the file ended + source++; + const char* __source = source; + if(func_ptr(parse) != NULL) + { + buffer_insert_offset(buffer, offsets_buffer, section_offsets_index); + func_ptr(parse) params(temp1, temp2 - temp1, buffer, offsets_buffer); + } + func_ptr(parse) = func_ptr(parse_layout); + temp1 = __source; + layout_section_count++; + section_mask |= (1UL << 1) << (section_count * 3); + section_count++; + continue; + } + else if(strncmp(source, SECTION_SHADER, count) == 0) + { + LOG_MSG("SHADER section found, parsing ...\n"); + if(shader_section_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_SHADER_SECTION_FOUND); + source += count; + source = strchr(source, '\n'); + if(source == NULL) break; //if the file ended + source++; + const char* __source = source; + if(func_ptr(parse) != NULL) + { + buffer_insert_offset(buffer, offsets_buffer, section_offsets_index); + func_ptr(parse) params(temp1, temp2 - temp1, buffer, offsets_buffer); + } + func_ptr(parse) = func_ptr(parse_shader); + temp1 = __source; + shader_section_count++; + section_mask |= (1UL << 2) << (section_count * 3); + section_count++; + continue; + } + LOG_FETAL_ERR("shader parse error: Unsupported section: %.*s\n", count, source); + } + + if(shader_section_count == 0) + LOG_FETAL_ERR("shader parse error: Shader section not found\n"); + + if(func_ptr(parse) != NULL) + { + buffer_insert_offset(buffer, offsets_buffer, section_offsets_index); + source = func_ptr(parse) params(temp1, _source + length - temp1, buffer, offsets_buffer); + } + + //Write section mask to the buffer, 4 BYTES + *(u32*)buf_get_ptr_at(buffer, section_mask_index) = section_mask; + + //Reverse the offsets (array of u32) + u32* offsets = (u32*)buf_get_ptr_at(buffer, section_offsets_index); + for(u8 i = 0; i < (section_count >> 1); i++) + { + u32 temp = offsets[i]; + offsets[i] = offsets[section_count - i - 1]; + offsets[section_count - i - 1] = temp; + } + + buf_fit(buffer); + buf_free(offsets_buffer); + CALLTRACE_RETURN(buffer); +} + +static void buffer_insert_bytes(BUFFER* buffer, BUFFER* offsets_buffer, buf_ucount_t index, const u8* bytes, u32 size) +{ + buf_ucount_t count = buf_get_element_count(offsets_buffer); + for(buf_ucount_t i = 0; i < count; i++) + { + buf_ucount_t _index; + buf_get_at(offsets_buffer, i, &_index); + if(_index < index) + continue; + *(u32*)buf_get_ptr_at(buffer, _index) += size; + _index += size; + buf_set_at(offsets_buffer, i, &_index); + } + buf_insert_pseudo(buffer, index, size); + char* const ptr = buf_get_ptr_at(buffer, index); + memcpy(ptr, bytes, size); +} + +static void buffer_insert_offset(BUFFER* buffer, BUFFER* offsets_buffer, buf_ucount_t index) +{ + // update all the previous offsets + buf_ucount_t count = buf_get_element_count(offsets_buffer); + for(buf_ucount_t i = 0; i < count; i++) + { + buf_ucount_t _index; + buf_get_at(offsets_buffer, i, &_index); + if(_index < index) + continue; + *(u32*)buf_get_ptr_at(buffer, _index) += 4; + _index += 4; + buf_set_at(offsets_buffer, i, &_index); + } + + // register for next update + buf_push(offsets_buffer, &index); + + // insert 4 bytes into "buffer" + buf_insert_pseudo(buffer, index, 4); + *(u32*)buf_get_ptr_at(buffer, index) = buf_get_element_count(buffer); +} + +function_signature(static const char*, parse_settings, const char* _source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer) +{ + CALLTRACE_BEGIN(); + const char* string = _source; + const char* const end = string + length; + if(is_empty(string, end)) + { + LOG_MSG("SETTINGS section is empty, skipping\n"); + CALLTRACE_RETURN(_source + length); + } + CALLTRACE_RETURN(_source + length); +} + +/* + *---------------------------INPUT STRING FORMAT---------------------------* +vertex[0, 0] uniform Matrices +{ + mat4 projection_matrix; + mat4 view_matrix; + mat4 model_matrix; +} matrices; + +fragment[0, 0] uniform sampler2D albedo_texture; +fragment vertex [0, 1] uniform SceneData +{ + float time; + vec3 light_dir; + float light_intensity; +} scene_data; + + *------------------------------OUTPUT BINARY FORMAT----------------------------* + Byte Index | Interpretation | Description + _______________|___________________________|___________________________________________ + 0 | u16 | descriptor count + ... | array of u32 | offsets for each serialized descriptor + 0 | u8 | descriptor set number/index + 1 | u8 | descriptor binding number/index + 2 | u16 | BIT(15) set if the type is an opaque type + | | BIT(14) set if the type is an uniform + | | BIT(13) = vertex shader, BIT(12) = tessellation shader, BIT(11) = geometry shader, BIT(10) = fragment shader + | | Lower 8 Bits contains the type information + 3 | null terminated string | if the type is block then it would be block name + len0() + 4 | null terminated string | identifier name + len01() + 5 | u16 | contains number of members in the block if the type is a block + len01() + 7 | u32 | contains length of the array if the type is an array + */ +function_signature(static const char*, parse_layout, const char* _source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer) +{ + CALLTRACE_BEGIN(); + const char* string = _source; + const char* const end = string + length; + if(is_empty(string, end)) + { + LOG_MSG("LAYOUT section is empty, skipping\n"); + CALLTRACE_RETURN(_source + length); + } + + //Reserve 2 BYTES for descriptor count in the buffer + buf_ucount_t descriptor_count_index = buf_get_element_count(buffer); + buf_push_pseudo(buffer, 2); + + //Store the descriptor offsets index to insert at later + buf_resize(buffer, buf_get_element_count(buffer) + 1); + buf_ucount_t descriptor_offsets_index = buf_get_element_count(buffer); + + u16 descriptor_count = 0; + while(string < end) + { + while(isspace(*string)) string++; + if(string >= end) break; //end of the file reached + u16 shader_mask = 0; + u16 storage_mask = 0; + u32 set_info[2] = { 0xFF, 0xFF }; + + string = parse_shader_stage(string, &shader_mask); + string = parse_array_operator(string, &set_info[0], 2); + assert(set_info[0] < 0xFF); + assert(set_info[1] < 0xFF); + string = parse_storage_qualifiers(string, &storage_mask); + + //Write offset (byte count), 4 BYTES + buffer_insert_offset(buffer, offsets_buffer, descriptor_offsets_index); + log_u32(buf_get_element_count(buffer)); + + //Write descriptor set number/index, 1 BYTE + buffer_write_u8(buffer, (u8)set_info[0]); + + //Write descriptor binding number/index, 1 BYTE + buffer_write_u8(buffer, (u8)set_info[1]); + + string = parse_type(string, storage_mask | shader_mask, buffer, offsets_buffer); + descriptor_count++; + } + + //Write number of descriptor count, 2 BYTES + *(u16*)buf_get_ptr_at(buffer, descriptor_count_index) = descriptor_count; + log_u32(descriptor_count); + + //Reverse the descriptor_offsets (array of u32) + u32* descriptor_offsets = buf_get_ptr_at(buffer, descriptor_offsets_index); + for(u16 i = 0; i < (descriptor_count >> 1); i++) + { + u32 temp = descriptor_offsets[i]; + descriptor_offsets[i] = descriptor_offsets[descriptor_count - i - 1]; + descriptor_offsets[descriptor_count - i - 1] = temp; + } + CALLTRACE_RETURN(_source + length); +} + +/* + fragment[0, 0] uniform sampler2D albedo_texture; + fragment vertex [0, 1] uniform SceneData + { + float time; + vec3 light_dir; + float light_intensity; + } scene_data; + */ +static const char* parse_type(const char* string, u16 mask, BUFFER* buffer, BUFFER* offsets_buffer) +{ + while(isspace(*string)) string++; + u32 count = get_word_length(string, 0); + bool found = true; + u16 type; + buf_ucount_t identifier_name_index; + if(strncmp(string, "sampler2D", count) == 0) { type = (1UL << 15) | (u16)SHADER_COMPILER_SAMPLER2D; } + else if(strncmp(string, "sampler3D", count) == 0) { type = (1UL << 15) | (u16)SHADER_COMPILER_SAMPLER3D; } + else if(strncmp(string, "vec4", count) == 0) { type = (u16)SHADER_COMPILER_VEC4; } + else if(strncmp(string, "vec3", count) == 0) { type = (u16)SHADER_COMPILER_VEC3; } + else if(strncmp(string, "vec2", count) == 0) { type = (u16)SHADER_COMPILER_VEC2; } + else if(strncmp(string, "ivec4", count) == 0) { type = (u16)SHADER_COMPILER_IVEC4; } + else if(strncmp(string, "ivec3", count) == 0) { type = (u16)SHADER_COMPILER_IVEC3; } + else if(strncmp(string, "ivec2", count) == 0) { type = (u16)SHADER_COMPILER_IVEC2; } + else if(strncmp(string, "uvec4", count) == 0) { type = (u16)SHADER_COMPILER_UVEC4; } + else if(strncmp(string, "uvec3", count) == 0) { type = (u16)SHADER_COMPILER_UVEC3; } + else if(strncmp(string, "uvec2", count) == 0) { type = (u16)SHADER_COMPILER_UVEC2; } + else if(strncmp(string, "int", count) == 0) { type = (u16)SHADER_COMPILER_INT; } + else if(strncmp(string, "uint", count) == 0) { type = (u16)SHADER_COMPILER_UINT; } + else if(strncmp(string, "float", count) == 0) { type = (u16)SHADER_COMPILER_FLOAT; } + else if(strncmp(string, "mat4", count) == 0) { type = (u16)SHADER_COMPILER_MAT4; } + else if(strncmp(string, "mat3", count) == 0) { type = (u16)SHADER_COMPILER_MAT3; } + else if(strncmp(string, "mat2", count) == 0) { type = (u16)SHADER_COMPILER_MAT2; } + else + { + found = false; + const char* block_name = string; + string += count; + while(*string != '{') { + if(!isspace(*string)) + { + count = get_word_length(string, 0); + LOG_FETAL_ERR("shader layout parse error: Unexpected symbol \"%.*s\", '{' is expected\n", count, string); + } + string++; + } + if((count == 0) || is_empty(block_name, block_name + count)) + LOG_FETAL_ERR("shader layout parse error: Block name cannot be empty\n"); + string++; + type = (u16)SHADER_COMPILER_BLOCK; + + //Write type info to the buffer, 2 BYTES + buffer_write_u16(buffer, type | mask); + log_u32(type | mask); + + //Write block name to the buffer, count + 1 BYTES + buffer_write_string(buffer, block_name, count, true); + + identifier_name_index = buf_get_element_count(buffer); + + //Reserve 2 BYTES for element count in the buffer + buf_ucount_t index = buf_get_element_count(buffer); + buf_push_pseudo(buffer, 2); + + u16 num_elements = 0; + while(*string != '}') + { + u16 info; + string = parse_type(string, mask, buffer, offsets_buffer); + while(isspace(*string)) string++; + num_elements++; + } + + //Write number of elements to the buffer, 2 BYTES + *(u16*)buf_get_ptr_at(buffer, index) = num_elements; + + string++; + } + + if(found) + { + //Write type info to the buffer, 2 BYTES + buffer_write_u16(buffer, type | mask); + identifier_name_index = buf_get_element_count(buffer); + string += count; + } + + while(isspace(*string)) string++; + count = get_word_length(string, ';'); + if((count == 0) || is_empty(string, string + count)) + LOG_FETAL_ERR("shader layout parse error: Identifier name cannot be empty\n"); + + //Write identifier name to the buffer, count + 1 BYTES + char identifier_name[count + 1]; memcpy(identifier_name, string, count); identifier_name[count] = 0; + buffer_insert_bytes(buffer, offsets_buffer, identifier_name_index, identifier_name, count + 1); + LOG_MSG("Identifier: %s\n", identifier_name); + + string += count; + while(*string != ';') + { + if(!isspace(*string)) + { + count = get_word_length(string, 0); + LOG_FETAL_ERR("shader layout parse error: Expected ';' before \"%.*s\"\n", count, string); + } + string++; + } + string++; + return string; +} + +static const char* parse_storage_qualifiers(const char* string, u16* out_info) +{ + while(isspace(*string)) string++; + u16 mask = 0; + u32 count = get_word_length(string, 0); + if(strncmp(string, "uniform", count) == 0) + mask |= (1UL << 14); + else + LOG_FETAL_ERR("shader data layout parse error: Unrecognized storage qualifier \"%.*s\"\n", count, string); + *out_info = mask; + return string + count; +} + +static const char* parse_shader_stage(const char* string, u16* out_mask) +{ + const char* stage_strings[SHADER_COMPILER_SHADER_STAGE_MAX] = { "vertex", "tessellation", "geometry", "fragment" }; + u32 count = 0; + u16 mask = 0; + u8 stage_count = 0; + while(true) + { + while(isspace(*string)) string++; + count = get_word_length(string, '['); + if(count == 0) break; + if(strncmp(string, SHADER_STAGE_VERTEX_STR, count) == 0) + mask |= 1UL << (13 - SHADER_COMPILER_SHADER_STAGE_VERTEX); + else if(strncmp(string, SHADER_STAGE_TESSELLATION_STR, count) == 0) + mask |= 1UL << (13 - SHADER_COMPILER_SHADER_STAGE_TESSELLATION); + else if(strncmp(string, SHADER_STAGE_GEOMETRY_STR, count) == 0) + mask |= 1UL << (13 - SHADER_COMPILER_SHADER_STAGE_GEOMETRY); + else if(strncmp(string, SHADER_STAGE_FRAGMENT_STR, count) == 0) + mask |= 1UL << (13 - SHADER_COMPILER_SHADER_STAGE_FRAGMENT); + else break; + string += count; + stage_count++; + } + if(stage_count == 0) + LOG_FETAL_ERR("shader layout parse error: Unrecognized symbol \"%.*s\", expected shader stage!\n", count, string); + *out_mask = mask; + return string; +} + +static const char* parse_array_operator(const char* string, u32* out_data, u8 required) +{ + while(isspace(*string)) string++; + u8 count = 0; + u32 arr_len = 0; + bool found = false; + if(strncmp(string, "[", 1) == 0) + { + found = true; +PARSE_NUMBER: + string++; + while(isspace(*string)) string++; + u8 len = 0; + while(isdigit(*string)) { string++; len++; }; + char sub_str[len + 1]; + /* + WARNING: Don't use strncpy(sub_str, string - len, len) here! + strncpy: No null-character is implicitly appended at the end of destination if source is longer than num. + Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow). + */ + memcpy(sub_str, string - len, len); sub_str[len] = 0; + arr_len = strtoul(sub_str, NULL, 0); + out_data[count] = arr_len; + log_u32(arr_len); + count++; + if(count > required) + LOG_FETAL_ERR("shader layout parse error: More than required elements found in the array index operator, \"%u\"\n", arr_len); + while(*string != ']') + { + if(*string == ',') + goto PARSE_NUMBER; + if(!isspace(*string)) + shader_data_layout_parse_error(SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_SYMBOLE_IN_ARRAY_SIZE, 1, string + 1); + string++; + } + string++; + } + if(!found) + { + u32 len = get_word_length(string, 0); + LOG_FETAL_ERR("shader layout parse error: Expected open square bracket '[' before \"%.*s\"\n", count, string); + } + if(count < required) + LOG_FETAL_ERR("shader layout parse error: Less than required elements found in the array index operator, \"%u\"\n", arr_len); + return string; +} + +static u32 get_word_length(const char* string, const char delimiter) +{ + u32 count = 0; + while((!isspace(*string)) && (delimiter != (*string))) { string++; count++; } + return count; +} + +static void shader_data_layout_parse_error(u32 err, u32 len, const char* string) +{ + switch(err) + { + case SHADER_DATA_LAYOUT_PARSE_ERROR_UNSUPPORTED_SHADER_STAGE : LOG_FETAL_ERR("shader_data_layout parse error: Unsupported shader stage: \"%.*s\"\n", len, string - len); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_UNSUPPORTED_DIRECTIVE : LOG_FETAL_ERR("shader_data_layout parse error: Unsupported preprocessor directive \"%s\"\n", len, string - len); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_ARRAY_DECLARATION : LOG_FETAL_ERR("shader_data_layout parse error: Invalid array declaration\n"); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_ARRAY_SIZE_INVALID : LOG_FETAL_ERR("shader_data_layout parse error: Array size is invalid\n"); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_ARRAY_SIZE_ZERO : LOG_FETAL_ERR("shader_data_layout parse error: Array size can't be zero\n"); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_INVALID_SYMBOLE_IN_ARRAY_SIZE : LOG_FETAL_ERR("shader_data_layout parse error: Invalid symbol \"%.*s\" in array index operator\n", len, string - len); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_UNRECOGNIZED_DATA_TYPE : LOG_FETAL_ERR("shader_data_layout parse error: Unrecognised data type: \"%.*s\"\n", len, string - len); break; + case SHADER_DATA_LAYOUT_PARSE_ERROR_SHADER_STAGE_NOT_FOUND: LOG_FETAL_ERR("shader_data_layout parse error: Shader stage not found\n"); + default: LOG_FETAL_ERR("shader_data_layout parse error: Unkown\n"); break; + } +} + +static void buffer_write_string(BUFFER* buffer, const char* string, u32 len, bool null_terminate) +{ + buf_pushv(buffer, (char*)string, len); + if(!null_terminate) + return; + char null_char = 0; + buf_push(buffer, &null_char); +} + +static void buffer_write_u8(BUFFER* buffer, u8 value) +{ + assert(buf_get_element_size(buffer) == 1); + buf_push(buffer, &value); +} + +static void buffer_write_u16(BUFFER* buffer, u16 value) +{ + assert(buf_get_element_size(buffer) == 1); + buf_ucount_t index = buf_get_element_count(buffer); + buf_push_pseudo(buffer, 2); + *(u16*)buf_get_ptr_at(buffer, index) = value; +} + +static void buffer_write_u32(BUFFER* buffer, u32 value) +{ + assert(buf_get_element_size(buffer) == 1); + buf_ucount_t index = buf_get_element_count(buffer); + buf_push_pseudo(buffer, 4); + *(u32*)buf_get_ptr_at(buffer, index) = value; +} + +static bool is_empty(const char* start, const char* const end) +{ + bool empty = true; + while(start < end) + { + if(!isspace(*start)) + { + empty = false; + break; + } + ++start; + } + return empty; +} + +static void remove_comments(char* start, buf_ucount_t length) +{ + const char* const end = start + length; + bool single_line_comment_begin = false; + bool multiple_line_comment_begin = false; + + while(start < end) + { + if(!multiple_line_comment_begin && !single_line_comment_begin) + { + bool found = true; + if(strncmp(start, "//", 2) == 0) + single_line_comment_begin = true; + else if(strncmp(start, "/*", 2) == 0) + multiple_line_comment_begin = true; + else found = false; + if(found) + { + start[0] = ' '; + start[1] = ' '; + start++; + } + start++; + continue; + } + if(multiple_line_comment_begin) + { + if(strncmp(start, "*/", 2) == 0) + multiple_line_comment_begin = false; + start[0] = ' '; + start[1] = ' '; + start += 2; + continue; + } + else if(single_line_comment_begin) + { + const char* ptr = strchr(start, '\n'); + if(ptr == NULL) + ptr = end; + if(ptr != start) + memset(start, ' ', ptr - start); + start = (char*)(ptr + 1); + single_line_comment_begin = false; + continue; + } + } +} + +function_signature(static const char*, parse_shader, const char* _source, buf_ucount_t length, BUFFER* buffer, BUFFER* offsets_buffer) +{ + CALLTRACE_BEGIN(); + const char* string = _source; + if(is_empty(string, string + length)) + { + LOG_MSG("SHADER section is empty, skipping\n"); + CALLTRACE_RETURN(_source + length); + } + + //Parse the _source string to separate vertex, tessellation, geometry, and fragment shaders + const char* stage_strings[SHADER_COMPILER_SHADER_STAGE_MAX] = { "vertex", "tessellation", "geometry", "fragment" }; + shader_source_t sources[SHADER_COMPILER_SHADER_STAGE_MAX]; memset(sources, 0, sizeof(shader_source_t) * SHADER_COMPILER_SHADER_STAGE_MAX); + const char* temp = NULL; + shader_source_t* previous_source = NULL; + uint8_t shader_count = 0; + u8 vertex_shader_count = 0; + u8 tessellation_shader_count = 0; + u8 geometry_shader_count = 0; + u8 fragment_shader_count = 0; + while((string = strchr(string, PREPROCESSOR)) != NULL) + { + temp = string - 1; + string += 1; + while((*string == ' ') || (*string == '\t')) string++; + if(strncmp(string, STAGE_DIRECTIVE, strlen(STAGE_DIRECTIVE)) != 0) + continue; + string += strlen(STAGE_DIRECTIVE); + while((*string == ' ') || (*string == '\t')) string++; + uint32_t count = 0; + while(!isspace(*string)) { string++; count++; } + if(count > strlen(SHADER_STAGE_TESSELLATION_STR)) LOG_FETAL_ERR( "Shader parse error: Shader stage name must one of the followings:\n" "1. %s\n" "2. %s\n" @@ -69,60 +799,67 @@ function_signature(BUFFER*, shader_compiler_compile, const char* _source, buf_uc SHADER_STAGE_GEOMETRY_STR, SHADER_STAGE_FRAGMENT_STR ); - } if(previous_source != NULL) previous_source->length = temp - previous_source->source; - source -= count; - if(strncmp(source, SHADER_STAGE_VERTEX_STR, count) == 0) + string -= count; + if(strncmp(string, SHADER_STAGE_VERTEX_STR, count) == 0) { + if(vertex_shader_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_VERTEX_SHADER_FOUND); //set vertex shader - source = strchr(source, '\n') + 1; + string = strchr(string, '\n') + 1; sources[SHADER_COMPILER_SHADER_STAGE_VERTEX] = (shader_source_t) { - .source = source, + .source = string, .stage = SHADER_COMPILER_SHADER_STAGE_VERTEX, }; previous_source = &sources[SHADER_COMPILER_SHADER_STAGE_VERTEX]; shader_count++; + vertex_shader_count++; continue; } - if(strncmp(source, SHADER_STAGE_TESSELLATION_STR, count) == 0) + if(strncmp(string, SHADER_STAGE_TESSELLATION_STR, count) == 0) { + if(tessellation_shader_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_TESSELLATION_SHADER_FOUND); //set tessellation shader - source = strchr(source, '\n') + 1; + string = strchr(string, '\n') + 1; sources[SHADER_COMPILER_SHADER_STAGE_TESSELLATION] = (shader_source_t) { - .source = source, + .source = string, .stage = SHADER_COMPILER_SHADER_STAGE_TESSELLATION, }; previous_source = &sources[SHADER_COMPILER_SHADER_STAGE_TESSELLATION]; shader_count++; + tessellation_shader_count++; continue; } - if(strncmp(source, SHADER_STAGE_GEOMETRY_STR, count) == 0) + if(strncmp(string, SHADER_STAGE_GEOMETRY_STR, count) == 0) { + if(geometry_shader_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_GEOMETRY_SHADER_FOUND); //set geometry shader - source = strchr(source, '\n') + 1; + string = strchr(string, '\n') + 1; sources[SHADER_COMPILER_SHADER_STAGE_GEOMETRY] = (shader_source_t) { - .source = source, + .source = string, .stage = SHADER_COMPILER_SHADER_STAGE_GEOMETRY, }; previous_source = &sources[SHADER_COMPILER_SHADER_STAGE_GEOMETRY]; shader_count++; + geometry_shader_count++; continue; } - if(strncmp(source, SHADER_STAGE_FRAGMENT_STR, count) == 0) + if(strncmp(string, SHADER_STAGE_FRAGMENT_STR, count) == 0) { + if(fragment_shader_count > 0) shader_parse_error(SHADER_PARSE_ERROR_MORE_THAN_ONE_FRAGMENT_SHADER_FOUND); //set fragment shader - source = strchr(source, '\n') + 1; + string = strchr(string, '\n') + 1; sources[SHADER_COMPILER_SHADER_STAGE_FRAGMENT] = (shader_source_t) { - .source = source, + .source = string, .stage = SHADER_COMPILER_SHADER_STAGE_FRAGMENT, }; previous_source = &sources[SHADER_COMPILER_SHADER_STAGE_FRAGMENT]; shader_count++; + fragment_shader_count++; continue; } @@ -130,21 +867,13 @@ function_signature(BUFFER*, shader_compiler_compile, const char* _source, buf_uc } if(previous_source != NULL) previous_source->length = _source + length - previous_source->source; - CALLTRACE_RETURN(generate_shader_binary(stage_strings, sources, shader_count)); + serialize_shader(stage_strings, sources, shader_count, buffer, offsets_buffer); + CALLTRACE_RETURN(_source + length); } - -function_signature(static BUFFER*, generate_shader_binary, const char* const* stage_strings, shader_source_t* sources, uint8_t shader_count) +function_signature(static void, serialize_shader, const char* const* stage_strings, shader_source_t* sources, uint8_t shader_count, BUFFER* buffer, BUFFER* offsets_buffer) { CALLTRACE_BEGIN(); - BUFFER* shader_binary = BUFcreate(NULL, sizeof(uint8_t), 0, 0); - - //TODO: This should be like buf_pushv(shader_binary, SHADER_BINARY_HEADER, strlen(SHADER_BINARY_HEADER)) - //Write the shader binary header "SHADER BINARY" - uint8_t header_len = strlen(SHADER_BINARY_HEADER); - buf_resize(shader_binary, header_len); - memcpy(shader_binary->bytes, SHADER_BINARY_HEADER, header_len); - buf_set_element_count(shader_binary, header_len); uint8_t shader_mask = 0x00; for(uint8_t i = 0; i < SHADER_COMPILER_SHADER_STAGE_MAX; i++) @@ -153,15 +882,20 @@ function_signature(static BUFFER*, generate_shader_binary, const char* const* st if(source.length == 0) continue; shader_mask |= (0x01 << source.stage); } + //Write the shader mask 0 0 0 0 1 0 0 1 -> fragment & vertex shaders - buf_push(shader_binary, &shader_mask); + buf_push(buffer, &shader_mask); + + log_u32(shader_mask); //Allocate space for offsets and lengths for each shader SPIRV binary - uint64_t indices[shader_count]; + buf_ucount_t indices[shader_count]; for(uint8_t i = 0; i < shader_count; i++) { - indices[i] = buf_get_element_count(shader_binary); - buf_push_pseudo(shader_binary, 8); + indices[i] = buf_get_element_count(buffer); + buf_push_pseudo(buffer, 8); + // register for next update + buf_push(offsets_buffer, &indices[i]); } shaderc_compiler_t compiler = shaderc_compiler_initialize(); @@ -177,30 +911,34 @@ function_signature(static BUFFER*, generate_shader_binary, const char* const* st case SHADER_COMPILER_SHADER_STAGE_TESSELLATION: shader_type = shaderc_tess_control_shader; break; case SHADER_COMPILER_SHADER_STAGE_GEOMETRY: shader_type = shaderc_geometry_shader; break; case SHADER_COMPILER_SHADER_STAGE_FRAGMENT: shader_type = shaderc_fragment_shader; break; - default: LOG_FETAL_ERR("Shader parse error: stage \"%u\" is undefined or unsupported shader stage\n", source.stage); break; + default: LOG_FETAL_ERR("Shader compile error: stage \"%u\" is undefined or unsupported shader stage\n", source.stage); break; } shaderc_compilation_result_t result = shaderc_compile_into_spv(compiler, source.source, source.length, shader_type, stage_strings[source.stage], "main", options); assert(result != NULL); if(shaderc_result_get_compilation_status(result) != shaderc_compilation_status_success) - { LOG_FETAL_ERR("Shader compile error: %s | %s\n", stage_strings[source.stage], shaderc_result_get_error_message(result)); - } void* bytes = (void*)shaderc_result_get_bytes(result); assert(bytes != NULL); uint64_t length = shaderc_result_get_length(result); assert(length > 0); - uint32_t offset = buf_get_element_count(shader_binary); + uint32_t offset = buf_get_element_count(buffer); + log_u32(offset); + log_u32(length); + //Write offset - memcpy(buf_get_ptr_at(shader_binary, indices[j]), &offset, 4); + memcpy(buf_get_ptr_at(buffer, indices[j]), &offset, 4); + //Write length - memcpy(buf_get_ptr_at(shader_binary, indices[j]) + 4, &length, 4); + memcpy(buf_get_ptr_at(buffer, indices[j]) + 4, &length, 4); + //Write SPIRV binary - while(length > 0) { buf_push(shader_binary, bytes); bytes++; --length; } + buf_pushv(buffer, bytes, length); + shaderc_result_release(result); j++; } shaderc_compile_options_release(options); shaderc_compiler_release(compiler); - CALLTRACE_RETURN(shader_binary); + CALLTRACE_END(); } diff --git a/shared-dependencies/BufferLib b/shared-dependencies/BufferLib index 8bf0400b..ca58fa01 160000 --- a/shared-dependencies/BufferLib +++ b/shared-dependencies/BufferLib @@ -1 +1 @@ -Subproject commit 8bf0400b194a481b3c2c2b03f247a4ba33feb93c +Subproject commit ca58fa01a74924898ad07074bf6658814bd4ad42 diff --git a/source/Serialization.c b/source/Serialization.c new file mode 100644 index 00000000..6919d020 --- /dev/null +++ b/source/Serialization.c @@ -0,0 +1,506 @@ +#include + +static BUFFER* serialized_structs = NULL; +static const char* source_buffer = NULL; +static char* freeable_source_buffer = NULL; + +//static SerializedStruct* serialized_struct_get(const char* name); +static void __initialize_local_property_addresses(SerializedStruct* serialized_struct); +static SerializedStruct __serialize_properties(const char* struct_name, char* string_buffer); +static SerializedProperty* __serialized_struct_get_property(SerializedStruct* serialized_struct, const char* property_name); + +void serialized_property_print(SerializedProperty* property) +{ + const char* format_string = + " Property name: %s\n" + " type: %d\n" + " storage: %d\n" + " address: %d\n" + " pointer: %d\n" + " const: %d\n"; + + printf(format_string, + property->name, + property->type, + property->storage, + property->address, + property->is_pointer, + property->is_const); +} + +void serialized_struct_print(const char* name) +{ + BUFFER* previous_buffer = BUFget_binded_buffer(); + SerializedStruct* serialized_struct = serialized_struct_get(name); + if(serialized_struct == NULL) + { + #ifdef DEBUG + printf("[ERROR] You are trying to print unserialized struct or unexisting struct \"%s\"\n", name); + #endif + return; + } + + BUFbind(serialized_struct->properties); + + printf("Struct name: %s\n" + "Number of properties: %d\n", + serialized_struct->name, + BUFget_element_count() + ); + + for(int i =0 ;i < BUFget_element_count(); i++) + { + SerializedProperty* property = (SerializedProperty*)BUFgetptr_at(i); + serialized_property_print(property); + } + BUFbind(previous_buffer); +} + +void* instantiate_object(const char* serialized_struct_name) +{ + SerializedStruct* object_definition = serialized_struct_get(serialized_struct_name); + if(object_definition == NULL) + throw_error("There is no Serialized Struct present, please first serialized the struct ", __LINE__, serialized_struct_name); + void* allocated_memory = malloc((object_definition->size) * sizeof(uint8_t)); + + #ifdef DEBUG + printf("[LOG] Object instantiated successfully of type \"%s\" and size \"%d\" bytse\n", object_definition->name, object_definition->size); + #endif + return allocated_memory; +} +void set_serialization_source_buffer(const char* _buffer) +{ + if(freeable_source_buffer != NULL) + { + free(freeable_source_buffer); + freeable_source_buffer = NULL; + } + source_buffer = _buffer; +} +void load_serialization_source_file(const char* file_name) +{ + if(freeable_source_buffer != NULL) + free(freeable_source_buffer); + freeable_source_buffer = defs_load_text_from_file_exclude_comments(file_name); + if(freeable_source_buffer != NULL) + { + #ifdef DEBUG + printf("[LOG] serialization source file loaded successfully, file_name: \"%s\"\n", file_name); + #endif + } + source_buffer = freeable_source_buffer; +} + +void destroy_serialization_data() +{ + BUFFER* previous_buffer = BUFget_binded_buffer(); + if(serialized_structs != NULL) + { + BUFbind(serialized_structs); + for(int i = 0; i < BUFget_element_count(); i++) + { + SerializedStruct* serialized_struct = (SerializedStruct*)BUFgetptr_at(i); + BUFbind(serialized_struct->properties); + BUFfree(); + BUFbind(serialized_structs); + } + BUFfree(); + } + if(freeable_source_buffer != NULL) + free(freeable_source_buffer); + + BUFbind(previous_buffer); + #ifdef DEBUG + printf("[LOG] serialization data successfully destroyed\n"); + #endif +} + +void struct_serialize(const char* struct_name) +{ + if(source_buffer == NULL) + throw_error("Please load a source file first for serializing any object", __LINE__, ""); + BUFFER* previous_buffer = BUFget_binded_buffer(); + if(serialized_struct_get(struct_name) != NULL) + { + #ifdef DEBUG + puts("Already serialized"); + #endif + return; + } + const char* search_buffer = source_buffer; + int iteration_count = 0; +start_search: + ++iteration_count; + if(iteration_count > 10) + throw_error("searching failed", __LINE__, ""); + + char* struct_search = strstr(search_buffer, "struct"); + + if(struct_search != NULL) + { + INCREMENT_CHAR_PTR(struct_search, strlen("struct")); + + while(isspace(*struct_search)) + INCREMENT_CHAR_PTR(struct_search, 1); + + if(*struct_search == '{') + { + ++struct_search; + char* close_brace_search = struct_search; + while(*close_brace_search != '}') + { + // if(strstr(close_brace_search, "struct") != NULL) + // { + // search_buffer = close_brace_search + strlen("struct"); + // if(strchr(close_brace_search, 0) > search_buffer) + // GOTO(start_search); + // else throw_error("struct definition is not found for", __LINE__, struct_name); + // } + INCREMENT_CHAR_PTR(close_brace_search, 1); + } + INCREMENT_CHAR_PTR(close_brace_search, 1); + while(isspace(*close_brace_search)) + INCREMENT_CHAR_PTR(close_brace_search, 1); + + if(strncmp(close_brace_search, struct_name, strlen(struct_name)) != 0) + { + while((*close_brace_search != 0) && !isspace(*close_brace_search) && !(*close_brace_search == ';')) + INCREMENT_CHAR_PTR(close_brace_search, 1); + if(*close_brace_search == 0) + throw_error("struct definition is not found for", __LINE__, struct_name); + search_buffer = close_brace_search; + GOTO(start_search); + } + + while(isspace(*struct_search)) + INCREMENT_CHAR_PTR(struct_search, 1); + + if(*struct_search == 0) + throw_error("structure definition incomplete for", __LINE__, struct_name); + + //parse all the properties here; + SerializedStruct serialized_struct = __serialize_properties(struct_name, struct_search); + __initialize_local_property_addresses(&serialized_struct); + BUFbind(serialized_structs); + BUFpush(&serialized_struct); + + } + else if(strncmp(struct_search, struct_name, strlen(struct_name)) == 0) + { + + INCREMENT_CHAR_PTR(struct_search, strlen(struct_name)); + + while(isspace(*struct_search)) + INCREMENT_CHAR_PTR(struct_search, 1); + + if(*struct_search == 0) + throw_error("open brace not found for the struct definition for", __LINE__, struct_name); + + if(*struct_search != '{') + { + /* + Homework: + Try to implement your own exception and error handling system. + and also the errors and exceptions should be considered like objects, we can instantiation and then fire whenever we want. + */ + search_buffer = struct_search; + GOTO(start_search); + } + + INCREMENT_CHAR_PTR(struct_search, 1); + char* close_brace_search = struct_search; + while(*close_brace_search != '}') + { + // if(strstr(close_brace_search, "struct") != 0) + // { + // search_buffer = strstr(close_brace_search, "struct") + strlen("struct"); + // if(strchr(close_brace_search, 0) > search_buffer) + // GOTO(start_search); + // else + // throw_error("closing brace not found for the struct definition for", __LINE__, struct_name); + // } + INCREMENT_CHAR_PTR(close_brace_search, 1); + } + + + while(isspace(*struct_search)) + INCREMENT_CHAR_PTR(struct_search, 1); + + //parse all the properties; + SerializedStruct serialized_struct = __serialize_properties(struct_name, struct_search); + __initialize_local_property_addresses(&serialized_struct); + BUFbind(serialized_structs); + BUFpush(&serialized_struct); + + } + else + { + while(*struct_search != '{') + INCREMENT_CHAR_PTR(struct_search, 1); + INCREMENT_CHAR_PTR(struct_search, 1); + search_buffer = struct_search; + GOTO(start_search); + } + } + else + { + #ifdef DEBUG + printf("Iteration count: %d\n" , iteration_count); + #endif + throw_error("no struct definition found in the source file", __LINE__, __FILE__); + } + + BUFbind(previous_buffer); +} + +void* serialized_struct_get_property_value(const char* struct_name, const char* property_name, void* object_ptr) +{ + SerializedStruct* object_definition = serialized_struct_get(struct_name); + if(object_definition == NULL) + throw_error("No serialized struct definition is found named: ", __LINE__, struct_name); + + SerializedProperty* property = __serialized_struct_get_property(object_definition, property_name); + if(property->address == -1) + { + printf("[ERROR] You are trying to get value from an invalid property \"%s\", exception thrown at serialized_struct_get_property_value()\n", property->name); + return NULL; + } + void* shifted_pointer = (void*)(property->address + (intptr_t)object_ptr); + return shifted_pointer; +} + +void* serialized_property_get_value(SerializedProperty* property) +{ + if(property->address == -1) + { + printf("[ERROR] You are trying to get value from an invalid property \"%s\", exception thrown at serialized_property_get_value()\n", property->name); + return NULL; + } + return (void*)(property->address); +} + +void serialized_struct_set_property_value(const char* struct_name, const char* property_name, void* value, void* object_ptr) +{ + SerializedStruct* object_definition = serialized_struct_get(struct_name); + if(object_definition == NULL) + throw_error("No serialized struct definition is found named: ", __LINE__, struct_name); + + SerializedProperty* property = __serialized_struct_get_property(object_definition, property_name); + memcpy((uint8_t*)(property->address + (intptr_t)object_ptr), (uint8_t*)value, _sizeof(property)); +} + +void serialized_property_set_value(SerializedProperty* property, void* value) +{ + if(property->address == -1) + { + printf("[ERROR] You are trying to set a value to an invalid property \"%s\", exception thrown at serialized_property_set_value()\n", property->name); + return; + } + memcpy((uint8_t*)(property->address), (uint8_t*)value, _sizeof(property)); +} + +SerializedProperty serialized_struct_get_property(const char* struct_name,const char* property_name, void* object_ptr) +{ + BUFFER* previous_buffer = BUFget_binded_buffer(); + SerializedProperty serialized_property; + SerializedStruct* serialized_struct = serialized_struct_get(struct_name); + if(serialized_struct == NULL) + { + printf("[ERROR] No struct has been serialized of name \"%s\", exception thrown at 'serialized_struct_get_property()'\n", struct_name); + serialized_property.address = -1; + serialized_property.type = TYPE_NONE; + serialized_property.storage = STSP_NONE; + strcpy(serialized_property.name,property_name); + serialized_property.is_const = false; + serialized_property.is_pointer = false; + BUFbind(previous_buffer); + return serialized_property; + } + BUFbind(serialized_struct->properties); + + for(int i =0 ; i < BUFget_element_count(); i++) + { + if(strcmp(((SerializedProperty*)BUFgetptr_at(i))->name, property_name) == 0) + { + BUFget_at(i, &serialized_property); + serialized_property.address += (intptr_t)object_ptr; + BUFbind(previous_buffer); + return serialized_property; + } + // else printf("Property name: %s\n", ((SerializedProperty*)BUFgetptr_at(i))->name); + } + throw_error("no propery definition found named as", __LINE__, property_name); +} + +SerializedStruct* serialized_struct_get(const char* name) +{ + if(serialized_structs == NULL) + serialized_structs = BUFcreate(NULL, sizeof(SerializedStruct), 1, 0); + + BUFFER* previous_buffer = BUFget_binded_buffer(); + BUFbind(serialized_structs); + + for(int i = 0; i < BUFget_element_count(); i++) + { + SerializedStruct* serialized_struct = (SerializedStruct*)BUFgetptr_at(i); + if(!strcmp(serialized_struct->name, name)) + return serialized_struct; + } + BUFbind(previous_buffer); + return NULL; +} + +static SerializedProperty* __serialized_struct_get_property(SerializedStruct* serialized_struct, const char* property_name) +{ + BUFFER* previous_buffer = BUFget_binded_buffer(); + BUFbind(serialized_struct->properties); + for(int i = 0; i < BUFget_element_count(); i++) + if(strcmp(((SerializedProperty*)BUFgetptr_at(i))->name, property_name) == 0) + return (SerializedProperty*)BUFgetptr_at(i); + BUFbind(previous_buffer); + return NULL; +} + +static void __initialize_local_property_addresses(SerializedStruct* serialized_struct) +{ + BUFFER* previous_buffer = BUFget_binded_buffer(); + BUFbind(serialized_struct->properties); + int byte_count = 0; + int word_length = 8; //bytes + int word_count = 1; + for(int i = 0; i < BUFget_element_count(); i++) + { + SerializedProperty* property = (SerializedProperty*)BUFgetptr_at(i); + if((byte_count + _sizeof(property)) > (word_count * word_length)) + { + byte_count = word_count * word_length; + ++word_count; + } + property->address = byte_count; + byte_count += _sizeof(property); + } + serialized_struct->size = word_count * word_length; + BUFbind(previous_buffer); +} + +static SerializedStruct __serialize_properties(const char* struct_name, char* _buffer) +{ + SerializedStruct serialized_struct; + uint8_t bytes[BUF_BUFFER_OBJECT_SIZE]; + BUFFER* properties = NULL; + BUFFER* previous_buffer = BUFget_binded_buffer(); + char string_buffer[strlen(_buffer) + 1]; + strcpy(string_buffer, _buffer); + + if(strlen(string_buffer) > 2) + properties = BUFcreate(NULL, sizeof(SerializedProperty), 1, 0); + else + throw_error("string_buffer is not a valid string to parse any kind of property", __LINE__, "exception at __serialize_properties"); + + char* token = strtok(string_buffer, " \t\n"); + _storage_specifiers storage; + _type_specifiers type; + bool storage_checked = false; + bool type_checked = false; + SerializedProperty property; + property.is_const = false; + property.is_pointer = false; + strcpy(property.name, "\0"); + BUFbind(properties); + while(token != NULL) + { + if(strstr(token, "}") != NULL) + { + if(BUFget_element_count() == 0) + { + BUFfree(); + serialized_struct.is_valid = false; + serialized_struct.properties = NULL; + strcpy(serialized_struct.name,"\0"); + #ifdef DEBUG + printf("[Warning]: serialized struct \"%s\" hasn't any property, it's empty\n", struct_name); + #endif + } + else + { + serialized_struct.is_valid = true; + strcpy(serialized_struct.name, struct_name); + serialized_struct.properties = properties; + #ifdef DEBUG + printf("[LOG]: struct \"%s\" is serialized successfully\n", struct_name); + #endif + } + break; + } + if((!property.is_const) && (strcmp(token, "const") == 0)) + property.is_const = true; + else + if((!property.is_pointer) && ((strcmp(token,"*") == 0))) + property.is_pointer = true; + else + if(!storage_checked && !type_checked && (isstorage(token, &storage) == true)) + { + storage_checked = true; + property.storage = storage; + } + else + if(!type_checked) + { + char* _token = token; + char _buffer[strlen(token)]; + if(strchr(token, '*') != NULL) + { + strncpy(_buffer, token, strlen(token) - 1); + _buffer[strlen(token) - 1] = 0; + _token = _buffer; + property.is_pointer = true; + } + if(istype(_token, &type)) + { + if(type == TYPE_INCOMPLETE) + { + + } + else + { + type_checked = true; + property.type = type; + } + } + } + else + if(type_checked && (strcmp(token, "*") != 0)) + { + char* identifier_name = token; + if(*identifier_name == '*') + { + property.is_pointer = true; + INCREMENT_CHAR_PTR(identifier_name, 1); + } + int counter = 0; + while(*identifier_name != ';') + { + property.name[counter] = *identifier_name; + INCREMENT_CHAR_PTR(identifier_name, 1); + ++counter; + if(counter > 19) + throw_error("Property name length is larger than 20 characters", __LINE__, ""); + } + property.name[counter] = 0; + if(*identifier_name == ';') + { + if(!storage_checked) + property.storage = STSP_NONE; + BUFpush(&property); + type_checked = false; + storage_checked = false; + property.is_const = false; + property.is_pointer = false; + strcpy(property.name, "\0"); + } + } + token = strtok(NULL, " \t\n"); + } + BUFbind(previous_buffer); + return serialized_struct; +} \ No newline at end of file diff --git a/source/defs.c b/source/defs.c new file mode 100644 index 00000000..9c13719e --- /dev/null +++ b/source/defs.c @@ -0,0 +1,254 @@ +#include +#include + +int __sizeof(SerializedProperty* property) +{ + if(property->is_pointer) + return sizeof(intptr_t); + switch(property->type) + { + case TYPE_SIGNED_INT8: return sizeof(int8_t); break; + case TYPE_SIGNED_INT16: return sizeof(int16_t); break; + case TYPE_SIGNED_INT32: return sizeof(int32_t); break; + case TYPE_SIGNED_INT64: return sizeof(int64_t); break; + case TYPE_UNSIGNED_INT8: return sizeof(uint8_t); break; + case TYPE_UNSIGNED_INT16: return sizeof(uint16_t); break; + case TYPE_UNSIGNED_INT32: return sizeof(uint32_t); break; + case TYPE_UNSIGNED_INT64: return sizeof(uint64_t); break; + case TYPE_FLOAT: return sizeof(float); break; + case TYPE_DOUBLE: return sizeof(double); break; + case TYPE_LONG_DOUBLE: return sizeof(long double); break; + default: throw_error("type not found in _sizeof function ", __LINE__, ""); + } + return 0; //bytes +} +bool isstorage(const char* string, _storage_specifiers* storage) +{ + if(strlen(string) < strlen("static")) + { + *storage = STSP_NONE; + return false; + } + else if(strcmp(string, "extern") == 0) + { + *storage = STSP_EXTERN; ; + return true; + } + else if(strcmp(string, "static") == 0) + { + *storage = STSP_STATIC; ; + return true; + } + else if(strcmp(string, "register") == 0) + { + *storage = STSP_REGISTER; + return true; + } + else + { + *storage = STSP_NONE; + return false; + } +} + +bool istype(const char* string, _type_specifiers* type) +{ + if(strlen(string) < strlen("int")) + { + *type = TYPE_NONE; + return false; + } + if(!strcmp(string, "void")) + { + *type = TYPE_VOID; + return true; + } + if(!strcmp(string, "int8_t")) + { + *type = TYPE_SIGNED_INT8; + return true; + } + else if(!strcmp(string, "int16_t")) + { + *type = TYPE_SIGNED_INT16; + return true; + } + else if(!strcmp(string, "int32_t")) + { + *type = TYPE_SIGNED_INT32; + return true; + } + else if(!strcmp(string, "int64_t")) + { + *type = TYPE_SIGNED_INT64; + return true; + } + else if(!strcmp(string, "uint8_t")) + { + *type = TYPE_UNSIGNED_INT8; + return true; + } + else if(!strcmp(string, "uint16_t")) + { + *type = TYPE_UNSIGNED_INT16; + return true; + } + else if(!strcmp(string, "uint32_t")) + { + *type = TYPE_UNSIGNED_INT32; + return true; + } + else if(!strcmp(string, "uint64_t")) + { + *type = TYPE_UNSIGNED_INT64; + return true; + } + else if(!strcmp(string, "float")) + { + *type = TYPE_FLOAT; + return true; + } + else if(!strcmp(string, "double")) + { + *type = TYPE_DOUBLE; + return true; + } + else if(!strcmp(string, "long double")) + { + *type = TYPE_LONG_DOUBLE; + return true; + } + else if(!strcmp(string, "signed") || !strcmp(string, "unsigned") || !strcmp(string, "long")) + { + *type = TYPE_INCOMPLETE; + return true; + } + else if(!strcmp(string, "char") || !strcmp(string, "signed char")) + { + *type = TYPE_SIGNED_INT8; + return true; + } + else if(!strcmp(string, "short") || !strcmp(string, "signed short") || !strcmp(string, "short int") || !strcmp(string,"signed short int")) + { + *type = TYPE_SIGNED_INT16; + return true; + } + else if(!strcmp(string, "int") || !strcmp(string, "signed int") || !strcmp(string, "long") || !strcmp(string, "long int")) + { + *type = TYPE_SIGNED_INT32; + return true; + } + else if(!strcmp(string, "long long int") || !strcmp(string, "long long")) + { + *type = TYPE_SIGNED_INT64; + return true; + } + else if(!strcmp(string, "unsigned char")) + { + *type = TYPE_UNSIGNED_INT8; + return true; + } + else if(!strcmp(string, "unsigned short") || !strcmp(string, "unsigned short int")) + { + *type = TYPE_UNSIGNED_INT16; + return true; + } + else if(!strcmp(string, "unsigned int") || !strcmp(string, "unsigned long") || !strcmp(string, "unsigned long int")) + { + *type = TYPE_UNSIGNED_INT32; + return true; + } + else if(!strcmp(string, "unsigned long long") || !strcmp(string, "unsigned long long int")) + { + *type = TYPE_UNSIGNED_INT64; + return true; + } +} + +char* defs_load_text_from_file(const char* file_name) +{ + FILE* file = fopen(file_name, "r"); + if(file == NULL) + { + #ifdef DEBUG + printf("[Error] File loading failed, file_name: \"%s\", from load_text_from_file\n", file_name); + #endif + return NULL; + } + char bytes[BUF_BUFFER_OBJECT_SIZE]; + BUFFER* memory_buffer = BUFcreate_object(bytes); + BUFcreate(memory_buffer, sizeof(char), 1, 0); + BUFbind(memory_buffer); + char ch = getc(file); + while(ch != EOF) + { + BUFpush(&ch); + ch = getc(file); + } + BUFpush_char(0); + BUFfit(); + fclose(file); + return (char*)BUFget_ptr(); +} + +char* defs_load_text_from_file_exclude_comments(const char* file_name) +{ + FILE* file = fopen(file_name, "r"); + if(file == NULL) + { + #ifdef DEBUG + printf("[Error] File loading failed, file_name: \"%s\", from load_text_from_file_exclude_comments\n", file_name); + #endif + return NULL; + } + + char bytes[BUF_BUFFER_OBJECT_SIZE]; + BUFFER* memory_buffer = BUFcreate_object(bytes); + BUFcreate(memory_buffer, sizeof(char), 1, 0); + BUFbind(memory_buffer); + char ch = getc(file); + char previous_ch = ch; + bool single_line_comment_begin = false; + bool multiple_line_comment_begin = false; + + while(ch != EOF) + { + if(!single_line_comment_begin && !multiple_line_comment_begin) + BUFpush(&ch); + previous_ch = ch; + ch = getc(file); + + if(multiple_line_comment_begin && (previous_ch == '*') && (ch == '/')) + { + multiple_line_comment_begin = false; + BUFpop(NULL); + ch = getc(file); + ch = getc(file); + continue; + } + else if(single_line_comment_begin && (ch == '\n')) + { + single_line_comment_begin = false; + ch = getc(file); + continue; + } + + if(!multiple_line_comment_begin && !single_line_comment_begin && (previous_ch == '/') && (ch == '/')) + { + single_line_comment_begin = true; + BUFpop(NULL); + ch = getc(file); + continue; + } + if(!single_line_comment_begin && !multiple_line_comment_begin && (previous_ch == '/') && (ch == '*')) + { + multiple_line_comment_begin = true; + ch = getc(file); + continue; + } + } + BUFpush_char(0); + BUFfit(); + fclose(file); + return (char*)BUFget_ptr(); +} \ No newline at end of file diff --git a/source/renderer/material.c b/source/renderer/material.c index e15384f5..15b2d420 100644 --- a/source/renderer/material.c +++ b/source/renderer/material.c @@ -1,83 +1,67 @@ #include -#include -#include +#include +#include #include -#include #include #include +#include +#include + +#include #define VERTEX_INFO_COUNT 4 instantiate_static_stack_array(VkFormat); static void get_vulkan_constants(VkFormat* out_formats, u32* out_sizes, u32* out_indices); -static void __material_create_no_alloc(renderer_t* renderer, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, u32 shader_count, stage_shader_t** shaders, material_t* material); -static material_t* __material_create(renderer_t* renderer, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, u32 shader_count, stage_shader_t** shaders); +static material_t* __material_create(renderer_t* renderer, VkDescriptorSetLayout vk_set_layout, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, shader_t* shader); +static void __material_create_no_alloc(renderer_t* renderer, VkDescriptorSetLayout vk_set_layout, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, shader_t* shader, material_t* material); static u32 decode_attribute_count(u64 packed_attributes); -static void decode_vulkan_vertex_infos(u64 packed_attributes, VkVertexInputRate input_rate, vulkan_vertex_info_t* out_vertex_infos, VkFormat* formats, u32* offsets) -{ - VkFormat* vulkan_formats = stack_newv(u32, 26); - u32* sizes = stack_newv(u32, 22); - u32* indices = stack_newv(u32, 22); - get_vulkan_constants(vulkan_formats, sizes, indices); +static void decode_vulkan_vertex_infos(u64 packed_attributes, VkVertexInputRate input_rate, vulkan_vertex_info_t* out_vertex_infos, VkFormat* formats, u32* offsets); - u8 bits_per_type = MATERIAL_TYPE_BITS(packed_attributes); - packed_attributes &= ~MATERIAL_TYPE_BITS_MASK; - u64 bits_mask = ~(0xFFFFFFFFFFFFFFFFULL << bits_per_type); +static void get_record_and_field_name(const char* const full_name, char out_struct_name[STRUCT_DESCRIPTOR_MAX_NAME_SIZE], char out_field_name[STRUCT_FIELD_MAX_NAME_SIZE]); +static VkDescriptorSetLayoutBinding* get_set_layout_bindings(shader_t* shader, u32* out_binding_count); +static void material_set_up_shader_resources(material_t* material); - u32 i = 0; - while(packed_attributes != 0) - { - //WARNING: this should be like this: refp(vulkan_vertex_info_t, out_vertex_infos, i) - vulkan_vertex_info_t* info = &out_vertex_infos[i]; - u64 attribute_type = (packed_attributes & bits_mask); - if(attribute_type == 0) - { - packed_attributes >>= bits_per_type; - continue; - } - VkFormat vulkan_format = ref(VkFormat, vulkan_formats, ref(u32, indices, attribute_type)); - info->input_rate = input_rate; - info->size = ref(u32, sizes, attribute_type); - info->attribute_count = 1; - switch(attribute_type | BIT64(63)) - { - case MATERIAL_MAT3: - break; +static void unmap_descriptor(material_t* material, material_field_handle_t handle); +static struct_descriptor_t* map_descriptor(material_t* material, material_field_handle_t handle); - case MATERIAL_MAT4: - break; +#ifndef GLOBAL_DEBUG +# define check_precondition(material) +#else + static void check_precondition(material_t* material); +#endif - default:/*or MATERIAL_MAT2*/ - //WARNING: this should be like this: ref(VkFormat, formats, i) - formats[i] = vulkan_format; - //WARNING: this should be like this: refp(VkFormat, formats, i) - info->attribute_formats = &formats[i]; - //WARNING: this should be like this: ref(u32, offsets, i) - offsets[i] = 0; - //WARNING: this should be like this: refp(u32, offsets, i) - info->attribute_offsets = &offsets[i]; - break; - } - packed_attributes >>= bits_per_type; - i++; - } - stack_free(vulkan_formats); - stack_free(indices); -} +typedef struct uniform_resource_t +{ + vulkan_buffer_t buffer; + u16 descriptor_index; +} uniform_resource_t; +typedef struct material_t +{ + vulkan_material_t* handle; + uniform_resource_t* uniform_resources; + u16 uniform_resource_count; +} material_t; -material_t* material_new() { return vulkan_material_new(); } +material_t* material_new() +{ + material_t* material = heap_new(material_t); + memset(material, 0, sizeof(material_t)); + material->handle = vulkan_material_new(); + return material; +} material_t* material_create(renderer_t* renderer, material_create_info_t* create_info) { u32 per_vertex_attribute_count = decode_attribute_count(create_info->per_vertex_attributes); u32 per_instance_attribute_count = decode_attribute_count(create_info->per_instance_attributes); + log_u32(per_vertex_attribute_count); + log_u32(per_instance_attribute_count); u32 total_attribute_count = per_vertex_attribute_count + per_instance_attribute_count; - if((total_attribute_count) == 0) - { + if(total_attribute_count == 0) LOG_FETAL_ERR("Material create error: total_attribute_count is equals to 0\n"); - } VkFormat* formats = stack_newv(VkFormat, total_attribute_count + 5); u32* offsets = stack_newv(u32, total_attribute_count + 5); vulkan_vertex_info_t* vertex_infos = stack_newv(vulkan_vertex_info_t, total_attribute_count); @@ -85,63 +69,414 @@ material_t* material_create(renderer_t* renderer, material_create_info_t* create decode_vulkan_vertex_infos(create_info->per_vertex_attributes, VK_VERTEX_INPUT_RATE_VERTEX, vertex_infos, formats, offsets); if(per_instance_attribute_count > 0) decode_vulkan_vertex_infos(create_info->per_instance_attributes, VK_VERTEX_INPUT_RATE_INSTANCE, vertex_infos + per_vertex_attribute_count, formats + per_vertex_attribute_count, offsets + per_vertex_attribute_count); - material_t* material = __material_create(renderer, total_attribute_count, vertex_infos, create_info->shader->stage_count, create_info->shader->stage_shaders); + + material_t* material = __material_create(renderer, create_info->shader->vk_set_layout, total_attribute_count, vertex_infos, create_info->shader); + material_set_up_shader_resources(material); stack_free(formats); stack_free(offsets); stack_free(vertex_infos); return material; } -static material_t* __material_create(renderer_t* renderer, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, u32 shader_count, stage_shader_t** shaders) +static material_t* __material_create(renderer_t* renderer, VkDescriptorSetLayout vk_set_layout, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, shader_t* shader) { + material_t* material = material_new(); vulkan_material_create_info_t material_info = { - .shaders = shaders, - .shader_count = shader_count, + .shader = shader, .vertex_info_count = vertex_info_count, //NOTE: calling vulkan_material_create() creates a deep copy of vertex_infos - .vertex_infos = vertex_infos + .vertex_infos = vertex_infos, + .vk_set_layout = vk_set_layout }; - vulkan_material_t* material = vulkan_material_create(renderer, &material_info); + material->handle = vulkan_material_create(renderer, &material_info); return material; } -static void __material_create_no_alloc(renderer_t* renderer, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, u32 shader_count, stage_shader_t** shaders, material_t* material) +static void __material_create_no_alloc(renderer_t* renderer, VkDescriptorSetLayout vk_set_layout, u32 vertex_info_count, vulkan_vertex_info_t* vertex_infos, shader_t* shader, material_t* material) { vulkan_material_create_info_t material_info = { - .shaders = shaders, - .shader_count = shader_count, + .shader = shader, .vertex_info_count = vertex_info_count, //NOTE: calling vulkan_material_create_no_alloc() doesn't creates a deep copy of vertex_infos - .vertex_infos = vertex_infos + .vertex_infos = vertex_infos, + .vk_set_layout = vk_set_layout }; - vulkan_material_create_no_alloc(renderer, &material_info, material); + vulkan_material_create_no_alloc(renderer, &material_info, material->handle); +} + +static void material_set_up_shader_resources(material_t* material) +{ + assert(material->handle->shader != NULL); + if((material->handle->shader->descriptors == NULL) || (material->handle->shader->descriptor_count == 0)) + { + material->uniform_resources = NULL; + material->uniform_resource_count = 0; + return; + } + u16 count = material->handle->shader->descriptor_count; + vulkan_shader_resource_descriptor_t* descriptors = material->handle->shader->descriptors; + uniform_resource_t* uniform_resources = heap_newv(uniform_resource_t, count); + memset(uniform_resources, 0, sizeof(uniform_resource_t) * count); + for(u16 i = 0; i < count; i++) + { + vulkan_shader_resource_descriptor_t* descriptor = refp(vulkan_shader_resource_descriptor_t, descriptors, i); + uniform_resource_t* resource = &uniform_resources[i]; + if(descriptor->handle.type == SHADER_COMPILER_BLOCK) + { + u32 size = struct_descriptor_sizeof(&descriptor->handle); + vulkan_buffer_init(&resource->buffer); + resource->descriptor_index = i; + vulkan_buffer_create_info_t create_info = + { + .size = size, + .usage_flags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .memory_property_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + }; + vulkan_buffer_create_no_alloc(material->handle->renderer, &create_info, &resource->buffer); + vulkan_material_set_uniform_buffer(material->handle, material->handle->renderer, descriptor->binding_number, &resource->buffer); + } + else + resource->descriptor_index = 0xFFFF; + } + material->uniform_resources = uniform_resources; + material->uniform_resource_count = material->handle->shader->descriptor_count; } void material_destroy(material_t* material, renderer_t* renderer) { - vulkan_material_destroy(material, renderer); + vulkan_material_destroy(material->handle, renderer); + for(u16 i = 0; i < material->uniform_resource_count; i++) + { + if(material->uniform_resources[i].descriptor_index == 0xFFFF) + continue; + vulkan_buffer_destroy(&material->uniform_resources[i].buffer, renderer); + } } void material_release_resources(material_t* material) { - vulkan_material_release_resources(material); + vulkan_material_release_resources(material->handle); + if(material->uniform_resources != NULL) + heap_free(material->uniform_resources); + heap_free(material); } void material_bind(material_t* material, renderer_t* renderer) { - vulkan_material_bind(material, renderer); + vulkan_material_bind(material->handle, renderer); } void material_push_constants(material_t* material, renderer_t* renderer, void* bytes) { - vulkan_material_push_constants(material, renderer, bytes); + vulkan_material_push_constants(material->handle, renderer, bytes); +} + +material_field_handle_t material_get_field_handle(material_t* material, const char* name) +{ + assert(material != NULL); + assert(material->handle->shader != NULL); + + if(material->handle->shader->descriptor_count == 0) + LOG_WRN("Couldn't get field handle to \"%s\", reason: material->handle->shader->descriptor_count == 0\n", name); + + char struct_name[STRUCT_DESCRIPTOR_MAX_NAME_SIZE]; + char field_name[STRUCT_FIELD_MAX_NAME_SIZE]; + get_record_and_field_name(name, struct_name, field_name); + + u16 descriptor_count = material->handle->shader->descriptor_count; + vulkan_shader_resource_descriptor_t* descriptors = material->handle->shader->descriptors; + for(u16 i = 0; i < descriptor_count; i++) + { + vulkan_shader_resource_descriptor_t descriptor = ref(vulkan_shader_resource_descriptor_t, descriptors, i); + if(strcmp(descriptor.handle.name, struct_name) == 0) + { + return (material_field_handle_t) + { + .descriptor_index = i, + .field_handle = struct_descriptor_get_field_handle(&descriptor.handle, field_name) + }; + } + } + LOG_FETAL_ERR("symbol \"%s\" isn't found in the shader resource descriptors\n", name); + return (material_field_handle_t) { .descriptor_index = 0xFFFF, .field_handle = STRUCT_FIELD_INVALID_HANDLE }; +} + +/* functions accepting handles */ +void material_set_floatH(material_t* material, material_field_handle_t handle, float value) +{ + check_precondition(material); + struct_descriptor_set_float(map_descriptor(material, handle), handle.field_handle, &value); + unmap_descriptor(material, handle); +} + +void material_set_intH(material_t* material, material_field_handle_t handle, int value) +{ + check_precondition(material); + struct_descriptor_set_int(map_descriptor(material, handle), handle.field_handle, &value); + unmap_descriptor(material, handle); +} + +void material_set_uintH(material_t* material, material_field_handle_t handle, uint value) +{ + check_precondition(material); + struct_descriptor_set_uint(map_descriptor(material, handle), handle.field_handle, &value); + unmap_descriptor(material, handle); +} + +void material_set_vec2H(material_t* material, material_field_handle_t handle, vec2_t(float) value) +{ + check_precondition(material); + struct_descriptor_set_vec2(map_descriptor(material, handle), handle.field_handle, (float*)&value); + unmap_descriptor(material, handle); +} + +void material_set_vec3H(material_t* material, material_field_handle_t handle, vec3_t(float) value) +{ + check_precondition(material); + struct_descriptor_set_vec3(map_descriptor(material, handle), handle.field_handle, (float*)&value); + unmap_descriptor(material, handle); +} + +void material_set_vec4H(material_t* material, material_field_handle_t handle, vec4_t(float) value) +{ + check_precondition(material); + struct_descriptor_set_vec4(map_descriptor(material, handle), handle.field_handle, (float*)&value); + unmap_descriptor(material, handle); +} + +void material_set_mat2H(material_t* material, material_field_handle_t handle, mat2_t(float) value) +{ + check_precondition(material); + struct_descriptor_set_mat2(map_descriptor(material, handle), handle.field_handle, (float*)&value); + unmap_descriptor(material, handle); +} + +void material_set_mat4H(material_t* material, material_field_handle_t handle, mat4_t(float) value) +{ + check_precondition(material); + struct_descriptor_set_mat4(map_descriptor(material, handle), handle.field_handle, (float*)&value); + unmap_descriptor(material, handle); } -void material_set_texture(material_t* material, renderer_t* renderer, texture_t* texture) +void material_set_texture2dH(material_t* material, material_field_handle_t handle, texture_t* texture) { - vulkan_material_set_texture(material, renderer, texture); + check_precondition(material); + assert(handle.descriptor_index < material->handle->shader->descriptor_count); + vulkan_shader_resource_descriptor_t descriptor = material->handle->shader->descriptors[handle.descriptor_index]; + assert(descriptor.set_number < 1); //for now we are just using one descriptor set and multiple bindings + vulkan_material_set_texture(material->handle, material->handle->renderer, descriptor.binding_number, texture); +} + +float material_get_floatH(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + float value; + struct_descriptor_get_float(map_descriptor(material, handle), handle.field_handle, &value); + return value; +} + +int material_get_intH(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + int value; + struct_descriptor_get_int(map_descriptor(material, handle), handle.field_handle, &value); + return value; +} + +uint material_get_uintH(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + uint value; + struct_descriptor_get_uint(map_descriptor(material, handle), handle.field_handle, &value); + return value; +} + +vec2_t(float) material_get_vec2H(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + vec2_t(float) value; + struct_descriptor_get_vec2(map_descriptor(material, handle), handle.field_handle, (float*)&value); + return value; +} + +vec3_t(float) material_get_vec3H(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + vec3_t(float) value; + struct_descriptor_get_vec3(map_descriptor(material, handle), handle.field_handle, (float*)&value); + return value; +} + +vec4_t(float) material_get_vec4H(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + vec4_t(float) value; + struct_descriptor_get_vec4(map_descriptor(material, handle), handle.field_handle, (float*)&value); + return value; +} + +mat2_t(float) material_get_mat2H(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + mat2_t(float) value; + struct_descriptor_get_mat2(map_descriptor(material, handle), handle.field_handle, (float*)&value); + return value; +} + +mat4_t(float) material_get_mat4H(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + mat4_t(float) value; + struct_descriptor_get_mat4(map_descriptor(material, handle), handle.field_handle, (float*)&value); + return value; +} + +texture_t* material_get_texture2dH(material_t* material, material_field_handle_t handle) +{ + check_precondition(material); + LOG_WRN("material_get_texture2dH isn't defined, for now it will return NULL\n"); + return NULL; +} + +/* functions accepting strings */ +void material_set_float(material_t* material, const char* name, float value) +{ + material_set_floatH(material, material_get_field_handle(material, name), value); +} + +void material_set_int(material_t* material, const char* name, int value) +{ + material_set_intH(material, material_get_field_handle(material, name), value); +} + +void material_set_uint(material_t* material, const char* name, uint value) +{ + material_set_uintH(material, material_get_field_handle(material, name), value); +} + +void material_set_vec2(material_t* material, const char* name, vec2_t(float) v) +{ + material_set_vec2H(material, material_get_field_handle(material, name), v); +} + +void material_set_vec3(material_t* material, const char* name, vec3_t(float) v) +{ + material_set_vec3H(material, material_get_field_handle(material, name), v); +} + +void material_set_vec4(material_t* material, const char* name, vec4_t(float) v) +{ + material_set_vec4H(material, material_get_field_handle(material, name), v); +} + +void material_set_mat2(material_t* material, const char* name, mat2_t(float) m) +{ + material_set_mat2H(material, material_get_field_handle(material, name), m); +} + +void material_set_mat4(material_t* material, const char* name, mat4_t(float) m) +{ + material_set_mat4H(material, material_get_field_handle(material, name), m); +} + +void material_set_texture2d(material_t* material, const char* name, texture_t* texture) +{ + material_set_texture2dH(material, material_get_field_handle(material, name), texture); +} + +float material_get_float(material_t* material, const char* name) +{ + return material_get_floatH(material, material_get_field_handle(material, name)); +} + +int material_get_int(material_t* material, const char* name) +{ + return material_get_intH(material, material_get_field_handle(material, name)); +} + +uint material_get_uint(material_t* material, const char* name) +{ + return material_get_uintH(material, material_get_field_handle(material, name)); +} + +vec2_t(float) material_get_vec2(material_t* material, const char* name) +{ + return material_get_vec2H(material, material_get_field_handle(material, name)); +} + +vec3_t(float) material_get_vec3(material_t* material, const char* name) +{ + return material_get_vec3H(material, material_get_field_handle(material, name)); +} + +vec4_t(float) material_get_vec4(material_t* material, const char* name) +{ + return material_get_vec4H(material, material_get_field_handle(material, name)); +} + +mat2_t(float) material_get_mat2(material_t* material, const char* name) +{ + return material_get_mat2H(material, material_get_field_handle(material, name)); +} + +mat4_t(float) material_get_mat4(material_t* material, const char* name) +{ + return material_get_mat4H(material, material_get_field_handle(material, name)); +} + +texture_t* material_get_texture2d(material_t* material, const char* name) +{ + return material_get_texture2dH(material, material_get_field_handle(material, name)); +} + + +#if GLOBAL_DEBUG +static void check_precondition(material_t* material) +{ + assert(material != NULL); + assert(material->handle->shader != NULL); + assert(material->handle->shader->descriptors != NULL); + assert_wrn(material->handle->shader->descriptor_count != 0); +} +#endif + + +static void unmap_descriptor(material_t* material, material_field_handle_t handle) +{ + vulkan_buffer_t* buffer = &(material->uniform_resources[handle.descriptor_index].buffer); + struct_descriptor_t* descriptor = &(material->handle->shader->descriptors[handle.descriptor_index].handle); + struct_descriptor_unmap(descriptor); + vulkan_buffer_unmap(buffer, material->handle->renderer); +} + +static struct_descriptor_t* map_descriptor(material_t* material, material_field_handle_t handle) +{ + vulkan_buffer_t* buffer = &(material->uniform_resources[handle.descriptor_index].buffer); + struct_descriptor_t* descriptor = &(material->handle->shader->descriptors[handle.descriptor_index].handle); + struct_descriptor_map(descriptor, vulkan_buffer_map(buffer, material->handle->renderer)); + return descriptor; +} + +static void get_record_and_field_name(const char* const full_name, char out_struct_name[STRUCT_DESCRIPTOR_MAX_NAME_SIZE], char out_field_name[STRUCT_FIELD_MAX_NAME_SIZE]) +{ + u32 len = strlen(full_name); + assert(len != 0); + const char* ptr = strchr(full_name, '.'); + memset(out_field_name, 0, STRUCT_FIELD_MAX_NAME_SIZE); + memset(out_struct_name, 0, STRUCT_DESCRIPTOR_MAX_NAME_SIZE); + if(ptr == NULL) + { + memcpy(out_struct_name, full_name, len); + return; + } + u16 struct_name_len = (u16)(ptr - full_name); + u16 field_name_len = (u16)(len - struct_name_len - 1); + assert(struct_name_len < STRUCT_DESCRIPTOR_MAX_NAME_SIZE); + assert(field_name_len < STRUCT_FIELD_MAX_NAME_SIZE); + memcpy(out_struct_name, full_name, struct_name_len); + memcpy(out_field_name, ptr + 1, field_name_len); } static void get_vulkan_constants(VkFormat* out_formats, u32* out_sizes, u32* out_indices) @@ -221,8 +556,8 @@ static void get_vulkan_constants(VkFormat* out_formats, u32* out_sizes, u32* out static u32 decode_attribute_count(u64 packed_attributes) { - u8 bits_per_type = MATERIAL_TYPE_BITS(packed_attributes); - packed_attributes &= ~MATERIAL_TYPE_BITS_MASK; + u8 bits_per_type = 5; + log_u64(packed_attributes); u64 bits_mask = ~(0xFFFFFFFFFFFFFFFFULL << bits_per_type); u32 count = 0; while(packed_attributes != 0) @@ -233,3 +568,56 @@ static u32 decode_attribute_count(u64 packed_attributes) } return count; } + +static void decode_vulkan_vertex_infos(u64 packed_attributes, VkVertexInputRate input_rate, vulkan_vertex_info_t* out_vertex_infos, VkFormat* formats, u32* offsets) +{ + VkFormat* vulkan_formats = stack_newv(u32, 26); + u32* sizes = stack_newv(u32, 22); + u32* indices = stack_newv(u32, 22); + get_vulkan_constants(vulkan_formats, sizes, indices); + + u8 bits_per_type = 5; + u64 bits_mask = ~(0xFFFFFFFFFFFFFFFFULL << bits_per_type); + + u32 i = 0; + while(packed_attributes != 0) + { + //WARNING: this should be like this: refp(vulkan_vertex_info_t, out_vertex_infos, i) + vulkan_vertex_info_t* info = &out_vertex_infos[i]; + u64 attribute_type = (packed_attributes & bits_mask); + if(attribute_type == 0) + { + packed_attributes >>= bits_per_type; + continue; + } + VkFormat vulkan_format = ref(VkFormat, vulkan_formats, ref(u32, indices, attribute_type)); + info->input_rate = input_rate; + info->size = ref(u32, sizes, attribute_type); + info->attribute_count = 1; + switch(attribute_type) + { + case MATERIAL_MAT3: + LOG_FETAL_ERR("Vertex attribute decode error: MATERIAL_MAT3 isn't supported yet!\n"); + break; + + case MATERIAL_MAT4: + LOG_FETAL_ERR("Vertex attribute decode error: MATERIAL_MAT4 isn't supported yet!\n"); + break; + + default:/*or MATERIAL_MAT2*/ + //WARNING: this should be like this: ref(VkFormat, formats, i) + formats[i] = vulkan_format; + //WARNING: this should be like this: refp(VkFormat, formats, i) + info->attribute_formats = &formats[i]; + //WARNING: this should be like this: ref(u32, offsets, i) + offsets[i] = 0; + //WARNING: this should be like this: refp(u32, offsets, i) + info->attribute_offsets = &offsets[i]; + break; + } + packed_attributes >>= bits_per_type; + i++; + } + stack_free(vulkan_formats); + stack_free(indices); +} diff --git a/source/renderer/mesh.c b/source/renderer/mesh.c index 1c1047f2..46783cfb 100644 --- a/source/renderer/mesh.c +++ b/source/renderer/mesh.c @@ -51,6 +51,7 @@ void mesh_create_no_alloc(renderer_t* renderer, mesh3d_t* mesh_data, mesh_t* mes }; } vulkan_mesh_create_no_alloc(renderer, &create_info, mesh); + stack_free(vertex_buffer_infos); } void mesh_destroy(mesh_t* mesh, renderer_t* renderer) diff --git a/source/renderer/shader.c b/source/renderer/shader.c index b519a425..025c1a33 100644 --- a/source/renderer/shader.c +++ b/source/renderer/shader.c @@ -1,89 +1,23 @@ #include -#include -#include -#include -#include -#include -#include +#include -shader_t* shader_load(renderer_t* renderer, const char* file_path) +shader_t* shader_create(renderer_t* renderer, BUFFER* shader_binary) { - BUFFER* shader_binary = load_binary_from_file(file_path); - const char* header = "SHADER BINARY"; u8 header_len = strlen(header); - char buffer[header_len]; - buf_ucount_t cursor = 0; - for(; cursor < header_len; cursor++) buf_get_at(shader_binary, cursor, &buffer[cursor]); - if(strncmp(buffer, header, header_len) != 0) - { - LOG_FETAL_ERR("Shader binary loading error: invalid header \"%.*s\"\n", header_len, buffer); - } - - u8 shader_mask = *(u8*)buf_get_ptr_at(shader_binary, cursor); cursor++; - u8 shader_count = 0; for(u8 i = 0; i < 4; i++) { if(shader_mask & (1 << i)) shader_count++; } - - stage_shader_t** shaders = stack_newv(stage_shader_t*, shader_count); - for(u8 i = 0, count = 0; i < SHADER_COMPILER_SHADER_STAGE_MAX; i++) - { - u8 bit = shader_mask & (1 << i); - if(bit == 0) continue; - u32 offset = *(u32*)buf_get_ptr_at(shader_binary, cursor); cursor += 4; - u32 length = *(u32*)buf_get_ptr_at(shader_binary, cursor); cursor += 4; - switch(bit) - { - case 1 << 0: - //Vertex shader spirv - u32* spirv = buf_get_ptr_at(shader_binary, offset); - ref(stage_shader_t*, shaders, count) = stage_shader_create(renderer, spirv, length, SHADER_STAGE_VERTEX); - count++; - break; - case 1 << 1: - //Tessellation shader spirv - spirv = buf_get_ptr_at(shader_binary, offset); - ref(stage_shader_t*, shaders, count) = stage_shader_create(renderer, spirv, length, SHADER_STAGE_TESSELLATION); - count++; - break; - case 1 << 2: - //Geometry shader spirv - spirv = buf_get_ptr_at(shader_binary, offset); - ref(stage_shader_t*, shaders, count) = stage_shader_create(renderer, spirv, length, SHADER_STAGE_GEOMETRY); - count++; - break; - case 1 << 3: - //Fragment shader spirv - spirv = buf_get_ptr_at(shader_binary, offset); - ref(stage_shader_t*, shaders, count) = stage_shader_create(renderer, spirv, length, SHADER_STAGE_FRAGMENT); - count++; - break; - default: - LOG_FETAL_ERR("Shader binary loading error: Invalid shader bit \"%u\" in shader_mask\n", bit); - } - } - shader_t* shader = shader_create(renderer, shaders, shader_count); - stack_free(shaders); - buf_free(shader_binary); - return shader; + return vulkan_shader_create(renderer, shader_binary); } -shader_t* shader_create(renderer_t* renderer, stage_shader_t** stage_shaders, u8 stage_count) +shader_t* shader_load_and_create(renderer_t* renderer, const char* file_path) { - shader_t* shader = heap_new(shader_t); - memset(shader, 0, sizeof(shader_t)); - shader->stage_shaders = heap_newv(stage_shader_t*, stage_count); - memcpy(shader->stage_shaders, refp(stage_shader_t*, stage_shaders, 0), sizeof(stage_shader_t*) * stage_count); - shader->stage_count = stage_count; - return shader; + return vulkan_shader_load_and_create(renderer, file_path); } void shader_destroy(shader_t* shader, renderer_t* renderer) { - for(u8 i = 0; i < shader->stage_count; i++) - stage_shader_destroy(ref(stage_shader_t*, shader->stage_shaders, i), renderer); + vulkan_shader_destroy(shader, renderer); } void shader_release_resources(shader_t* shader) { - heap_free(shader->stage_shaders); - heap_free(shader); + vulkan_shader_release_resources(shader); } - diff --git a/source/renderer/stage_shader.c b/source/renderer/stage_shader.c deleted file mode 100644 index b5ea2be7..00000000 --- a/source/renderer/stage_shader.c +++ /dev/null @@ -1,36 +0,0 @@ - -#include -#include - -stage_shader_t* stage_shader_new() { return vulkan_shader_new(); } - -stage_shader_t* stage_shader_create(renderer_t* renderer, void* spirv, uint32_t length, shader_stage_t shader_stage) -{ - return vulkan_shader_create(renderer, spirv, length, shader_stage); -} - -void stage_shader_create_no_alloc(renderer_t* renderer, void* spirv, uint32_t length, shader_stage_t shader_stage, stage_shader_t* shader) -{ - vulkan_shader_create_no_alloc(renderer, spirv, length, shader_stage, shader); -} - -stage_shader_t* stage_shader_load_and_create(renderer_t* renderer, const char* file_name, shader_stage_t shader_stage) -{ - return vulkan_shader_load_and_create(renderer, file_name, shader_stage); -} - -void stage_shader_load_and_create_no_alloc(renderer_t* renderer, const char* file_name, shader_stage_t shader_stage, stage_shader_t* shader) -{ - vulkan_shader_load_and_create_no_alloc(renderer, file_name, shader_stage, shader); -} - -void stage_shader_destroy(stage_shader_t* shader, renderer_t* renderer) -{ - vulkan_shader_destroy(shader, renderer); -} - -void stage_shader_release_resources(stage_shader_t* shader) -{ - vulkan_shader_release_resources(shader); -} - diff --git a/source/renderer/vulkan/vulkan_buffer.c b/source/renderer/vulkan/vulkan_buffer.c index 0568bdf4..e7e35c58 100644 --- a/source/renderer/vulkan/vulkan_buffer.c +++ b/source/renderer/vulkan/vulkan_buffer.c @@ -28,19 +28,16 @@ void vulkan_buffer_create_no_alloc(renderer_t* renderer, vulkan_buffer_create_in { assert(renderer != NULL); assert(buffer != NULL); - assert(create_info->data != NULL); - assert(create_info->stride != 0); - assert(create_info->count != 0); + assert(((create_info->stride != 0) && (create_info->count != 0)) || (create_info->size != 0)); - u32 buffer_size = create_info->stride * create_info->count; + u32 buffer_size = (create_info->size == 0) ? (create_info->stride * create_info->count) : create_info->size; buffer->handle = vk_get_buffer(renderer->vk_device, buffer_size, create_info->usage_flags, create_info->sharing_mode); buffer->memory = vk_get_device_memory_for_buffer(renderer->vk_device, renderer->vk_physical_device, buffer->handle, buffer_size, create_info->memory_property_flags); - void* ptr; - vkMapMemory(renderer->vk_device, buffer->memory, 0, buffer_size, 0, &ptr); - memcpy(ptr, create_info->data, buffer_size); - vkUnmapMemory(renderer->vk_device, buffer->memory); buffer->stride = create_info->stride; buffer->count = create_info->count; + buffer->size = buffer_size; + if(create_info->data != NULL) + vulkan_buffer_copy_data(buffer, renderer, create_info->data, 0, buffer->size); } void vulkan_buffer_destroy(vulkan_buffer_t* buffer, renderer_t* renderer) @@ -57,3 +54,30 @@ void vulkan_buffer_release_resources(vulkan_buffer_t* buffer) assert(buffer != NULL); heap_free(buffer); } + +void vulkan_buffer_copy_data(vulkan_buffer_t* buffer, renderer_t* renderer, void* data, u32 start_offset, u32 size) +{ + assert(buffer != NULL); + assert(data != NULL); + assert((start_offset + size) <= buffer->size); + assert_wrn(size != 0); + + void* ptr; + vkMapMemory(renderer->vk_device, buffer->memory, 0, buffer->size, 0, &ptr); + memcpy(ptr, data + start_offset, size); + vkUnmapMemory(renderer->vk_device, buffer->memory); +} + +void* vulkan_buffer_map(vulkan_buffer_t* buffer, renderer_t* renderer) +{ + assert(buffer != NULL); + assert_wrn(buffer->size != 0); + void* ptr; + vkMapMemory(renderer->vk_device, buffer->memory, 0, buffer->size, 0, &ptr); + return ptr; +} + +void vulkan_buffer_unmap(vulkan_buffer_t* buffer, renderer_t* renderer) +{ + vkUnmapMemory(renderer->vk_device, buffer->memory); +} diff --git a/source/renderer/vulkan/vulkan_descriptor_set.c b/source/renderer/vulkan/vulkan_descriptor_set.c new file mode 100644 index 00000000..03d43294 --- /dev/null +++ b/source/renderer/vulkan/vulkan_descriptor_set.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +vulkan_descriptor_set_t* vulkan_descriptor_set_new() +{ + vulkan_descriptor_set_t* set = heap_new(vulkan_descriptor_set_t); + memset(set, 0, sizeof(vulkan_descriptor_set_t)); + return set; +} + +void vulkan_descriptor_set_create_no_alloc(renderer_t* renderer, vulkan_descriptor_set_create_info_t* create_info, vulkan_descriptor_set_t* set) +{ + VkDescriptorSetAllocateInfo alloc_info = + { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = create_info->pool, + .descriptorSetCount = 1, + .pSetLayouts = &create_info->layout + }; + vkCall(vkAllocateDescriptorSets(renderer->vk_device, &alloc_info, &set->handle)); + set->pool = create_info->pool; +} + +vulkan_descriptor_set_t* vulkan_descriptor_set_create(renderer_t* renderer, vulkan_descriptor_set_create_info_t* create_info) +{ + vulkan_descriptor_set_t* set = vulkan_descriptor_set_new(); + vulkan_descriptor_set_create_no_alloc(renderer, create_info, set); + return set; +} + +void vulkan_descriptor_set_destroy(vulkan_descriptor_set_t* set, renderer_t* renderer) +{ + vkCall(vkFreeDescriptorSets(renderer->vk_device, set->pool, 1, &set->handle)); +} + +void vulkan_descriptor_set_release_resources(vulkan_descriptor_set_t* set) +{ + heap_free(set); +} + +void vulkan_descriptor_set_bind(vulkan_descriptor_set_t* set, renderer_t* renderer, vulkan_pipeline_layout_t* pipeline_layout) +{ + u32 image_index = renderer->swapchain->current_image_index; + vkCmdBindDescriptorSets(renderer->vk_command_buffers.value2[image_index], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout->handle, 0, 1, &set->handle, 0, NULL); +} + +void vulkan_descriptor_set_write_texture(vulkan_descriptor_set_t* set, renderer_t* renderer, u32 binding_index, vulkan_texture_t* texture) +{ + VkDescriptorImageInfo image_info = + { + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .imageView = texture->image_view, + .sampler = texture->image_sampler + }; + VkWriteDescriptorSet descriptor_write = + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = set->handle, + .dstBinding = binding_index, + .dstArrayElement = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .pImageInfo = &image_info, + }; + vkUpdateDescriptorSets(renderer->vk_device, 1, &descriptor_write, 0, NULL); +} + +void vulkan_descriptor_set_write_uniform_buffer(vulkan_descriptor_set_t* set, renderer_t* renderer, u32 binding_index, vulkan_buffer_t* buffer) +{ + VkDescriptorBufferInfo buffer_info = + { + .buffer = buffer->handle, + .offset = 0, + .range = buffer->size + }; + VkWriteDescriptorSet descriptor_write = + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = set->handle, + .dstBinding = binding_index, + .dstArrayElement = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .pBufferInfo = &buffer_info, + }; + vkUpdateDescriptorSets(renderer->vk_device, 1, &descriptor_write, 0, NULL); +} diff --git a/source/renderer/vulkan/vulkan_graphics_pipeline.c b/source/renderer/vulkan/vulkan_graphics_pipeline.c index 945c6ce9..32209902 100644 --- a/source/renderer/vulkan/vulkan_graphics_pipeline.c +++ b/source/renderer/vulkan/vulkan_graphics_pipeline.c @@ -24,11 +24,12 @@ void vulkan_graphics_pipeline_create_no_alloc(renderer_t* renderer, vulkan_graph ASSERT(renderer->vk_render_pass != VK_NULL_HANDLE, "renderer->vk_render_pass == VK_NULL_HANDLE\n"); ASSERT(renderer->window != NULL, "renderer->window == NULL\n"); - vulkan_pipeline_layout_create_no_alloc(renderer, pipeline->pipeline_layout); + vulkan_pipeline_layout_create_info_t layout_create_info = { .vk_set_layout = create_info->shader->vk_set_layout }; + vulkan_pipeline_layout_create_no_alloc(renderer, &layout_create_info, pipeline->pipeline_layout); - VkPipelineShaderStageCreateInfo* shader_stages = stack_newv(VkPipelineShaderStageCreateInfo, create_info->shader_count); - for(u32 i = 0; i < create_info->shader_count; i++) - ref(VkPipelineShaderStageCreateInfo, shader_stages, i) = (*refp(vulkan_shader_t*, create_info->shaders, i))->stage; + VkPipelineShaderStageCreateInfo* shader_stages = stack_newv(VkPipelineShaderStageCreateInfo, create_info->shader->stage_count); + for(u32 i = 0; i < create_info->shader->stage_count; i++) + ref(VkPipelineShaderStageCreateInfo, shader_stages, i) = (*refp(vulkan_stage_shader_t*, create_info->shader->stage_shaders, i))->stage; vertex_attribute_binding_info_t* vertex_attribute_infos = stack_alloc(sizeof(vertex_attribute_binding_info_t) * create_info->vertex_info_count); memset(vertex_attribute_infos, 0, sizeof(vertex_attribute_binding_info_t) * create_info->vertex_info_count); @@ -50,7 +51,7 @@ void vulkan_graphics_pipeline_create_no_alloc(renderer_t* renderer, vulkan_graph VkPipelineViewportStateCreateInfo viewportState = vk_get_pipeline_viewport_state_create_info(renderer->window->width, renderer->window->height); VkPipelineMultisampleStateCreateInfo multisampling = vk_get_pipeline_multisample_state_create_info(); VkPipelineColorBlendStateCreateInfo colorBlending = vk_get_pipeline_color_blend_state_create_info(); - pipeline->pipeline = vk_get_graphics_pipeline( renderer->vk_device, pipeline->pipeline_layout->pipeline_layout, renderer->vk_render_pass, + pipeline->pipeline = vk_get_graphics_pipeline( renderer->vk_device, pipeline->pipeline_layout->handle, renderer->vk_render_pass, shader_stages, &vertexInputInfo, &inputAssembly, diff --git a/source/renderer/vulkan/vulkan_material.c b/source/renderer/vulkan/vulkan_material.c index 6e5e768f..003fa061 100644 --- a/source/renderer/vulkan/vulkan_material.c +++ b/source/renderer/vulkan/vulkan_material.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,12 +27,15 @@ vulkan_material_t* vulkan_material_new() void vulkan_material_create_no_alloc(renderer_t* renderer, vulkan_material_create_info_t* create_info, vulkan_material_t* material) { ASSERT(renderer->window != NULL, "renderer->window == NULL\n"); + assert(create_info->vertex_info_count != 0); + assert(create_info->vertex_infos != NULL); + material->renderer = renderer; + material->shader = create_info->shader; vulkan_graphics_pipeline_create_info_t pipeline_create_info = { - .shaders = create_info->shaders, - .shader_count = create_info->shader_count, + .shader = create_info->shader, .vertex_info_count = create_info->vertex_info_count, - .vertex_infos = create_info->vertex_infos + .vertex_infos = create_info->vertex_infos, }; vulkan_graphics_pipeline_create_no_alloc(renderer, &pipeline_create_info, material->graphics_pipeline); } @@ -39,14 +44,14 @@ vulkan_material_t* vulkan_material_create(renderer_t* renderer, vulkan_material_ { vulkan_material_t* material = vulkan_material_new(); vulkan_material_create_no_alloc(renderer, create_info, material); - material->create_info = *create_info; - material->create_info.vertex_infos = heap_newv(vulkan_vertex_info_t, create_info->vertex_info_count); + material->vertex_infos = heap_newv(vulkan_vertex_info_t, create_info->vertex_info_count); + material->vertex_info_count = create_info->vertex_info_count; //TODO: This should be like safe_memcpy() - memcpy(material->create_info.vertex_infos, create_info->vertex_infos, sizeof(vulkan_vertex_info_t) * create_info->vertex_info_count); + memcpy(material->vertex_infos, create_info->vertex_infos, sizeof(vulkan_vertex_info_t) * create_info->vertex_info_count); for(u32 i = 0; i < create_info->vertex_info_count; i++) { vulkan_vertex_info_t* src_info = refp(vulkan_vertex_info_t, create_info->vertex_infos, i); - vulkan_vertex_info_t* dst_info = refp(vulkan_vertex_info_t, material->create_info.vertex_infos, i); + vulkan_vertex_info_t* dst_info = refp(vulkan_vertex_info_t, material->vertex_infos, i); VkFormat* attribute_formats = heap_newv(VkFormat, src_info->attribute_count); u32* attribute_offsets = heap_newv(u32, src_info->attribute_count); //TODO: This should be like safe_memcpy() @@ -55,7 +60,6 @@ vulkan_material_t* vulkan_material_create(renderer_t* renderer, vulkan_material_ dst_info->attribute_offsets = attribute_offsets; dst_info->attribute_formats = attribute_formats; } - material->renderer = renderer; render_window_subscribe_on_resize(renderer->window, recreate_material, material); return material; } @@ -64,21 +68,20 @@ void vulkan_material_destroy(vulkan_material_t* material, renderer_t* renderer) { vulkan_graphics_pipeline_destroy(material->graphics_pipeline, renderer); render_window_unsubscribe_on_resize(renderer->window, recreate_material); + material->shader = NULL; } void vulkan_material_release_resources(vulkan_material_t* material) { vulkan_graphics_pipeline_release_resources(material->graphics_pipeline); - u32 vertex_info_count = material->create_info.vertex_info_count; + u32 vertex_info_count = material->vertex_info_count; for(u32 i = 0; i < vertex_info_count; i++) { - vulkan_vertex_info_t* info = refp(vulkan_vertex_info_t, material->create_info.vertex_infos, i); + vulkan_vertex_info_t* info = refp(vulkan_vertex_info_t, material->vertex_infos, i); heap_free(info->attribute_formats); heap_free(info->attribute_offsets); } - heap_free(material->create_info.vertex_infos); - if(material->descriptor_sets != NULL) - heap_free(material->descriptor_sets); + heap_free(material->vertex_infos); heap_free(material); } @@ -86,8 +89,8 @@ void vulkan_material_bind(vulkan_material_t* material, renderer_t* renderer) { u32 image_index = renderer->swapchain->current_image_index; vulkan_graphics_pipeline_bind(material->graphics_pipeline, renderer); - if(material->descriptor_sets != NULL) - vkCmdBindDescriptorSets(renderer->vk_command_buffers.value2[image_index], VK_PIPELINE_BIND_POINT_GRAPHICS, material->graphics_pipeline->pipeline_layout->pipeline_layout, 0, 1, refp(VkDescriptorSet, material->descriptor_sets, image_index), 0, NULL); + if(material->shader->vk_set != NULL) + vulkan_descriptor_set_bind(material->shader->vk_set, renderer, material->graphics_pipeline->pipeline_layout); } void vulkan_material_push_constants(vulkan_material_t* material, renderer_t* renderer, void* bytes) @@ -95,46 +98,35 @@ void vulkan_material_push_constants(vulkan_material_t* material, renderer_t* ren vulkan_pipeline_layout_push_constants(material->graphics_pipeline->pipeline_layout, renderer, bytes); } -void vulkan_material_set_texture(vulkan_material_t* material, renderer_t* renderer, vulkan_texture_t* texture) +void vulkan_material_set_texture(vulkan_material_t* material, renderer_t* renderer, u32 binding_index, vulkan_texture_t* texture) { - material->descriptor_set_count = 3; - material->descriptor_sets = heap_newv(VkDescriptorSet, 3); + if(material->shader->vk_set == NULL) + { + assert_wrn(material->shader->vk_set != NULL); + return; + } + vulkan_descriptor_set_write_texture(material->shader->vk_set, renderer, binding_index, texture); +} - for(u32 i = 0; i < 3; i++) +void vulkan_material_set_uniform_buffer(vulkan_material_t* material, renderer_t* renderer, u32 binding_index, vulkan_buffer_t* buffer) +{ + if(material->shader->vk_set == NULL) { - VkDescriptorSetAllocateInfo alloc_info = - { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = renderer->vk_descriptor_pool, - .descriptorSetCount = 1, - .pSetLayouts = &(material->graphics_pipeline->pipeline_layout->descriptor_set_layout) - }; - vkCall(vkAllocateDescriptorSets(renderer->vk_device, &alloc_info, refp(VkDescriptorSet, material->descriptor_sets, i))); - VkDescriptorImageInfo image_info = - { - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .imageView = texture->image_view, - .sampler = texture->image_sampler - }; - VkWriteDescriptorSet descriptor_write = - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ref(VkDescriptorSet, material->descriptor_sets, i), - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .descriptorCount = 1, - .pBufferInfo = NULL, //Optional - .pImageInfo = &image_info, - .pTexelBufferView = NULL // Optional - }; - vkUpdateDescriptorSets(renderer->vk_device, 1, &descriptor_write, 0, NULL); + assert_wrn(material->shader->vk_set != NULL); + return; } + vulkan_descriptor_set_write_uniform_buffer(material->shader->vk_set, renderer, binding_index, buffer); } static void recreate_material(render_window_t* window, void* user_data) { vulkan_material_t* material = user_data; vulkan_graphics_pipeline_destroy(material->graphics_pipeline, material->renderer); - vulkan_material_create_no_alloc(material->renderer, &(material->create_info), material); + vulkan_graphics_pipeline_create_info_t pipeline_create_info = + { + .shader = material->shader, + .vertex_info_count = material->vertex_info_count, + .vertex_infos = material->vertex_infos, + }; + vulkan_graphics_pipeline_create_no_alloc(material->renderer, &pipeline_create_info, material->graphics_pipeline); } diff --git a/source/renderer/vulkan/vulkan_mesh.c b/source/renderer/vulkan/vulkan_mesh.c index 84a87356..afd62afa 100644 --- a/source/renderer/vulkan/vulkan_mesh.c +++ b/source/renderer/vulkan/vulkan_mesh.c @@ -30,16 +30,12 @@ void vulkan_mesh_create_no_alloc(renderer_t* renderer, vulkan_mesh_create_info_t { vulkan_vertex_buffer_create_info_t* info = refp(vulkan_vertex_buffer_create_info_t, create_info->vertex_buffer_infos, i); if(vertex_count != info->count) - { LOG_FETAL_ERR("Vertex buffer creation failed, all the per-vertex vertex buffers should have the same count\n"); - } vulkan_mesh_create_and_add_vertex_buffer(mesh, renderer, info); } } else - { - log_wrn("there is no vertex buffers in vulkan_mesh_create_info_t* create_info\n"); - } + LOG_FETAL_ERR("there is no vertex buffers in vulkan_mesh_create_info_t* create_info\n"); //create index buffer if(create_info->index_buffer_info.count != 0) @@ -163,7 +159,6 @@ void vulkan_mesh_create_and_add_vertex_buffer(vulkan_mesh_t* mesh, renderer_t* r //otherwise, allocate new memory block and init the internal fields else { - //WARNING: buf_push_pseudo(&mesh->vertex_buffers, 1) doesn't seems to be working! vulkan_buffer_t __buffer; vulkan_buffer_init(&__buffer); buf_push(&mesh->vertex_buffers, &__buffer); diff --git a/source/renderer/vulkan/vulkan_pipeline_layout.c b/source/renderer/vulkan/vulkan_pipeline_layout.c index 9a0da678..4ba30611 100644 --- a/source/renderer/vulkan/vulkan_pipeline_layout.c +++ b/source/renderer/vulkan/vulkan_pipeline_layout.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include vulkan_pipeline_layout_t* vulkan_pipeline_layout_new() { @@ -12,47 +14,31 @@ vulkan_pipeline_layout_t* vulkan_pipeline_layout_new() return layout; } -void vulkan_pipeline_layout_create_no_alloc(renderer_t* renderer, vulkan_pipeline_layout_t* pipeline_layout) +void vulkan_pipeline_layout_create_no_alloc(renderer_t* renderer, vulkan_pipeline_layout_create_info_t* create_info, vulkan_pipeline_layout_t* pipeline_layout) { + assert(create_info != NULL); VkPushConstantRange* push_constant_range = stack_new(VkPushConstantRange); /*TODO: push_constant_range->size = sizeof(mat4_t(float));*/ push_constant_range->size = sizeof(float) * 16; push_constant_range->offset = 0; push_constant_range->stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - /* Descriptor set layout */ - VkDescriptorSetLayoutBinding layout_binding = - { - .binding = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = NULL, //optional - }; - - VkDescriptorSetLayoutCreateInfo layout_create_info = - { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = 1, - .pBindings = &layout_binding - }; - vkCall(vkCreateDescriptorSetLayout(renderer->vk_device, &layout_create_info, NULL, &(pipeline_layout->descriptor_set_layout))); - pipeline_layout->pipeline_layout = vk_get_pipeline_layout(renderer->vk_device, 1, &(pipeline_layout->descriptor_set_layout), 1, push_constant_range); + u32 set_layout_count = create_info->vk_set_layout == VK_NULL_HANDLE ? 0 : 1; + pipeline_layout->handle = vk_get_pipeline_layout(renderer->vk_device, set_layout_count, &create_info->vk_set_layout, 1, push_constant_range); stack_free(push_constant_range); } -vulkan_pipeline_layout_t* vulkan_pipeline_layout_create(renderer_t* renderer) +vulkan_pipeline_layout_t* vulkan_pipeline_layout_create(renderer_t* renderer, vulkan_pipeline_layout_create_info_t* create_info) { vulkan_pipeline_layout_t* pipeline_layout = vulkan_pipeline_layout_new(); - vulkan_pipeline_layout_create_no_alloc(renderer, pipeline_layout); + vulkan_pipeline_layout_create_no_alloc(renderer, create_info, pipeline_layout); return pipeline_layout; } void vulkan_pipeline_layout_destroy(vulkan_pipeline_layout_t* pipeline_layout, renderer_t* renderer) { - vkDestroyDescriptorSetLayout(renderer->vk_device, pipeline_layout->descriptor_set_layout, NULL); - vkDestroyPipelineLayout(renderer->vk_device, pipeline_layout->pipeline_layout, NULL); + vkDestroyPipelineLayout(renderer->vk_device, pipeline_layout->handle, NULL); } void vulkan_pipeline_layout_release_resources(vulkan_pipeline_layout_t* pipeline_layout) @@ -63,5 +49,5 @@ void vulkan_pipeline_layout_release_resources(vulkan_pipeline_layout_t* pipeline void vulkan_pipeline_layout_push_constants(vulkan_pipeline_layout_t* pipeline_layout, renderer_t* renderer, void* bytes) { - vkCmdPushConstants(ref(VkCommandBuffer, renderer->vk_command_buffers.value2, renderer->swapchain->current_image_index), pipeline_layout->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float) * 16, bytes); + vkCmdPushConstants(ref(VkCommandBuffer, renderer->vk_command_buffers.value2, renderer->swapchain->current_image_index), pipeline_layout->handle, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float) * 16, bytes); } \ No newline at end of file diff --git a/source/renderer/vulkan/vulkan_renderer.c b/source/renderer/vulkan/vulkan_renderer.c index 5a236f10..6d41f6f5 100644 --- a/source/renderer/vulkan/vulkan_renderer.c +++ b/source/renderer/vulkan/vulkan_renderer.c @@ -42,7 +42,7 @@ renderer_t* renderer_init(u32 width, u32 height, const char* title, bool full_sc renderer->vk_graphics_queue = vk_get_device_queue(renderer->vk_device, vk_get_graphics_queue_family_index(renderer->vk_physical_device), 0); //Create descripter pool - renderer->vk_descriptor_pool = vk_get_descripter_pool(renderer->vk_device); + renderer->vk_descriptor_pool = vk_get_descriptor_pool(renderer->vk_device); return renderer; } @@ -78,6 +78,10 @@ void renderer_end_frame(renderer_t* renderer) { vkCmdEndRenderPass(renderer->vk_command_buffers.value2[renderer->swapchain->current_image_index]); vkCall(vkEndCommandBuffer(renderer->vk_command_buffers.value2[renderer->swapchain->current_image_index])); +} + +void renderer_update(renderer_t* renderer) +{ uint32_t wait_destination_mask = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; VkSubmitInfo submit_info = { @@ -106,10 +110,6 @@ void renderer_end_frame(renderer_t* renderer) vkQueuePresentKHR(renderer->vk_graphics_queue, &present_info); vkQueueWaitIdle(renderer->vk_graphics_queue); vkDeviceWaitIdle(renderer->vk_device); -} - -void renderer_update(renderer_t* renderer) -{ render_window_poll_events(renderer->window); } diff --git a/source/renderer/vulkan/vulkan_shader.c b/source/renderer/vulkan/vulkan_shader.c index 31d6bb4e..8817f367 100644 --- a/source/renderer/vulkan/vulkan_shader.c +++ b/source/renderer/vulkan/vulkan_shader.c @@ -1,55 +1,388 @@ +#include #include #include - +#include +#include #include +#include #include -#include +#include +#include +#include vulkan_shader_t* vulkan_shader_new() { vulkan_shader_t* shader = heap_new(vulkan_shader_t); memset(shader, 0, sizeof(vulkan_shader_t)); - return refp(vulkan_shader_t, shader, 0); + return shader; } +static VkDescriptorSetLayout get_vulkan_descriptor_set_layout(renderer_t* renderer, vulkan_shader_resource_descriptor_t* descriptors, u32 binding_count); +static vulkan_stage_shader_t** create_stage_shaders(renderer_t* renderer, BUFFER* shader_binary, u32 cursor, u8* out_stage_count); +static vulkan_shader_resource_descriptor_t* create_descriptors(BUFFER* shader_binary, u32 cursor, u16* out_descriptor_count); +static u16 sizeof_glsl_type(u8 type); +static u16 alignof_glsl_type(u8 type); -vulkan_shader_t* vulkan_shader_create(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t vulkan_shader_type) +vulkan_shader_t* vulkan_shader_create(renderer_t* renderer, BUFFER* shader_binary) { + const char* header = "SHADER BINARY"; u8 header_len = strlen(header); + char buffer[header_len]; + buf_ucount_t cursor = 0; + for(; cursor < header_len; cursor++) buf_get_at(shader_binary, cursor, &buffer[cursor]); + if(strncmp(buffer, header, header_len) != 0) + LOG_FETAL_ERR("Shader binary loading error: invalid header \"%.*s\"\n", header_len, buffer); + + u32 shader_offset = 0xFFFFFFFF; //invalid + u32 layout_offset = 0xFFFFFFFF; //invalid + bool shader_found = false; + bool layout_found = false; + + const u32 section_mask = *(u32*)buf_get_ptr_at(shader_binary, cursor); cursor += 4; + const u32 MASK = 0x00000007UL; + for(u8 i = 0; i < 3; i++) + { + if((!shader_found) && (section_mask & ((1UL << 2) << (i * 3)))) + { + shader_offset = *(u32*)buf_get_ptr_at(shader_binary, cursor); + shader_found = true; + } + else if((!layout_found) && (section_mask & ((1UL << 1) << (i * 3)))) + { + layout_offset = *(u32*)buf_get_ptr_at(shader_binary, cursor); + layout_found = true; + } + if(section_mask & (MASK << (i * 3))) + cursor += 4; + } + if(!shader_found) + LOG_FETAL_ERR("Shader binary loading error: SHADER section not found!\n"); + if(!layout_found) + LOG_WRN("Shader binary loading warning: LAYOUT section not found!\n"); + vulkan_shader_t* shader = vulkan_shader_new(); - vulkan_shader_create_no_alloc(renderer, spirv, length, vulkan_shader_type, shader); + shader->stage_shaders = create_stage_shaders(renderer, shader_binary, shader_offset, &shader->stage_count); + if(layout_found) + { + shader->descriptors = create_descriptors(shader_binary, layout_offset, &shader->descriptor_count); + shader->vk_set_layout = get_vulkan_descriptor_set_layout(renderer, shader->descriptors, shader->descriptor_count); + vulkan_descriptor_set_create_info_t set_create_info = + { + .pool = renderer->vk_descriptor_pool, + .layout = shader->vk_set_layout + }; + if(shader->vk_set_layout != VK_NULL_HANDLE) + shader->vk_set = vulkan_descriptor_set_create(renderer, &set_create_info); + } return shader; } -void vulkan_shader_create_no_alloc(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t vulkan_shader_type, vulkan_shader_t* shader) +vulkan_shader_t* vulkan_shader_load_and_create(renderer_t* renderer, const char* file_path) { - assert(renderer->vk_device != VK_NULL_HANDLE); - assert(shader != NULL); - shader->module = vk_get_shader_module(renderer->vk_device, spirv, length, vulkan_shader_type); - shader->stage = vk_get_pipeline_shader_stage_create_info(refp(vulkan_shader_t, shader, 0)->module, vulkan_shader_type, "main"); + BUFFER* shader_binary = load_binary_from_file(file_path); + vulkan_shader_t* shader = vulkan_shader_create(renderer, shader_binary); + buf_free(shader_binary); + return shader; } -void vulkan_shader_load_and_create_no_alloc(renderer_t* renderer, const char* file_name, vulkan_shader_type_t vulkan_shader_type, vulkan_shader_t* shader) +void vulkan_shader_destroy(vulkan_shader_t* shader, renderer_t* renderer) { - ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); - refp(vulkan_shader_t, shader, 0)->module = vk_get_shader_module_load(renderer->vk_device, file_name); - refp(vulkan_shader_t, shader, 0)->stage = vk_get_pipeline_shader_stage_create_info(refp(vulkan_shader_t, shader, 0)->module, vulkan_shader_type, "main"); + for(u8 i = 0; i < shader->stage_count; i++) + vulkan_stage_shader_destroy(ref(vulkan_stage_shader_t*, shader->stage_shaders, i), renderer); + if(shader->vk_set_layout != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(renderer->vk_device, shader->vk_set_layout, NULL); + if(shader->vk_set != NULL) + vulkan_descriptor_set_destroy(shader->vk_set, renderer); } -vulkan_shader_t* vulkan_shader_load_and_create(renderer_t* renderer, const char* file_name, vulkan_shader_type_t vulkan_shader_type) +void vulkan_shader_release_resources(vulkan_shader_t* shader) { - ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); - vulkan_shader_t* shader = vulkan_shader_new(); - vulkan_shader_load_and_create_no_alloc(renderer, file_name, vulkan_shader_type, shader); - return shader; + if(shader->descriptors != NULL) + heap_free(shader->descriptors); + heap_free(shader->stage_shaders); + if(shader->vk_set != NULL) + vulkan_descriptor_set_release_resources(shader->vk_set); + heap_free(shader); } +static vulkan_stage_shader_t** create_stage_shaders(renderer_t* renderer, BUFFER* shader_binary, u32 cursor, u8* stage_count) +{ + assert(cursor != 0xFFFFFFFF); + u8 shader_mask = *(u8*)buf_get_ptr_at(shader_binary, cursor); cursor++; + u8 shader_count = 0; for(u8 i = 0; i < 4; i++) { if(shader_mask & (1 << i)) shader_count++; } + *stage_count = shader_count; -void vulkan_shader_destroy(vulkan_shader_t* shader, renderer_t* renderer) + vulkan_stage_shader_t** shaders = heap_newv(vulkan_stage_shader_t*, shader_count); + for(u8 i = 0, count = 0; i < SHADER_COMPILER_SHADER_STAGE_MAX; i++) + { + u8 bit = shader_mask & (1 << i); + if(bit == 0) continue; + u32 offset = *(u32*)buf_get_ptr_at(shader_binary, cursor); cursor += 4; + u32 length = *(u32*)buf_get_ptr_at(shader_binary, cursor); cursor += 4; + switch(bit) + { + case 1 << SHADER_COMPILER_SHADER_STAGE_VERTEX: + //Vertex shader spirv + u32* spirv = buf_get_ptr_at(shader_binary, offset); + ref(vulkan_stage_shader_t*, shaders, count) = vulkan_stage_shader_create(renderer, spirv, length, VULKAN_SHADER_TYPE_VERTEX); + count++; + break; + case 1 << SHADER_COMPILER_SHADER_STAGE_TESSELLATION: + //Tessellation shader spirv + spirv = buf_get_ptr_at(shader_binary, offset); + ref(vulkan_stage_shader_t*, shaders, count) = vulkan_stage_shader_create(renderer, spirv, length, VULKAN_SHADER_TYPE_TESSELLATION); + count++; + break; + case 1 << SHADER_COMPILER_SHADER_STAGE_GEOMETRY: + //Geometry shader spirv + spirv = buf_get_ptr_at(shader_binary, offset); + ref(vulkan_stage_shader_t*, shaders, count) = vulkan_stage_shader_create(renderer, spirv, length, VULKAN_SHADER_TYPE_GEOMETRY); + count++; + break; + case 1 << SHADER_COMPILER_SHADER_STAGE_FRAGMENT: + //Fragment shader spirv + spirv = buf_get_ptr_at(shader_binary, offset); + ref(vulkan_stage_shader_t*, shaders, count) = vulkan_stage_shader_create(renderer, spirv, length, VULKAN_SHADER_TYPE_FRAGMENT); + count++; + break; + default: + LOG_FETAL_ERR("Shader binary loading error: Invalid shader bit \"%u\" in shader_mask\n", bit); + break; + } + } + return shaders; +} + +static vulkan_shader_resource_descriptor_t* create_descriptors(BUFFER* shader_binary, u32 cursor, u16* out_descriptor_count) +{ + assert(cursor != 0xFFFFFFFF); + u16 descriptor_count = *(u16*)buf_get_ptr_at(shader_binary, cursor); cursor += 2; + *out_descriptor_count = descriptor_count; + if(descriptor_count == 0) + { + assert_wrn(descriptor_count != 0); + return NULL; + } + vulkan_shader_resource_descriptor_t* descriptors = heap_newv(vulkan_shader_resource_descriptor_t, descriptor_count); + + BUFFER fields = buf_create(sizeof(struct_field_t), 0, 0); + buf_ucount_t* indices = stack_newv(buf_ucount_t, descriptor_count); + for(u16 i = 0; i < descriptor_count; i++) indices[i] = BUF_INVALID_INDEX; + for(u16 i = 0; i < descriptor_count; i++, cursor += 4) + { + u32 offset = *(u32*)buf_get_ptr_at(shader_binary, cursor); + u32 temp_cursor = offset; + vulkan_shader_resource_descriptor_t* descriptor = refp(vulkan_shader_resource_descriptor_t, descriptors, i); + memset(&descriptor->handle, 0, sizeof(struct_descriptor_t)); + descriptor->set_number = *(u8*)buf_get_ptr_at(shader_binary, temp_cursor); temp_cursor += 1; + descriptor->binding_number = *(u8*)buf_get_ptr_at(shader_binary, temp_cursor); temp_cursor += 1; + assert(descriptor->set_number < 255); + assert(descriptor->binding_number < 255); + u16 descriptor_info = *(u16*)buf_get_ptr_at(shader_binary, temp_cursor); temp_cursor += 2; + descriptor->is_opaque = (descriptor_info & (1U << 15)) ? true : false; + descriptor->is_uniform = (descriptor_info & (1U << 14)) ? true : false; + descriptor->handle.type = descriptor_info & 0xFFU; + descriptor->stage_flags = 0; + if(descriptor_info & (1U << (13 - SHADER_COMPILER_SHADER_STAGE_VERTEX))) + descriptor->stage_flags |= 1U << VULKAN_SHADER_TYPE_VERTEX; + if(descriptor_info & (1U << (13 - SHADER_COMPILER_SHADER_STAGE_TESSELLATION))) + descriptor->stage_flags |= 1U << VULKAN_SHADER_TYPE_TESSELLATION; + if(descriptor_info & (1U << (13 - SHADER_COMPILER_SHADER_STAGE_GEOMETRY))) + descriptor->stage_flags |= 1U << VULKAN_SHADER_TYPE_GEOMETRY; + if(descriptor_info & (1U << (13 - SHADER_COMPILER_SHADER_STAGE_FRAGMENT))) + descriptor->stage_flags |= 1U << VULKAN_SHADER_TYPE_FRAGMENT; + + const char* name = buf_get_ptr_at(shader_binary, temp_cursor); + u32 len = strlen(name); + assert(len < STRUCT_DESCRIPTOR_MAX_NAME_SIZE); + temp_cursor += len + 1; + if(descriptor->handle.type == SHADER_COMPILER_BLOCK) + { + // ignore the block name + name = buf_get_ptr_at(shader_binary, temp_cursor); + len = strlen(name); + assert(len < STRUCT_DESCRIPTOR_MAX_NAME_SIZE); + temp_cursor += len + 1; + } + strcpy(descriptor->handle.name, name); + + LOG_MSG("Descriptor[%u]: (set = %u, binding = %u), stage_flags = %u, is_uniform = %s, is_opaque = %s, is_block = %s, name = %s\n", + i, descriptor->set_number, descriptor->binding_number, descriptor->stage_flags, + descriptor->is_uniform ? "true" : "false", descriptor->is_opaque ? "true" : "false", (descriptor->handle.type == SHADER_COMPILER_BLOCK) ? "true" : "false", + descriptor->handle.name); + + if(descriptor->handle.type == SHADER_COMPILER_BLOCK) + { + descriptor->handle.field_count = *(u16*)buf_get_ptr_at(shader_binary, temp_cursor); temp_cursor += 2; + LOG_MSG("Field Count: %u\n", descriptor->handle.field_count); + indices[i] = buf_get_element_count(&fields); + for(u16 j = 0; j < descriptor->handle.field_count; j++) + { + u16 descriptor_info = *(u16*)buf_get_ptr_at(shader_binary, temp_cursor); temp_cursor += 2; + const char* name = buf_get_ptr_at(shader_binary, temp_cursor); + u32 len = strlen(name); + assert(len < STRUCT_FIELD_MAX_NAME_SIZE); + temp_cursor += len + 1; + u8 type = descriptor_info & 0xFFU; + struct_field_t field = { .type = type, .size = sizeof_glsl_type(type), .alignment = alignof_glsl_type(type) }; + strcpy(field.name, name); + buf_push(&fields, &field); + LOG_MSG("Field[%u]: type = %u, size = %u, align = %u, name = %s\n", j, field.type, field.size, field.alignment, field.name); + } + } + } + if(buf_get_element_count(&fields) == 0) + buf_free(&fields); + else + buf_fit(&fields); + for(u16 i = 0; i < descriptor_count; i++) + { + if(indices[i] == BUF_INVALID_INDEX) + continue; + descriptors[i].handle.fields = buf_get_ptr_at(&fields, indices[i]); + struct_descriptor_recalculate(&descriptors[i].handle); + LOG_MSG("Struct \"%s\", size = %u\n", descriptors[i].handle.name, struct_descriptor_sizeof(&descriptors[i].handle)); + } + stack_free(indices); + return descriptors; +} + + +static VkDescriptorSetLayout get_vulkan_descriptor_set_layout(renderer_t* renderer, vulkan_shader_resource_descriptor_t* descriptors, u32 binding_count) { - vkDestroyShaderModule(renderer->vk_device, refp(vulkan_shader_t, shader, 0)->module, NULL); + if(binding_count == 0) + { + assert_wrn(binding_count != 0); + return VK_NULL_HANDLE; + } + VkDescriptorSetLayoutBinding* bindings = stack_newv(VkDescriptorSetLayoutBinding, binding_count); + memset(bindings, 0, sizeof(VkDescriptorSetLayoutBinding) * binding_count); + for(u32 i = 0; i < binding_count; i++) + { + VkDescriptorSetLayoutBinding* binding = refp(VkDescriptorSetLayoutBinding, bindings, i); + vulkan_shader_resource_descriptor_t* descriptor = refp(vulkan_shader_resource_descriptor_t, descriptors, i); + binding->binding = descriptor->binding_number; + binding->descriptorCount = 1; //for now we are not using arrays + binding->stageFlags = 0; + if(descriptor->stage_flags & (1 << VULKAN_SHADER_TYPE_VERTEX)) + binding->stageFlags |= VK_SHADER_STAGE_VERTEX_BIT; + if(descriptor->stage_flags & (1 << VULKAN_SHADER_TYPE_TESSELLATION)) + binding->stageFlags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + if(descriptor->stage_flags & (1 << VULKAN_SHADER_TYPE_GEOMETRY)) + binding->stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT; + if(descriptor->stage_flags & (1 << VULKAN_SHADER_TYPE_FRAGMENT)) + binding->stageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT; + switch(descriptor->handle.type) + { + case SHADER_COMPILER_BLOCK: + binding->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + break; + + case SHADER_COMPILER_SAMPLER2D: + binding->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + break; + + case SHADER_COMPILER_SAMPLER3D: + LOG_FETAL_ERR("Cannot create set layout binding for the type SHADER_COMPILER_SAMPLER3D, because the implementation is still in development\n"); + break; + + default: + LOG_FETAL_ERR("Cannot create set layout binding for the type \"%u\", because it is not recognized\n", descriptor->handle.type); + break; + } + } + VkDescriptorSetLayout vk_set_layout = vk_get_descriptor_set_layout(renderer->vk_device, bindings, binding_count); + stack_free(bindings); + return vk_set_layout; } -void vulkan_shader_release_resources(vulkan_shader_t* shader) +/* + Scalars + The basic non-vector types are: + + bool: conditional type, values may be either true or false + int: a signed, two's complement, 32-bit integer + uint: an unsigned 32-bit integer + float: an IEEE-754 single-precision floating point number + double: an IEEE-754 double-precision floating-point number + + Vectors + Each of the scalar types, including booleans, have 2, 3, and 4-component vector equivalents. The n digit below can be 2, 3, or 4: + + bvecn: a vector of booleans + ivecn: a vector of signed integers + uvecn: a vector of unsigned integers + vecn: a vector of single-precision floating-point numbers + dvecn: a vector of double-precision floating-point numbers + + NOTE: uniform int count: 'non-opaque uniforms outside a block' : not allowed when using GLSL for Vulkan + */ +static u16 sizeof_glsl_type(u8 type) { - heap_free(shader); + switch(type) + { + case SHADER_COMPILER_BLOCK : LOG_FETAL_ERR("getting size of non glsl type \"SHADER_COMPILER_BLOCK\" is a invalid operation\n"); + case SHADER_COMPILER_FLOAT : + case SHADER_COMPILER_INT : + case SHADER_COMPILER_UINT : return 4; + case SHADER_COMPILER_DOUBLE : LOG_FETAL_ERR("\"double\" isn't supported yet\n"); + case SHADER_COMPILER_VEC4 : + case SHADER_COMPILER_IVEC4 : + case SHADER_COMPILER_UVEC4 : + case SHADER_COMPILER_MAT2 : return 16; + case SHADER_COMPILER_IVEC3 : + case SHADER_COMPILER_UVEC3 : + case SHADER_COMPILER_VEC3 : return 12; + case SHADER_COMPILER_IVEC2 : + case SHADER_COMPILER_UVEC2 : + case SHADER_COMPILER_VEC2 : return 8; + case SHADER_COMPILER_MAT4 : return 64; + case SHADER_COMPILER_MAT3 : return 36; + case SHADER_COMPILER_SAMPLER2D : + case SHADER_COMPILER_SAMPLER3D : LOG_FETAL_ERR("getting size of opaque types are invalid operation\n"); + default : LOG_FETAL_ERR("Unrecognized glsl type \"%u\"\n", type); + }; +} + +/* + From the spec: + + Standard Uniform Buffer Layout + + The 'base alignment' of the type of an OpTypeStruct member of is defined recursively as follows: + + A scalar of size N has a base alignment of N. + A two-component vector, with components of size N, has a base alignment of 2 N. + A three- or four-component vector, with components of size N, has a base alignment of 4 N. + An array has a base alignment equal to the base alignment of its element type, rounded up to a multiple of 16. + A structure has a base alignment equal to the largest base alignment of any of its members, rounded up to a multiple of 16. + A row-major matrix of C columns has a base alignment equal to the base alignment of a vector of C matrix components. + A column-major matrix has a base alignment equal to the base alignment of the matrix column type. + The std140 layout in GLSL satisfies these rules. + + */ +static u16 alignof_glsl_type(u8 type) +{ + switch(type) + { + case SHADER_COMPILER_BLOCK : LOG_FETAL_ERR("getting alignment of non glsl type \"SHADER_COMPILER_BLOCK\" is a invalid operation\n"); + case SHADER_COMPILER_FLOAT : + case SHADER_COMPILER_INT : + case SHADER_COMPILER_UINT : return 4; + case SHADER_COMPILER_DOUBLE : LOG_FETAL_ERR("\"double\" isn't supported yet\n"); + case SHADER_COMPILER_VEC4 : + case SHADER_COMPILER_IVEC4 : + case SHADER_COMPILER_UVEC4 : + case SHADER_COMPILER_IVEC3 : + case SHADER_COMPILER_UVEC3 : + case SHADER_COMPILER_VEC3 : + case SHADER_COMPILER_MAT4 : + case SHADER_COMPILER_MAT3 : return 16; + case SHADER_COMPILER_IVEC2 : + case SHADER_COMPILER_UVEC2 : + case SHADER_COMPILER_VEC2 : + case SHADER_COMPILER_MAT2 : return 8; + case SHADER_COMPILER_SAMPLER2D : + case SHADER_COMPILER_SAMPLER3D : LOG_FETAL_ERR("getting alignment of opaque types are invalid operation\n"); + default : LOG_FETAL_ERR("Unrecognized glsl type \"%u\"\n", type); + }; } diff --git a/source/renderer/vulkan/vulkan_stage_shader.c b/source/renderer/vulkan/vulkan_stage_shader.c new file mode 100644 index 00000000..fb169353 --- /dev/null +++ b/source/renderer/vulkan/vulkan_stage_shader.c @@ -0,0 +1,55 @@ + +#include +#include + +#include +#include +#include + +vulkan_stage_shader_t* vulkan_stage_shader_new() +{ + vulkan_stage_shader_t* shader = heap_new(vulkan_stage_shader_t); + memset(shader, 0, sizeof(vulkan_stage_shader_t)); + return refp(vulkan_stage_shader_t, shader, 0); +} + +vulkan_stage_shader_t* vulkan_stage_shader_create(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t shader_type) +{ + vulkan_stage_shader_t* shader = vulkan_stage_shader_new(); + vulkan_stage_shader_create_no_alloc(renderer, spirv, length, shader_type, shader); + return shader; +} + +void vulkan_stage_shader_create_no_alloc(renderer_t* renderer, void* spirv, uint32_t length, vulkan_shader_type_t shader_type, vulkan_stage_shader_t* shader) +{ + assert(renderer->vk_device != VK_NULL_HANDLE); + assert(shader != NULL); + shader->module = vk_get_shader_module(renderer->vk_device, spirv, length); + shader->stage = vk_get_pipeline_shader_stage_create_info(refp(vulkan_stage_shader_t, shader, 0)->module, shader_type, "main"); +} + +void vulkan_stage_shader_load_and_create_no_alloc(renderer_t* renderer, const char* file_name, vulkan_shader_type_t shader_type, vulkan_stage_shader_t* shader) +{ + ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); + refp(vulkan_stage_shader_t, shader, 0)->module = vk_get_shader_module_load(renderer->vk_device, file_name); + refp(vulkan_stage_shader_t, shader, 0)->stage = vk_get_pipeline_shader_stage_create_info(refp(vulkan_stage_shader_t, shader, 0)->module, shader_type, "main"); +} + +vulkan_stage_shader_t* vulkan_stage_shader_load_and_create(renderer_t* renderer, const char* file_name, vulkan_shader_type_t shader_type) +{ + ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); + vulkan_stage_shader_t* shader = vulkan_stage_shader_new(); + vulkan_stage_shader_load_and_create_no_alloc(renderer, file_name, shader_type, shader); + return shader; +} + + +void vulkan_stage_shader_destroy(vulkan_stage_shader_t* shader, renderer_t* renderer) +{ + vkDestroyShaderModule(renderer->vk_device, refp(vulkan_stage_shader_t, shader, 0)->module, NULL); +} + +void vulkan_stage_shader_release_resources(vulkan_stage_shader_t* shader) +{ + heap_free(shader); +} diff --git a/source/renderer/vulkan/vulkan_swapchain.c b/source/renderer/vulkan/vulkan_swapchain.c index e4af9190..7bbcf4f3 100644 --- a/source/renderer/vulkan/vulkan_swapchain.c +++ b/source/renderer/vulkan/vulkan_swapchain.c @@ -14,62 +14,62 @@ vulkan_swapchain_t* vulkan_swapchain_new() { vulkan_swapchain_t* swapchain = heap_new(vulkan_swapchain_t); memset(swapchain, 0, sizeof(vulkan_swapchain_t)); - return refp(vulkan_swapchain_t, swapchain, 0); + return swapchain; } vulkan_swapchain_t* vulkan_swapchain_create(render_window_t* window, renderer_t* renderer) { ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); vulkan_swapchain_t* swapchain = vulkan_swapchain_new(); - refp(vulkan_swapchain_t, swapchain, 0)->window = window; + swapchain->window = window; //TODO: Make swapchain image count configurable - refp(vulkan_swapchain_t, swapchain, 0)->image_count = 3; - render_window_get_vulkan_surface(window, &(renderer->vk_instance), &(refp(vulkan_swapchain_t, swapchain, 0)->surface)); - create_swapchain(refp(vulkan_swapchain_t, swapchain, 0), renderer); - refp(vulkan_swapchain_t, swapchain, 0)->image_available_semaphore = vk_get_semaphore(renderer->vk_device); - refp(vulkan_swapchain_t, swapchain, 0)->render_finished_semaphore = vk_get_semaphore(renderer->vk_device); - return refp(vulkan_swapchain_t, swapchain, 0); + swapchain->image_count = 3; + render_window_get_vulkan_surface(window, &(renderer->vk_instance), &(swapchain->surface)); + create_swapchain(swapchain, renderer); + swapchain->image_available_semaphore = vk_get_semaphore(renderer->vk_device); + swapchain->render_finished_semaphore = vk_get_semaphore(renderer->vk_device); + return swapchain; } void vulkan_swapchain_refresh(vulkan_swapchain_t* swapchain, renderer_t* renderer) { - destroy_swapchain(refp(vulkan_swapchain_t, swapchain, 0), renderer); + destroy_swapchain(swapchain, renderer); VkSwapchainCreateInfoKHR create_info = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .minImageCount = refp(vulkan_swapchain_t, swapchain, 0)->image_count, + .minImageCount = swapchain->image_count, .imageFormat = VK_FORMAT_B8G8R8A8_SRGB, - .imageExtent = { refp(vulkan_swapchain_t, swapchain, 0)->window->width, refp(vulkan_swapchain_t, swapchain, 0)->window->height }, + .imageExtent = { swapchain->window->width, swapchain->window->height }, .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, .presentMode = VK_PRESENT_MODE_MAILBOX_KHR, .clipped = VK_TRUE, - .surface = refp(vulkan_swapchain_t, swapchain, 0)->surface, + .surface = swapchain->surface, .oldSwapchain = VK_NULL_HANDLE, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR }; - refp(vulkan_swapchain_t, swapchain, 0)->swapchain = vk_get_swapchain(renderer->vk_device, &create_info); - vk_get_images_out(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->swapchain, refp(vulkan_swapchain_t, swapchain, 0)->images, refp(vulkan_swapchain_t, swapchain, 0)->image_count); - vk_get_image_views_out(renderer->vk_device, VK_FORMAT_B8G8R8A8_SRGB, refp(vulkan_swapchain_t, swapchain, 0)->image_count, refp(vulkan_swapchain_t, swapchain, 0)->images, refp(vulkan_swapchain_t, swapchain, 0)->image_views); - vk_get_framebuffers_out(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->image_count, renderer->vk_render_pass, (VkExtent2D) { renderer->window->width, renderer->window->height }, 1, refp(vulkan_swapchain_t, swapchain, 0)->image_views, refp(vulkan_swapchain_t, swapchain, 0)->framebuffers); + swapchain->swapchain = vk_get_swapchain(renderer->vk_device, &create_info); + vk_get_images_out(renderer->vk_device, swapchain->swapchain, swapchain->images, swapchain->image_count); + vk_get_image_views_out(renderer->vk_device, VK_FORMAT_B8G8R8A8_SRGB, swapchain->image_count, swapchain->images, swapchain->image_views); + vk_get_framebuffers_out(renderer->vk_device, swapchain->image_count, renderer->vk_render_pass, (VkExtent2D) { renderer->window->width, renderer->window->height }, 1, swapchain->image_views, swapchain->framebuffers); } void vulkan_swapchain_destroy(vulkan_swapchain_t* swapchain, renderer_t* renderer) { ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); - destroy_semaphores(refp(vulkan_swapchain_t, swapchain, 0), renderer); - destroy_swapchain(refp(vulkan_swapchain_t, swapchain, 0), renderer); - vkDestroySurfaceKHR(renderer->vk_instance, refp(vulkan_swapchain_t, swapchain, 0)->surface, NULL); + destroy_semaphores(swapchain, renderer); + destroy_swapchain(swapchain, renderer); + vkDestroySurfaceKHR(renderer->vk_instance, swapchain->surface, NULL); } u32 vulkan_swapchain_acquire_next_image(vulkan_swapchain_t* swapchain, renderer_t* renderer) { ASSERT(renderer->vk_device != VK_NULL_HANDLE, "renderer->vk_device == VK_NULL_HANDLE\n"); - vkAcquireNextImageKHR(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->swapchain, UINT64_MAX, refp(vulkan_swapchain_t, swapchain, 0)->image_available_semaphore, VK_NULL_HANDLE, &(refp(vulkan_swapchain_t, swapchain, 0)->current_image_index)); - return refp(vulkan_swapchain_t, swapchain, 0)->current_image_index; + vkAcquireNextImageKHR(renderer->vk_device, swapchain->swapchain, UINT64_MAX, swapchain->image_available_semaphore, VK_NULL_HANDLE, &(swapchain->current_image_index)); + return swapchain->current_image_index; } void vulkan_swapchain_release_resources(vulkan_swapchain_t* swapchain) @@ -144,7 +144,7 @@ static void create_swapchain(vulkan_swapchain_t* swapchain, renderer_t* renderer ASSERT(swapchain->window != NULL, "swapchain->window == NULL\n"); ASSERT(renderer->vk_render_pass != VK_NULL_HANDLE, "renderer->vk_render_pass == VK_NULL_HANDLE\n"); VkBool32 is_supported; - vkCall(vkGetPhysicalDeviceSurfaceSupportKHR(renderer->vk_physical_device, renderer->vk_graphics_queue_index, refp(vulkan_swapchain_t, swapchain, 0)->surface, &is_supported)); + vkCall(vkGetPhysicalDeviceSurfaceSupportKHR(renderer->vk_physical_device, renderer->vk_graphics_queue_index, swapchain->surface, &is_supported)); ASSERT(is_supported == VK_TRUE, "surface not supported by the choosen physical device (GPU)\n"); VkSurfaceCapabilitiesKHR surface_capabilities; @@ -158,39 +158,39 @@ static void create_swapchain(vulkan_swapchain_t* swapchain, renderer_t* renderer VkSwapchainCreateInfoKHR create_info = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .minImageCount = refp(vulkan_swapchain_t, swapchain, 0)->image_count, + .minImageCount = swapchain->image_count, .imageFormat = VK_FORMAT_B8G8R8A8_SRGB, - .imageExtent = { refp(vulkan_swapchain_t, swapchain, 0)->window->width, refp(vulkan_swapchain_t, swapchain, 0)->window->height }, + .imageExtent = { swapchain->window->width, swapchain->window->height }, .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, .presentMode = VK_PRESENT_MODE_MAILBOX_KHR, .clipped = VK_TRUE, - .surface = refp(vulkan_swapchain_t, swapchain, 0)->surface, + .surface = swapchain->surface, .oldSwapchain = VK_NULL_HANDLE, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR }; - refp(vulkan_swapchain_t, swapchain, 0)->swapchain = vk_get_swapchain(renderer->vk_device, &create_info); - refp(vulkan_swapchain_t, swapchain, 0)->images = vk_get_images(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->swapchain).value2; - refp(vulkan_swapchain_t, swapchain, 0)->image_views = vk_get_image_views(renderer->vk_device, VK_FORMAT_B8G8R8A8_SRGB, refp(vulkan_swapchain_t, swapchain, 0)->image_count, refp(vulkan_swapchain_t, swapchain, 0)->images).value2; - refp(vulkan_swapchain_t, swapchain, 0)->framebuffers = vk_get_framebuffers(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->image_count, renderer->vk_render_pass, (VkExtent2D) { renderer->window->width, renderer->window->height }, 1, refp(vulkan_swapchain_t, swapchain, 0)->image_views).value2; - refp(vulkan_swapchain_t, swapchain, 0)->current_image_index = 0; + swapchain->swapchain = vk_get_swapchain(renderer->vk_device, &create_info); + swapchain->images = vk_get_images(renderer->vk_device, swapchain->swapchain).value2; + swapchain->image_views = vk_get_image_views(renderer->vk_device, VK_FORMAT_B8G8R8A8_SRGB, swapchain->image_count, swapchain->images).value2; + swapchain->framebuffers = vk_get_framebuffers(renderer->vk_device, swapchain->image_count, renderer->vk_render_pass, (VkExtent2D) { renderer->window->width, renderer->window->height }, 1, swapchain->image_views).value2; + swapchain->current_image_index = 0; } static void destroy_semaphores(vulkan_swapchain_t* swapchain, renderer_t* renderer) { - vkDestroySemaphore(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->image_available_semaphore, NULL); - vkDestroySemaphore(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->render_finished_semaphore, NULL); + vkDestroySemaphore(renderer->vk_device, swapchain->image_available_semaphore, NULL); + vkDestroySemaphore(renderer->vk_device, swapchain->render_finished_semaphore, NULL); } static void destroy_swapchain(vulkan_swapchain_t* swapchain, renderer_t* renderer) { - vkDestroySwapchainKHR(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->swapchain, NULL); - for(u32 i = 0; i < refp(vulkan_swapchain_t, swapchain, 0)->image_count; i++) - vkDestroyFramebuffer(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->framebuffers[i], NULL); - for(u32 i = 0; i < refp(vulkan_swapchain_t, swapchain, 0)->image_count; i++) - vkDestroyImageView(renderer->vk_device, refp(vulkan_swapchain_t, swapchain, 0)->image_views[i], NULL); + vkDestroySwapchainKHR(renderer->vk_device, swapchain->swapchain, NULL); + for(u32 i = 0; i < swapchain->image_count; i++) + vkDestroyFramebuffer(renderer->vk_device, swapchain->framebuffers[i], NULL); + for(u32 i = 0; i < swapchain->image_count; i++) + vkDestroyImageView(renderer->vk_device, swapchain->image_views[i], NULL); } diff --git a/source/renderer/vulkan/vulkan_wrapper.c b/source/renderer/vulkan/vulkan_wrapper.c index caa9839e..82c36d5e 100644 --- a/source/renderer/vulkan/vulkan_wrapper.c +++ b/source/renderer/vulkan/vulkan_wrapper.c @@ -18,6 +18,21 @@ define_exception(VULKAN_SURFACE_NOT_SUPPORTED); define_exception(VULKAN_PHYSICAL_DEVICE_EXTENSION_NOT_SUPPORTED); define_exception(VULKAN_UNSUPPORTED_SHADER_TYPE); + +function_signature(VkDescriptorSetLayout, vk_get_descriptor_set_layout, VkDevice device, VkDescriptorSetLayoutBinding* bindings, uint32_t binding_count) +{ + CALLTRACE_BEGIN(); + VkDescriptorSetLayoutCreateInfo layout_create_info = + { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = binding_count, + .pBindings = bindings + }; + VkDescriptorSetLayout set_layout; + vkCall(vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &set_layout)); + CALLTRACE_RETURN(set_layout); +} + /*---------- COMMAND BUFFERS ------------ */ function_signature(VkCommandBuffer, vk_get_begin_single_time_command_buffer, VkDevice device, VkCommandPool command_pool) { @@ -137,16 +152,21 @@ function_signature(VkSemaphore, vk_get_semaphore, VkDevice device) CALLTRACE_RETURN(semaphore); } -function_signature(VkDescriptorPool, vk_get_descripter_pool, VkDevice device) +function_signature(VkDescriptorPool, vk_get_descriptor_pool, VkDevice device) { CALLTRACE_BEGIN(); - VkDescriptorPoolSize pool_size = { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 3 }; + VkDescriptorPoolSize sizes[2] = + { + { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 2 }, + { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 2 } + }; VkDescriptorPoolCreateInfo pool_create_info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .poolSizeCount = 1, - .pPoolSizes = &pool_size, - .maxSets = 3 + .poolSizeCount = 2, + .pPoolSizes = &sizes[0], + .maxSets = 6, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT }; VkDescriptorPool descriptor_pool; vkCall(vkCreateDescriptorPool(device, &pool_create_info, NULL, &descriptor_pool)); @@ -545,11 +565,10 @@ function_signature(VkPipelineShaderStageCreateInfo, vk_get_pipeline_shader_stage throw_exception(VULKAN_UNSUPPORTED_SHADER_TYPE); break; } - createInfo.stage = (vulkan_shader_type == VULKAN_SHADER_TYPE_VERTEX) ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT; CALLTRACE_RETURN(createInfo); } -function_signature(VkShaderModule, vk_get_shader_module, VkDevice device, void* spirv, uint32_t length, vulkan_shader_type_t shader_type) +function_signature(VkShaderModule, vk_get_shader_module, VkDevice device, void* spirv, uint32_t length) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; diff --git a/source/struct_descriptor.c b/source/struct_descriptor.c new file mode 100644 index 00000000..476a80d4 --- /dev/null +++ b/source/struct_descriptor.c @@ -0,0 +1,287 @@ + +#include +#include +#include +#include + +/* + COMPUTING PADDING + The following formulas provide the number of padding bytes required to align the start of a data structure + (where mod is the modulo operator): + padding = (align - (offset mod align)) mod align + aligned = offset + padding + = offset + ((align - (offset mod align)) mod align) + Since the alignment is by definition a power of two,[a] the modulo operation can be reduced to a bitwise boolean AND operation. + padding = (align - (offset & (align - 1))) & (align - 1) + = (-offset & (align - 1)) + aligned = (offset + (align - 1)) & ~(align - 1) + = (offset + (align - 1)) & -align + */ + +void struct_descriptor_recalculate(struct_descriptor_t* descriptor) +{ + assert(descriptor != NULL); + if((descriptor->fields == 0) || (descriptor->field_count == 0) || (descriptor->field_count == 0xFFFF)) + return; + struct_field_t* fields = descriptor->fields; + u32 offset = 0; + descriptor->size = 0; + for(u16 i = 0; i < descriptor->field_count; i++) + { + u16 align = fields[i].alignment; + fields[i].offset = ((align - (offset % align)) % align) + offset; + offset = fields[i].offset + fields[i].size; + } + descriptor->size = offset; +} + +void struct_descriptor_map(struct_descriptor_t* descriptor, void* ptr) +{ + assert(descriptor != NULL); + descriptor->ptr = ptr; +} + +void struct_descriptor_unmap(struct_descriptor_t* descriptor) +{ + assert(descriptor != NULL); + descriptor->ptr = NULL; +} + +u32 struct_descriptor_sizeof(struct_descriptor_t* descriptor) +{ + assert(descriptor != NULL); + return descriptor->size; +} + +struct_field_handle_t struct_descriptor_get_field_handle(struct_descriptor_t* descriptor, const char* field_name) +{ + assert(descriptor != NULL); + assert(descriptor->field_count < 0xFFFF); + for(u16 i = 0; i < descriptor->field_count; i++) + if(strcmp(descriptor->fields[i].name, field_name) == 0) + return i; + LOG_WRN("Returning STRUCT_FIELD_INVALID_HANDLE, field_name: %s\n", field_name); + return STRUCT_FIELD_INVALID_HANDLE; +} + +#ifndef GLOBAL_DEBUG +# define check_precondition(descriptor, handle) +#else + static void check_precondition(struct_descriptor_t* descriptor, struct_field_handle_t handle); +#endif + +#define cpy_data_from(descriptor, handle, data) __cpy_data_from(descriptor, handle, data, descriptor->fields[handle].size) +#define cpy_data_to(descriptor, handle, data) __cpy_data_to(descriptor, handle, data, descriptor->fields[handle].size) + +static inline void __cpy_data_from(struct_descriptor_t* descriptor, struct_field_handle_t handle, const void* const data, u16 size) +{ + memcpy(descriptor->ptr + descriptor->fields[handle].offset, data, size); +} + +static inline void __cpy_data_to(struct_descriptor_t* descriptor, struct_field_handle_t handle, void* const data, u16 size) +{ + memcpy(data, descriptor->ptr + descriptor->fields[handle].offset, size); +} + +void struct_descriptor_set_value(struct_descriptor_t* descriptor, struct_field_handle_t handle, const void* const in) +{ + check_precondition(descriptor, handle); + cpy_data_from(descriptor, handle, in); +} + +void struct_descriptor_set_float(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 4); +} + +void struct_descriptor_set_int(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 4); +} + +void struct_descriptor_set_uint(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 4); +} + +void struct_descriptor_set_vec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 16); +} + +void struct_descriptor_set_vec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 12); +} + +void struct_descriptor_set_vec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 8); +} + +void struct_descriptor_set_ivec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 16); +} + +void struct_descriptor_set_ivec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 12); +} + +void struct_descriptor_set_ivec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const int* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 8); +} + +void struct_descriptor_set_uvec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 16); +} + +void struct_descriptor_set_uvec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 12); +} + +void struct_descriptor_set_uvec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const uint* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 8); +} + +void struct_descriptor_set_mat4(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 64); +} + +void struct_descriptor_set_mat3(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 36); +} + +void struct_descriptor_set_mat2(struct_descriptor_t* descriptor, struct_field_handle_t handle, const float* const in) +{ + check_precondition(descriptor, handle); + __cpy_data_from(descriptor, handle, in, 16); +} + +void struct_descriptor_get_value(struct_descriptor_t* descriptor, struct_field_handle_t handle, void* const out) +{ + check_precondition(descriptor, handle); + cpy_data_to(descriptor, handle, out); +} + +void struct_descriptor_get_float(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 4); +} + +void struct_descriptor_get_int(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 4); +} + +void struct_descriptor_get_uint(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 4); +} + +void struct_descriptor_get_vec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 16); +} + +void struct_descriptor_get_vec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 12); +} + +void struct_descriptor_get_vec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 8); +} + +void struct_descriptor_get_ivec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 16); +} + +void struct_descriptor_get_ivec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 12); +} + +void struct_descriptor_get_ivec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, int* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 8); +} + +void struct_descriptor_get_uvec4(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 16); +} + +void struct_descriptor_get_uvec3(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 12); +} + +void struct_descriptor_get_uvec2(struct_descriptor_t* descriptor, struct_field_handle_t handle, uint* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 8); +} + +void struct_descriptor_get_mat4(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 64); +} + +void struct_descriptor_get_mat3(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 36); +} + +void struct_descriptor_get_mat2(struct_descriptor_t* descriptor, struct_field_handle_t handle, float* const out) +{ + check_precondition(descriptor, handle); + __cpy_data_to(descriptor, handle, out, 16); +} + + +#ifdef GLOBAL_DEBUG +static void check_precondition(struct_descriptor_t* descriptor, struct_field_handle_t handle) +{ + assert(descriptor != NULL); + assert(descriptor->ptr != NULL); + assert(descriptor->fields != NULL); + assert(handle < descriptor->field_count); +} +#endif diff --git a/testbed/makefile b/testbed/makefile index 9b45892d..dbbc6f1a 100644 --- a/testbed/makefile +++ b/testbed/makefile @@ -18,11 +18,11 @@ EXECUTABLE_NAME = main.exe EXTERNAL_LIBRARIES = -L..\external-dependency-libs -lvulkan-1 -lglfw3 -lgdi32 -lfreetype.dll EXTERNAL_INCLUDES = -I./dependencies/ -I./shared-dependencies #TODO: Move EntityComponentSystem from VulkanRenderer to TestBed -DEPENDENCIES = .. ../testbed/dependencies/EntityComponentSystem MeshLib MeshLib/dependencies/DiskManager HPML tgc SafeMemory SafeMemory/shared-dependencies/CallTrace TemplateSystem MeshLib/dependencies/DiskManager ttf2mesh -DEPENDENCY_LIBS = ../lib/vulkanrenderer.a ../testbed/dependencies/EntityComponentSystem/lib/ecs.a MeshLib/lib/meshlib.a MeshLib/dependencies/DiskManager/lib/diskmanager.a HPML/lib/hpml.a SafeMemory/shared-dependencies/CallTrace/lib/calltrace.a SafeMemory/lib/safemem.a tgc/lib/tgc.a ttf2mesh/lib/ttf2mesh.a +DEPENDENCIES = .. ../testbed/dependencies/EntityComponentSystem MeshLib MeshLib/dependencies/DiskManager HPML tgc SafeMemory SafeMemory/shared-dependencies/CallTrace TemplateSystem MeshLib/dependencies/DiskManager ttf2mesh ../shared-dependencies/BufferLib +DEPENDENCY_LIBS = ../lib/vulkanrenderer.a ../testbed/dependencies/EntityComponentSystem/lib/ecs.a MeshLib/lib/meshlib.a MeshLib/dependencies/DiskManager/lib/diskmanager.a HPML/lib/hpml.a SafeMemory/lib/safemem.a tgc/lib/tgc.a ttf2mesh/lib/ttf2mesh.a ../shared-dependencies/BufferLib/lib/bufferlib.a SafeMemory/shared-dependencies/CallTrace/lib/calltrace.a DEPENDENCIES_DIR = ../dependencies -SHARED_DEPENDENCIES = BufferLib -SHARED_DEPENDENCY_LIBS = BufferLib/lib/bufferlib.a +SHARED_DEPENDENCIES = +SHARED_DEPENDENCY_LIBS = SHARED_DEPENDENCIES_DIR = ../shared-dependencies #------------------------------------------- @@ -168,7 +168,7 @@ $(TARGET): $(__DEPENDENCY_LIBS) $(__SHARED_DEPENDENCY_LIBS) $(TARGET_STATIC_LIB) @echo [Log] Linking $@ ... $(COMPILER) $(COMPILER_FLAGS) source/main.o \ $(addprefix -L, $(dir $(TARGET_STATIC_LIB) $(__DEPENDENCY_LIBS) $(__SHARED_DEPENDENCY_LIBS))) \ - $(addprefix -l:, $(notdir $(TARGET_STATIC_LIB) $(__DEPENDENCY_LIBS) $(__SHARED_DEPENDENCY_LIBS))) \ + $(addprefix -l:, $(notdir $(TARGET_STATIC_LIB) $(__SHARED_DEPENDENCY_LIBS) $(__DEPENDENCY_LIBS))) \ $(LIBS) -o $@ @echo [Log] $(PROJECT_NAME) built successfully! @@ -210,6 +210,7 @@ clean: bin-clean .PHONY: build .PHONY: build-run +.PHONY: run build: $(MAKE) --directory=.. lib-static-debug @@ -217,3 +218,6 @@ build: build-run: build $(__EXECUTABLE_NAME) + +run: build-run + \ No newline at end of file diff --git a/testbed/resource/shaders/albedo_shader.glsl b/testbed/resource/shaders/albedo_shader.glsl index bd47290a..1b8b7206 100644 --- a/testbed/resource/shaders/albedo_shader.glsl +++ b/testbed/resource/shaders/albedo_shader.glsl @@ -1,3 +1,40 @@ +#section SETTINGS DEFAULT + +wireframe true +line_thickness 5 +blend true +winding clockwise + + +//TODO: Make vertex attributes programmable in this file as followings: +per-vertex [0] vec3 position; +per-vertex [1] vec3 normal; +per-vertex [2] vec3 color; +per-vertex [3] vec2 cootex_rd; + +per-instance[0] vec3 offset; + + +#section LAYOUT + +fragment[0, 0] uniform sampler2D texture; +fragment[0, 1] uniform sampler2D texture2; +fragment[0, 2] uniform SceneData +{ + vec3 green_color; + float time; + uint value; +} scene_data; + +fragment[0, 3] uniform Light +{ + vec3 dir; + float intensity; +} light; + + + +#section SHADER #stage vertex @@ -6,7 +43,7 @@ layout(push_constant) uniform Push { mat4 mvp_matrix; -} push; +}; layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNormal; @@ -19,7 +56,7 @@ layout(location = 2) out vec2 texCoord; void main() { - vec4 v = push.mvp_matrix * vec4(inPosition, 1.0); + vec4 v = mvp_matrix * vec4(inPosition, 1.0); gl_Position = v; fragColor = inColor; normal = inNormal; @@ -37,13 +74,25 @@ layout(location = 0) in vec3 fragColor; layout(location = 1) in vec3 normal; layout(location = 2) in vec2 texCoord; -layout(binding = 0) uniform sampler2D texSampler; +layout(set = 0, binding = 0) uniform sampler2D texSampler; +layout(set = 0, binding = 1) uniform sampler2D texSampler2; +layout(set = 0, binding = 2) uniform SceneData +{ + vec3 green_color; + float time; + uint value; +}; +layout(set = 0, binding = 3) uniform Light +{ + vec3 dir; + float intensity; +} light; -float dot_product(vec3 v1, vec3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } void main() { - vec3 lightDir = normalize(vec3(1, -1, 0.1)); - color = fragColor * (max(0, dot(lightDir, -normal)) + 0.1f); - color = color * texture(texSampler, texCoord).xyz; + color = fragColor * (max(0, dot(light.dir, -normal)) + 0.1f); + float t = (1 - sin(time)) * 0.5; + vec3 texture_color = (texture(texSampler, texCoord).xyz * t + (1 - t) * texture(texSampler2, texCoord).xyz); + color = color * green_color * light.intensity * texture_color; } diff --git a/testbed/resource/shaders/color_shader.glsl b/testbed/resource/shaders/color_shader.glsl index a870fae6..3af7db7c 100644 --- a/testbed/resource/shaders/color_shader.glsl +++ b/testbed/resource/shaders/color_shader.glsl @@ -1,4 +1,6 @@ +#section SHADER + #stage vertex #version 450 diff --git a/testbed/resource/shaders/font_shader.glsl b/testbed/resource/shaders/font_shader.glsl index 5049361c..97d9fa40 100644 --- a/testbed/resource/shaders/font_shader.glsl +++ b/testbed/resource/shaders/font_shader.glsl @@ -1,4 +1,6 @@ +#section SHADER + #stage vertex #version 450 diff --git a/testbed/resource/shaders/instanced_color_shader.glsl b/testbed/resource/shaders/instanced_color_shader.glsl index 14377e34..2493133c 100644 --- a/testbed/resource/shaders/instanced_color_shader.glsl +++ b/testbed/resource/shaders/instanced_color_shader.glsl @@ -1,4 +1,6 @@ +#section SHADER + #stage vertex #version 450 diff --git a/testbed/resource/shaders/text_shader.glsl b/testbed/resource/shaders/text_shader.glsl index 20d54313..a0ad0ead 100644 --- a/testbed/resource/shaders/text_shader.glsl +++ b/testbed/resource/shaders/text_shader.glsl @@ -1,12 +1,16 @@ - +#section SHADER #stage vertex #version 450 +layout(binding = 0) uniform UniformBufferObject +{ + float time; +} ubo; + layout(push_constant) uniform Push { - //model view project matrix mat4 mvp; } push; @@ -35,3 +39,5 @@ void main() { color = vec3(1, 1, 1); } + + diff --git a/testbed/resource/textures/applelogo.bmp b/testbed/resource/textures/applelogo.bmp new file mode 100644 index 00000000..d2dc6453 Binary files /dev/null and b/testbed/resource/textures/applelogo.bmp differ diff --git a/testbed/resource/textures/windowslogo.bmp b/testbed/resource/textures/windowslogo.bmp new file mode 100644 index 00000000..2ffa07f3 Binary files /dev/null and b/testbed/resource/textures/windowslogo.bmp differ diff --git a/testbed/source/main.c b/testbed/source/main.c index f16afd5d..be8b60ca 100644 --- a/testbed/source/main.c +++ b/testbed/source/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,7 @@ static void offset_visitor(vec3_t(float)* position, void* user_data) int main(int argc, char** argv) { memory_allocator_init(&argc); + renderer_t* renderer = renderer_init(800, 800, "Vulkan 3D Renderer", false); recreate_matrix(renderer_get_window(renderer), NULL); render_window_subscribe_on_resize(renderer_get_window(renderer), recreate_matrix, NULL); @@ -68,14 +70,14 @@ int main(int argc, char** argv) shader_t* text_shader = shader_load(renderer, "resource/shaders/text_shader.sb"); font_t* font = font_load_and_create("resource/fonts/arial.ttf"); text_mesh_t* text = text_mesh_create(font); - text_mesh_set_string(text, renderer, "Vulkan 3D Engine"); + text_mesh_set_string(text, renderer, "Vulkan 3D Renderer"); // text_mesh_set_size(text, 100); material_create_info_t text_material_info = { .per_vertex_attributes = MATERIAL_ALIGN(MATERIAL_VEC3, 0), //position .per_instance_attributes = MATERIAL_ALIGN(MATERIAL_VEC3, 0), //offset - .shader = text_shader + .shader = text_shader, }; material_t* text_material = material_create(renderer, &text_material_info); /*---------------------------------------*/ @@ -85,42 +87,58 @@ int main(int argc, char** argv) mesh3d_t* cube_mesh3d = mesh3d_cube(1); mesh_t* cube = mesh_create(renderer, cube_mesh3d); texture_t* linux_texture = texture_load(renderer, "resource/textures/linuxlogo.bmp"); + texture_t* windows_texture = texture_load(renderer, "resource/textures/windowslogo.bmp"); + texture_t* apple_texture = texture_load(renderer, "resource/textures/applelogo.bmp"); material_create_info_t cube_material_info = { .per_vertex_attributes = MATERIAL_ALIGN(MATERIAL_VEC3, 0) //position | MATERIAL_ALIGN(MATERIAL_VEC3, 1) //normal | MATERIAL_ALIGN(MATERIAL_VEC3, 2) //color | MATERIAL_ALIGN(MATERIAL_VEC2, 3), //texture coordinates - .shader = albedo_shader + .shader = albedo_shader, }; material_t* cube_material = material_create(renderer, &cube_material_info); - material_set_texture(cube_material,renderer, linux_texture); + + material_set_texture2d(cube_material, "texture", linux_texture); + material_set_texture2d(cube_material, "texture2", windows_texture); /*---------------------------------------*/ time_handle_t frame_time_handle = time_get_handle(); time_handle_t second_time_handle = time_get_handle(); + time_handle_t game_time_handle = time_get_handle(); u32 frame_count = 0; float angle = 0; + u32 texture_index = 0; + material_field_handle_t handle = material_get_field_handle(cube_material, "scene_data.time"); //TODO: render loop should run on separate thread -> render thread while(renderer_is_running(renderer)) { float delta_time = time_get_delta_time(&frame_time_handle); + float game_time = time_get_seconds(game_time_handle); + mat4_t(float) model_matrix = mat4_rotation(float)(0, angle * DEG2RAD, 0); + material_set_floatH(cube_material, handle, game_time); + material_set_uint(cube_material, "scene_data.value", 2); + material_set_vec3(cube_material, "scene_data.green_color", vec3(float)(1, 1, 0)); + material_set_vec3(cube_material, "light.dir", vec3(float)(0, -1, 0)); + material_set_float(cube_material, "light.intensity", 1.0f); + renderer_begin_frame(renderer, 0, 0, 0, 0); material_bind(cube_material, renderer); - mat4_t(float) mvp = mat4_mul(float)(3, clip_matrix, projection_matrix, view_matrix); + mat4_t(float) mvp = mat4_mul(float)(4, clip_matrix, projection_matrix, view_matrix, model_matrix); mat4_move(float)(&mvp, mat4_transpose(float)(mvp)); material_push_constants(cube_material, renderer, &mvp); mesh_draw_indexed(cube, renderer); material_bind(text_material, renderer); mat4_t(float) canvas_transform = mat4_mul(float)(2, clip_matrix, screen_space_matrix); - mat4_t(float) model_matrix = mat4_mul(float)(2, mat4_translation(float)(0, 0, -700), mat4_scale(float)(0, 70, 70)); - mat4_move(float)(&canvas_transform, mat4_transpose(float)(mat4_mul(float)(2, canvas_transform, model_matrix))); + mat4_t(float) _model_matrix = mat4_mul(float)(2, mat4_translation(float)(0, -(int)renderer_get_window(renderer)->height * 0.5f + 40, -250), mat4_scale(float)(0, 50, 50)); + mat4_move(float)(&canvas_transform, mat4_transpose(float)(mat4_mul(float)(2, canvas_transform, _model_matrix))); material_push_constants(text_material, renderer, &canvas_transform); text_mesh_draw(text, renderer); renderer_end_frame(renderer); + renderer_update(renderer); angle += 180 * delta_time; if(angle >= 360.0f) @@ -129,9 +147,19 @@ int main(int argc, char** argv) float seconds = time_get_seconds(second_time_handle); if(seconds >= 1) { - printf("FPS: %u\n", (int)((int)frame_count / seconds)); + printf("FPS: %u, TIME: %.3f\n", (int)((int)frame_count / seconds), game_time); second_time_handle = time_get_handle(); frame_count = 0; + texture_index++; + texture_index = texture_index % 3; + switch(texture_index) + { + case 0: material_set_texture2d(cube_material, "texture", linux_texture); break; + case 1: material_set_texture2d(cube_material, "texture", windows_texture); break; + case 2: material_set_texture2d(cube_material, "texture", apple_texture); break; + default: + assert(false); + } } ++frame_count; } @@ -154,6 +182,10 @@ int main(int argc, char** argv) material_release_resources(cube_material); texture_destroy(linux_texture, renderer); texture_release_resources(linux_texture); + texture_destroy(windows_texture, renderer); + texture_release_resources(windows_texture); + texture_destroy(apple_texture, renderer); + texture_release_resources(apple_texture); renderer_terminate(renderer); memory_allocator_terminate();