diff options
-rw-r--r-- | assets/shaders/cube.frag | 12 | ||||
-rw-r--r-- | assets/shaders/cube.vert | 7 | ||||
-rw-r--r-- | examples/cube/ex_cube.c | 25 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.c | 200 | ||||
-rw-r--r-- | src/renderer/backends/backend_vulkan.h | 3 | ||||
-rw-r--r-- | src/renderer/ral.h | 2 | ||||
-rw-r--r-- | src/renderer/ral_types.h | 6 | ||||
-rw-r--r-- | src/renderer/render.c | 3 | ||||
-rw-r--r-- | xmake.lua | 1 |
9 files changed, 191 insertions, 68 deletions
diff --git a/assets/shaders/cube.frag b/assets/shaders/cube.frag index e69de29..11f1efa 100644 --- a/assets/shaders/cube.frag +++ b/assets/shaders/cube.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoord; + +layout(binding = 1) uniform sampler2D texSampler; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = texture(texSampler, fragTexCoord); // vec4(fragTexCoord, 0.0); +} diff --git a/assets/shaders/cube.vert b/assets/shaders/cube.vert index 1818c3c..fa9f85b 100644 --- a/assets/shaders/cube.vert +++ b/assets/shaders/cube.vert @@ -4,16 +4,17 @@ layout(binding = 0) uniform UniformBufferObject { mat4 model; mat4 view; mat4 proj; -} -ubo; +} ubo; layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNormal; -layout(location = 2) in vec3 inTexCoords; +layout(location = 2) in vec2 inTexCoords; layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoord; void main() { gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); fragColor = abs(inNormal); + fragTexCoord = inTexCoords; } diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c index 80a4e26..5d6cbbe 100644 --- a/examples/cube/ex_cube.c +++ b/examples/cube/ex_cube.c @@ -22,20 +22,30 @@ typedef struct mvp_uniforms { mat4 view; mat4 projection; } mvp_uniforms; +typedef struct my_shader_bind_group { + mvp_uniforms mvp; + texture_handle tex; +} my_shader_bind_group; // We also must create a function that knows how to return a `shader_data_layout` shader_data_layout mvp_uniforms_layout(void* data) { - mvp_uniforms* d = (mvp_uniforms*)data; + my_shader_bind_group* d = (my_shader_bind_group*)data; bool has_data = data != NULL; shader_binding b1 = { .label = "mvp_uniforms", .type = SHADER_BINDING_BYTES, .stores_data = has_data, .data = { .bytes = { .size = sizeof(mvp_uniforms) } } }; + + shader_binding b2 = { .label = "texture_sampler", + .type = SHADER_BINDING_TEXTURE, + .stores_data = has_data + }; if (has_data) { - b1.data.bytes.data = d; + b1.data.bytes.data = &d->mvp; + b2.data.texture.handle = d->tex; } - return (shader_data_layout){ .name = "global_ubo", .bindings = { b1 }, .bindings_count = 1 }; + return (shader_data_layout){ .name = "global_ubo", .bindings = { b1, b2 }, .bindings_count = 2 }; } int main() { @@ -60,7 +70,7 @@ int main() { gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description); str8 vert_path = str8lit("build/linux/x86_64/debug/cube.vert.spv"); - str8 frag_path = str8lit("build/linux/x86_64/debug/triangle.frag.spv"); + str8 frag_path = str8lit("build/linux/x86_64/debug/cube.frag.spv"); str8_opt vertex_shader = str8_from_file(&scratch, vert_path); str8_opt fragment_shader = str8_from_file(&scratch, frag_path); if (!vertex_shader.has_value || !fragment_shader.has_value) { @@ -93,6 +103,7 @@ int main() { // Texture texture_data tex_data = texture_data_load("assets/textures/texture.jpg", false); texture_handle texture = texture_data_upload(tex_data, true); + printf("Texture %d", texture.raw); // Main loop while (!should_exit(&g_core)) { @@ -118,7 +129,11 @@ int main() { camera_view_projection(&cam, g_core.renderer.swapchain.extent.width, g_core.renderer.swapchain.extent.height, &view, &proj); mvp_uniforms mvp_data = { .model = model, .view = view, .projection = proj }; - mvp_uniforms_data.data = &mvp_data; + my_shader_bind_group shader_bind_data = { + .mvp = mvp_data, + .tex = texture + }; + mvp_uniforms_data.data = &shader_bind_data; encode_bind_shader_data(enc, 0, &mvp_uniforms_data); // Record draw calls diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c index 33e0860..e8b54d9 100644 --- a/src/renderer/backends/backend_vulkan.c +++ b/src/renderer/backends/backend_vulkan.c @@ -92,8 +92,12 @@ VkShaderModule create_shader_module(str8 spirv); /** @brief Helper function for creating array of all extensions we want */ cstr_darray* get_all_extensions(); +void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout, + VkImageLayout new_layout); + // --- Handy macros #define BUFFER_GET(h) (buffer_pool_get(&context.resource_pools->buffers, h)) +#define TEXTURE_GET(h) (texture_pool_get(&context.resource_pools->textures, h)) bool gpu_backend_init(const char* window_name, GLFWwindow* window) { memset(&context, 0, sizeof(vulkan_context)); @@ -571,24 +575,24 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip // assert(description.data_layouts_count == 1); printf("data layouts %d\n", description.data_layouts_count); - for (u32 i = 0; i < description.data_layouts_count; i++) { - shader_data_layout sdl = description.data_layouts[i].shader_data_get_layout(NULL); + for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) { + shader_data_layout sdl = description.data_layouts[layout_i].shader_data_get_layout(NULL); + TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.bindings_count); - // NOTE: is using VLA generally ok? - VkDescriptorSetLayoutBinding desc_set_bindings[description.data_layouts_count]; + VkDescriptorSetLayoutBinding desc_set_bindings[sdl.bindings_count]; // Bindings - assert(sdl.bindings_count == 1); - for (u32 j = 0; j < sdl.bindings_count; j++) { - desc_set_bindings[j].binding = j; - desc_set_bindings[j].descriptorCount = 1; - switch (sdl.bindings[j].type) { + assert(sdl.bindings_count == 2); + for (u32 binding_j = 0; binding_j < sdl.bindings_count; binding_j++) { + desc_set_bindings[binding_j].binding = binding_j; + desc_set_bindings[binding_j].descriptorCount = 1; + switch (sdl.bindings[binding_j].type) { case SHADER_BINDING_BUFFER: case SHADER_BINDING_BYTES: - desc_set_bindings[j].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - desc_set_bindings[j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; // FIXME: dont hardcode + desc_set_bindings[binding_j].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; // FIXME: dont hardcode - u64 buffer_size = sdl.bindings[j].data.bytes.size; + u64 buffer_size = sdl.bindings[binding_j].data.bytes.size; VkDeviceSize uniform_buf_size = buffer_size; // TODO: Create backing buffer @@ -617,18 +621,24 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip sizeof(uniform_buf_mem_mappings)); uniform_data.size = buffer_size; - pipeline->uniform_pointers[j] = uniform_data; + pipeline->uniform_pointers[binding_j] = uniform_data; + + break; + case SHADER_BINDING_TEXTURE: + desc_set_bindings[binding_j].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; // FIXME: dont hardcode + desc_set_bindings[binding_j].pImmutableSamplers = NULL; break; default: ERROR_EXIT("Unimplemented binding type!! in backend_vulkan"); } - switch (sdl.bindings[j].vis) { + switch (sdl.bindings[binding_j].vis) { case VISIBILITY_VERTEX: - desc_set_bindings[j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; break; case VISIBILITY_FRAGMENT: - desc_set_bindings[j].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + desc_set_bindings[binding_j].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; break; case VISIBILITY_COMPUTE: WARN("Compute is not implemented yet"); @@ -643,7 +653,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip desc_set_layout_info.pBindings = desc_set_bindings; VK_CHECK(vkCreateDescriptorSetLayout(context.device->logical_device, &desc_set_layout_info, - context.allocator, &desc_set_layouts[i])); + context.allocator, &desc_set_layouts[layout_i])); } printf("Descriptor set layouts\n"); @@ -683,17 +693,15 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; pipeline_create_info.basePipelineIndex = -1; - printf("Here\n"); + printf("About to create graphics pipeline\n"); VkResult result = vkCreateGraphicsPipelines(context.device->logical_device, VK_NULL_HANDLE, 1, &pipeline_create_info, context.allocator, &pipeline->handle); if (result != VK_SUCCESS) { - printf("BAD\n"); FATAL("graphics pipeline creation failed. its fked mate"); ERROR_EXIT("Doomed"); } - printf("Here2\n"); TRACE("Vulkan Graphics pipeline created"); // once the pipeline has been created we can destroy these @@ -810,13 +818,17 @@ gpu_cmd_encoder gpu_cmd_encoder_create() { VK_CHECK(vkAllocateCommandBuffers(context.device->logical_device, &allocate_info, &encoder.cmd_buffer);); - VkDescriptorPoolSize uniform_pool_size; - uniform_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uniform_pool_size.descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; + VkDescriptorPoolSize pool_sizes[2]; + // Uniforms pool + pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + pool_sizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; + // Samplers pool + pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + pool_sizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT * MAX_DESCRIPTOR_SETS; VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &uniform_pool_size; + pool_info.poolSizeCount = 2; + pool_info.pPoolSizes = pool_sizes; pool_info.maxSets = 100; VK_CHECK(vkCreateDescriptorPool(context.device->logical_device, &pool_info, context.allocator, @@ -875,6 +887,8 @@ void encode_bind_pipeline(gpu_cmd_encoder* encoder, pipeline_kind kind, gpu_pipe } void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* data) { + arena tmp = arena_create(malloc(1024), 1024); + assert(data->data != NULL); // Update the local buffer @@ -886,44 +900,62 @@ void encode_bind_shader_data(gpu_cmd_encoder* encoder, u32 group, shader_data* d alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &encoder->pipeline->desc_set_layouts[group]; - VkDescriptorSet sets[1]; + shader_data_layout sdl = data->shader_data_get_layout(data->data); + size_t binding_count = sdl.bindings_count; + assert(binding_count == 2); + + VkDescriptorSet sets[0]; VK_CHECK(vkAllocateDescriptorSets(context.device->logical_device, &alloc_info, sets)); + // FIXME: hardcoded VkDescriptorSet_darray_push(context.free_set_queue, sets[0]); + /* VkDescriptorSet_darray_push(context.free_set_queue, sets[1]); */ - shader_data_layout sdl = data->shader_data_get_layout(NULL); - assert(sdl.bindings_count == 1); - - VkWriteDescriptorSet write_sets[1]; - memset(&write_sets, 0, sizeof(write_sets)); + VkWriteDescriptorSet write_sets[binding_count]; + memset(&write_sets, 0, binding_count * sizeof(VkWriteDescriptorSet)); - assert(sdl.bindings_count == 1); for (u32 i = 0; i < sdl.bindings_count; i++) { shader_binding binding = sdl.bindings[i]; if (binding.type == SHADER_BINDING_BUFFER || binding.type == SHADER_BINDING_BYTES) { - VkDescriptorBufferInfo buffer_info; - buffer_info.buffer = ubo.buffers[context.current_frame]; - buffer_info.offset = 0; - buffer_info.range = binding.data.bytes.size; - - write_sets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_sets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write_sets[0].descriptorCount = 1; - write_sets[0].dstSet = sets[0]; - write_sets[0].dstBinding = 0; - write_sets[0].dstArrayElement = 0; - write_sets[0].pBufferInfo = &buffer_info; - } else { + VkDescriptorBufferInfo* buffer_info = arena_alloc(&tmp, sizeof(VkDescriptorBufferInfo)); + buffer_info->buffer = ubo.buffers[context.current_frame]; + buffer_info->offset = 0; + buffer_info->range = binding.data.bytes.size; + + write_sets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_sets[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write_sets[i].descriptorCount = 1; + write_sets[i].dstSet = sets[0]; + write_sets[i].dstBinding = i; + write_sets[i].dstArrayElement = 0; + write_sets[i].pBufferInfo = buffer_info; + } else if (binding.type == SHADER_BINDING_TEXTURE) { + gpu_texture* texture = TEXTURE_GET(binding.data.texture.handle); + VkDescriptorImageInfo* image_info = arena_alloc(&tmp, sizeof(VkDescriptorImageInfo)); + image_info->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info->imageView = texture->view; + image_info->sampler = texture->sampler; + + write_sets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_sets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_sets[i].descriptorCount = 1; + write_sets[i].dstSet = sets[0]; + write_sets[i].dstBinding = i; + write_sets[i].dstArrayElement = 0; + write_sets[i].pImageInfo = image_info; + }else { WARN("Unknown binding"); } } // Update - vkUpdateDescriptorSets(context.device->logical_device, 1, write_sets, 0, NULL); + vkUpdateDescriptorSets(context.device->logical_device, binding_count, write_sets, 0, NULL); // Bind vkCmdBindDescriptorSets(encoder->cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, encoder->pipeline->layout_handle, 0, 1, sets, 0, NULL); + + arena_free_storage(&tmp); } void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf) { @@ -1453,19 +1485,15 @@ void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) { vulkan_command_buffer_finish_oneshot(temp_cmd_buffer); } -texture_handle gpu_texture_create(texture_desc desc, const void* data) { +texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data) { VkDeviceSize image_size = desc.extents.x * desc.extents.y * 4; - TRACE("Uploading pixel data to texture using staging buffer"); - // Create a staging buffer - buffer_handle staging = - gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL); - // Copy data into it - buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, image_size); - VkImage image; VkDeviceMemory image_memory; + // FIXME: get from desc + VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; + VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.extent.width = desc.extents.x; @@ -1473,7 +1501,7 @@ texture_handle gpu_texture_create(texture_desc desc, const void* data) { image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; - image_create_info.format = VK_FORMAT_R8G8B8A8_SRGB; + image_create_info.format = format; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; @@ -1494,13 +1522,71 @@ texture_handle gpu_texture_create(texture_desc desc, const void* data) { vkBindImageMemory(context.device->logical_device, image, image_memory, 0); - gpu_buffer_destroy(staging); - texture_handle handle; gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle); + DEBUG("Allocated texture with handle %d", handle.raw); texture->handle = image; + texture->debug_label = "Test Texture"; + texture->desc = desc; texture->memory = image_memory; texture->size = image_size; + + if (data) { + TRACE("Uploading pixel data to texture using staging buffer"); + // Create a staging buffer + buffer_handle staging = + gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL); + // Copy data into it + vulkan_transition_image_layout(texture, format, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, image_size); + copy_buffer_to_image_oneshot(staging, handle); + vulkan_transition_image_layout(texture, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + gpu_buffer_destroy(staging); + } + + // Texture View + if (create_view) { + VkImageViewCreateInfo view_create_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_create_info.image = image; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = format; + view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + view_create_info.subresourceRange.baseMipLevel = 0; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.baseArrayLayer = 0; + view_create_info.subresourceRange.layerCount = 1; + + VK_CHECK(vkCreateImageView(context.device->logical_device, &view_create_info, context.allocator, + &texture->view)); + } + + // Sampler + VkSamplerCreateInfo sampler_info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.anisotropyEnable = VK_TRUE; + sampler_info.maxAnisotropy = 16; + sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + sampler_info.unnormalizedCoordinates = VK_FALSE; + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler_info.mipLodBias = 0.0; + sampler_info.minLod = 0.0; + sampler_info.maxLod = 0.0; + + VkResult res = vkCreateSampler(context.device->logical_device, &sampler_info, context.allocator, + &texture->sampler); + if (res != VK_SUCCESS) { + ERROR("Error creating texture sampler for image %s", texture->debug_label); + return; + } + return handle; } diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h index 1e36ca3..dc0f7bd 100644 --- a/src/renderer/backends/backend_vulkan.h +++ b/src/renderer/backends/backend_vulkan.h @@ -109,4 +109,7 @@ typedef struct gpu_texture { VkDeviceMemory memory; u64 size; texture_desc desc; + VkImageView view; + VkSampler sampler; + char* debug_label; } gpu_texture; diff --git a/src/renderer/ral.h b/src/renderer/ral.h index a82a2ba..3697ea5 100644 --- a/src/renderer/ral.h +++ b/src/renderer/ral.h @@ -147,7 +147,7 @@ void gpu_buffer_upload(); void gpu_buffer_bind(buffer_handle buffer); // Textures -texture_handle gpu_texture_create(texture_desc desc, const void* data); +texture_handle gpu_texture_create(texture_desc desc, bool create_view, const void* data); void gpu_texture_destroy(); void gpu_texture_upload(); diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h index 8339625..62a2f1d 100644 --- a/src/renderer/ral_types.h +++ b/src/renderer/ral_types.h @@ -139,6 +139,7 @@ typedef struct custom_vertex { } custom_vertex; // Vertex attributes +/// @strip_prefix(ATTR_) typedef enum vertex_attrib_type { ATTR_F32, ATTR_F32x2, @@ -211,7 +212,10 @@ typedef struct shader_binding { void* data; size_t size; } bytes; - } data; /** @brief */ + struct { + texture_handle handle; + } texture; + } data; /** @brief can store any kind of data that we can bind to a shader / descriptor set */ } shader_binding; #define MAX_LAYOUT_BINDINGS 8 diff --git a/src/renderer/render.c b/src/renderer/render.c index 9f9a97c..5723c9e 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -230,8 +230,9 @@ texture_data texture_data_load(const char* path, bool invert_y) { } texture_handle texture_data_upload(texture_data data, bool free_on_upload) { - texture_handle handle = gpu_texture_create(data.description, data.image_data); + texture_handle handle = gpu_texture_create(data.description, true, data.image_data); if (free_on_upload) { + TRACE("Freed stb_image data"); stbi_image_free(data.image_data); } return handle; @@ -123,6 +123,7 @@ target("core_config") add_files("assets/shaders/triangle.vert") add_files("assets/shaders/triangle.frag") add_files("assets/shaders/cube.vert") + add_files("assets/shaders/cube.frag") -- add_files("assets/shaders/*.frag") if is_plat("windows") then add_includedirs("$(env VULKAN_SDK)/Include", {public = true}) |