summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmniscient <omniscient.oce@gmail.com>2024-05-18 23:53:11 +1000
committerOmniscient <omniscient.oce@gmail.com>2024-05-18 23:53:11 +1000
commitd79a8aa200bd64b14b85d2ec0c207601ba5c7922 (patch)
tree742c45019abe645355ec27a74924e1bec7963c7a
parentc69fab91c3cd8976ad660939765ca9a5e32a239a (diff)
working on image creation
-rw-r--r--assets/shaders/triangle.vert2
-rw-r--r--examples/cube/ex_cube.c5
-rw-r--r--examples/triangle/ex_triangle.c18
-rw-r--r--src/renderer/backends/backend_vulkan.c224
-rw-r--r--src/renderer/backends/backend_vulkan.h8
-rw-r--r--src/renderer/ral.c21
-rw-r--r--src/renderer/ral.h7
-rw-r--r--src/renderer/ral_types.h3
-rw-r--r--src/renderer/render.c44
-rw-r--r--src/renderer/render.h16
-rw-r--r--src/renderer/render_types.h15
11 files changed, 289 insertions, 74 deletions
diff --git a/assets/shaders/triangle.vert b/assets/shaders/triangle.vert
index b8c8f63..8030561 100644
--- a/assets/shaders/triangle.vert
+++ b/assets/shaders/triangle.vert
@@ -2,8 +2,6 @@
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec3 inColor;
-// layout(location = 1) in vec3 inNormal;
-// layout(location = 2) in vec2 inTexCoords;
layout(location = 0) out vec3 fragColor;
diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c
index 7c7831d..264bf71 100644
--- a/examples/cube/ex_cube.c
+++ b/examples/cube/ex_cube.c
@@ -86,9 +86,14 @@ int main() {
};
gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description);
+ // Geometry
geometry_data cube_data = geo_create_cuboid(f32x3(1, 1, 1));
mesh cube = mesh_create(&cube_data, false);
+ // Texture
+ texture_data tex_data = texture_data_load("assets/textures/texture.jpg", false);
+ texture_handle texture = texture_data_upload(tex_data, true);
+
// Main loop
while (!should_exit(&g_core)) {
input_update(&g_core.input);
diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c
index 5d8f0cf..886637a 100644
--- a/examples/triangle/ex_triangle.c
+++ b/examples/triangle/ex_triangle.c
@@ -16,17 +16,22 @@
extern core g_core;
const custom_vertex vertices[] = {
+ (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.0) },
+ (custom_vertex){ .pos = vec2(0.5, -0.5), .color = vec3(1.0, 0.0, 0.0) },
(custom_vertex){ .pos = vec2(-0.5, 0.5), .color = vec3(0.0, 0.0, 1.0) },
(custom_vertex){ .pos = vec2(0.5, 0.5), .color = vec3(0.0, 1.0, 0.0) },
- (custom_vertex){ .pos = vec2(0.5, -0.5), .color = vec3(1.0, 0.0, 0.0) },
- (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.0) },
};
-const u16 indices[] = { 0, 1, 2, 2, 3, 0 };
+const u32 indices[] = { 2, 1, 0, 1, 2, 3};
int main() {
core_bringup();
arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024);
+ vertex_description vertex_input = {0};
+ vertex_input.debug_label = "Hello";
+ vertex_desc_add(&vertex_input, "inPos", ATTR_F32x2);
+ vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3);
+
gpu_renderpass_desc pass_description = {};
gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description);
@@ -40,6 +45,9 @@ int main() {
struct graphics_pipeline_desc pipeline_description = {
.debug_name = "Basic Pipeline",
+ .vertex_desc = vertex_input,
+ // .data_layouts = {0},
+ // .data_layouts_count = 0,
.vs = { .debug_name = "Triangle Vertex Shader",
.filepath = vert_path,
.code = vertex_shader.contents,
@@ -56,13 +64,13 @@ int main() {
// Load triangle vertex and index data
buffer_handle triangle_vert_buf =
- gpu_buffer_create(sizeof(vertices), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices);
+ gpu_buffer_create(4 * sizeof(vertex) , CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices);
buffer_handle triangle_index_buf =
gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices);
// Main loop
- while (!should_exit(&g_core)) {
+ while (!should_exit()) {
input_update(&g_core.input);
if (!gpu_backend_begin_frame()) {
diff --git a/src/renderer/backends/backend_vulkan.c b/src/renderer/backends/backend_vulkan.c
index 2dc11b5..208aef0 100644
--- a/src/renderer/backends/backend_vulkan.c
+++ b/src/renderer/backends/backend_vulkan.c
@@ -414,37 +414,39 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip
VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_shader_stage_info,
frag_shader_stage_info };
- // TODO: Attributes
- VkVertexInputAttributeDescription attribute_descs[2] = { 0 };
- /* u32 offset = 0; */
- /* for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) { */
- /* attribute_descs[i].binding = 0; */
- /* attribute_descs[i].location = i; */
- /* attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]);
- */
- /* attribute_descs[i].offset = offset; */
- /* size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]); */
- /* printf("offset total %d this attr %ld\n", offset, this_offset); */
- /* printf("sizeof vertex %ld\n", sizeof(vertex)); */
- /* printf("%d \n", offsetof(vertex, static_3d)); */
- /* offset += this_offset; */
- /* } */
- printf("Vertex attributes\n");
- attribute_descs[0].binding = 0;
- attribute_descs[0].location = 0;
- attribute_descs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
- attribute_descs[0].offset = 0; // offsetof(custom_vertex, pos);
-
- attribute_descs[1].binding = 0;
- attribute_descs[1].location = 1;
- attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT;
- attribute_descs[1].offset = 12; // offsetof(custom_vertex, color);
+ // Attributes
+ u32 attr_count = description.vertex_desc.attributes_count;
+ printf("N attributes %d\n", attr_count);
+ VkVertexInputAttributeDescription attribute_descs[attr_count];
+ memset(attribute_descs, 0, attr_count * sizeof(VkVertexInputAttributeDescription));
+ u32 offset = 0;
+ for (u32 i = 0; i < description.vertex_desc.attributes_count; i++) {
+ attribute_descs[i].binding = 0;
+ attribute_descs[i].location = i;
+ attribute_descs[i].format = format_from_vertex_attr(description.vertex_desc.attributes[i]);
+ attribute_descs[i].offset = offset;
+ size_t this_offset = vertex_attrib_size(description.vertex_desc.attributes[i]);
+ printf("offset total %d this attr %ld\n", offset, this_offset);
+ printf("sizeof vertex %ld\n", sizeof(vertex));
+ /* printf("%d \n", offsetof(vertex, static_3d)); */
+ offset += this_offset;
+ }
+ /* printf("Vertex attributes\n"); */
+ /* attribute_descs[0].binding = 0; */
+ /* attribute_descs[0].location = 0; */
+ /* attribute_descs[0].format = VK_FORMAT_R32G32B32_SFLOAT; */
+ /* attribute_descs[0].offset = 0; // offsetof(custom_vertex, pos); */
+
+ /* attribute_descs[1].binding = 0; */
+ /* attribute_descs[1].location = 1; */
+ /* attribute_descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; */
+ /* attribute_descs[1].offset = 12; // offsetof(custom_vertex, color); */
// Vertex input
// TODO: Generate this from descroiption now
VkVertexInputBindingDescription binding_desc;
binding_desc.binding = 0;
- binding_desc.stride = sizeof(vertex); // description.vertex_desc.stride;
+ binding_desc.stride = description.vertex_desc.stride;
binding_desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkPipelineVertexInputStateCreateInfo vertex_input_info = {
@@ -453,7 +455,7 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip
vertex_input_info.vertexBindingDescriptionCount = 1;
vertex_input_info.pVertexBindingDescriptions = &binding_desc;
vertex_input_info.vertexAttributeDescriptionCount =
- 2; // description.vertex_desc.attributes_count;
+ attr_count; // description.vertex_desc.attributes_count;
vertex_input_info.pVertexAttributeDescriptions = attribute_descs;
// Input Assembly
@@ -558,10 +560,15 @@ gpu_pipeline* gpu_graphics_pipeline_create(struct graphics_pipeline_desc descrip
malloc(description.data_layouts_count * sizeof(VkDescriptorSetLayout));
pipeline->desc_set_layouts = desc_set_layouts;
pipeline->desc_set_layouts_count = description.data_layouts_count;
+ if (description.data_layouts_count > 0) {
pipeline->uniform_pointers =
malloc(description.data_layouts_count * sizeof(desc_set_uniform_buffer));
+ } else {
+ pipeline->uniform_pointers = NULL;
+ }
// assert(description.data_layouts_count == 1);
+ printf("data layouts %d\n", description.data_layouts_count);
for (u32 i = 0; i < description.data_layouts_count; i++) {
shader_data_layout sdl = description.data_layouts[i].shader_data_get_layout(NULL);
@@ -1343,15 +1350,15 @@ buffer_handle gpu_buffer_create(u64 size, gpu_buffer_type buf_type, gpu_buffer_f
void gpu_buffer_destroy(buffer_handle buffer) {
gpu_buffer* b =
- buffer_pool_get(&context.resource_pools->buffers, buffer); // context.buffers[buffer.raw];
+ buffer_pool_get(&context.resource_pools->buffers, buffer);
vkDestroyBuffer(context.device->logical_device, b->handle, context.allocator);
vkFreeMemory(context.device->logical_device, b->memory, context.allocator);
+ buffer_pool_dealloc(&context.resource_pools->buffers, buffer);
}
// Upload data to a
void buffer_upload_bytes(buffer_handle gpu_buf, bytebuffer cpu_buf, u64 offset, u64 size) {
gpu_buffer* buffer = buffer_pool_get(&context.resource_pools->buffers, gpu_buf);
- /* gpu_buffer buffer = context.buffers[gpu_buf.raw]; */
void* data_ptr;
vkMapMemory(context.device->logical_device, buffer->memory, 0, size, 0, &data_ptr);
DEBUG("Uploading %d bytes to buffer", size);
@@ -1371,6 +1378,80 @@ void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_off
vkCmdCopyBuffer(encoder->cmd_buffer, src_buf->handle, dst_buf->handle, 1, &copy_region);
}
+// one-shot command buffers
+VkCommandBuffer vulkan_command_buffer_create_oneshot() {
+ VkCommandBufferAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
+ alloc_info.commandPool = context.device->pool;
+ alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ alloc_info.commandBufferCount = 1;
+ alloc_info.pNext = 0;
+
+ VkCommandBuffer cmd_buffer;
+ vkAllocateCommandBuffers(context.device->logical_device, &alloc_info, &cmd_buffer);
+
+ VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
+ begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+ vkBeginCommandBuffer(cmd_buffer, &begin_info);
+
+ return cmd_buffer;
+}
+
+void vulkan_command_buffer_finish_oneshot(VkCommandBuffer cmd_buffer) {
+ VK_CHECK(vkEndCommandBuffer(cmd_buffer));
+
+ // submit to queue
+ VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &cmd_buffer;
+ VK_CHECK(vkQueueSubmit(context.device->graphics_queue, 1, &submit_info, 0));
+ VK_CHECK(vkQueueWaitIdle(context.device->graphics_queue));
+
+ vkFreeCommandBuffers(context.device->logical_device, context.device->pool, 1, &cmd_buffer);
+}
+
+void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst,
+ u64 dst_offset, u64 copy_size) {
+ VkBufferCopy copy_region;
+ copy_region.srcOffset = src_offset;
+ copy_region.dstOffset = dst_offset;
+ copy_region.size = copy_size;
+
+ gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src);
+ gpu_buffer* dst_buf = buffer_pool_get(&context.resource_pools->buffers, dst);
+ VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot();
+ vkCmdCopyBuffer(temp_cmd_buffer, src_buf->handle, dst_buf->handle, 1, &copy_region);
+ vulkan_command_buffer_finish_oneshot(temp_cmd_buffer);
+}
+
+void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst) {
+ gpu_buffer* src_buf = buffer_pool_get(&context.resource_pools->buffers, src);
+ gpu_texture* dst_tex = texture_pool_get(&context.resource_pools->textures, dst);
+
+ VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot();
+
+ VkBufferImageCopy region;
+ region.bufferOffset = 0;
+ region.bufferRowLength = 0;
+ region.bufferImageHeight = 0;
+ region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ region.imageSubresource.mipLevel = 0;
+ region.imageSubresource.baseArrayLayer = 0;
+ region.imageSubresource.layerCount = 1;
+ printf("Image details width: %d height %d\n", dst_tex->desc.extents.x, dst_tex->desc.extents.y);
+ region.imageOffset.x = 0;
+ region.imageOffset.y = 0;
+ region.imageOffset.z = 0;
+ region.imageExtent.width = dst_tex->desc.extents.x;
+ region.imageExtent.height = dst_tex->desc.extents.y;
+ region.imageExtent.depth = 1;
+
+ vkCmdCopyBufferToImage(temp_cmd_buffer, src_buf->handle, dst_tex->handle,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+
+ vulkan_command_buffer_finish_oneshot(temp_cmd_buffer);
+}
+
texture_handle gpu_texture_create(texture_desc desc, const void* data) {
VkDeviceSize image_size = desc.extents.x * desc.extents.y * 4;
@@ -1380,6 +1461,91 @@ texture_handle gpu_texture_create(texture_desc desc, const void* data) {
gpu_buffer_create(image_size, CEL_BUFFER_DEFAULT, CEL_BUFFER_FLAG_CPU, NULL);
// Copy data into it
buffer_upload_bytes(staging, (bytebuffer){ .buf = (u8*)data, .size = image_size }, 0, image_size);
+
+ VkImage image;
+ VkDeviceMemory image_memory;
+
+ VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
+ image_create_info.imageType = VK_IMAGE_TYPE_2D;
+ image_create_info.extent.width = desc.extents.x;
+ image_create_info.extent.height = desc.extents.y;
+ image_create_info.extent.depth = 1;
+ image_create_info.mipLevels = 1;
+ image_create_info.arrayLayers = 1;
+ image_create_info.format = VK_FORMAT_R8G8B8A8_SRGB;
+ image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+ image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
+ image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
+
+ VK_CHECK(
+ vkCreateImage(context.device->logical_device, &image_create_info, context.allocator, &image));
+
+ VkMemoryRequirements memory_reqs;
+ vkGetImageMemoryRequirements(context.device->logical_device, image, &memory_reqs);
+
+ VkMemoryAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ alloc_info.allocationSize = memory_reqs.size;
+ alloc_info.memoryTypeIndex =
+ find_memory_index(memory_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+ vkAllocateMemory(context.device->logical_device, &alloc_info, context.allocator, &image_memory);
+
+ vkBindImageMemory(context.device->logical_device, image, image_memory, 0);
+
+gpu_buffer_destroy(staging);
+
+ texture_handle handle;
+ gpu_texture* texture = texture_pool_alloc(&context.resource_pools->textures, &handle);
+ texture->handle = image;
+ texture->memory = image_memory;
+ texture->size = image_size;
+ return handle;
+}
+
+void vulkan_transition_image_layout(gpu_texture* texture, VkFormat format, VkImageLayout old_layout,
+ VkImageLayout new_layout) {
+ VkCommandBuffer temp_cmd_buffer = vulkan_command_buffer_create_oneshot();
+
+ VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
+ barrier.oldLayout = old_layout;
+ barrier.newLayout = new_layout;
+ barrier.srcQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index;
+ barrier.dstQueueFamilyIndex = context.device->queue_family_indicies.graphics_family_index;
+ barrier.image = texture->handle;
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ barrier.subresourceRange.baseMipLevel = 0;
+ barrier.subresourceRange.levelCount = 1;
+ barrier.subresourceRange.baseArrayLayer = 0;
+ barrier.subresourceRange.layerCount = 1;
+ barrier.srcAccessMask = 0; // TODO
+ barrier.dstAccessMask = 0; // TODO
+
+ VkPipelineStageFlags source_stage;
+ VkPipelineStageFlags dest_stage;
+
+ if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
+ new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
+ new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else {
+ FATAL("Unsupported image layout transition");
+ return;
+ }
+
+ vkCmdPipelineBarrier(temp_cmd_buffer, source_stage, dest_stage, 0, 0, 0, 0, 0, 1, &barrier);
+
+ vulkan_command_buffer_finish_oneshot(temp_cmd_buffer);
}
size_t vertex_attrib_size(vertex_attrib_type attr) {
diff --git a/src/renderer/backends/backend_vulkan.h b/src/renderer/backends/backend_vulkan.h
index 77b9f94..1e36ca3 100644
--- a/src/renderer/backends/backend_vulkan.h
+++ b/src/renderer/backends/backend_vulkan.h
@@ -6,6 +6,7 @@
#include "defines.h"
#include "mem.h"
#include "ral.h"
+#include "ral_types.h"
#define MAX_FRAMES_IN_FLIGHT 2
#define GPU_SWAPCHAIN_IMG_COUNT 2
@@ -102,3 +103,10 @@ typedef struct gpu_buffer {
VkDeviceMemory memory;
u64 size;
} gpu_buffer;
+
+typedef struct gpu_texture {
+ VkImage handle;
+ VkDeviceMemory memory;
+ u64 size;
+ texture_desc desc;
+} gpu_texture;
diff --git a/src/renderer/ral.c b/src/renderer/ral.c
index 6a417dd..304017d 100644
--- a/src/renderer/ral.c
+++ b/src/renderer/ral.c
@@ -1,22 +1 @@
#include "ral.h"
-
-/* typedef struct foo { */
-/* u32 a; */
-/* f32 b; */
-/* char c; */
-/* } foo; */
-
-/* TYPED_POOL(gpu_buffer, buffer); */
-
-/* typedef struct buffer_handle { */
-/* u32 raw; */
-/* } buffer_handle; */
-
-/* typedef struct gpu_buffer gpu_buffer; */
-/* TYPED_POOL(gpu_buffer, buffer); */
-/* TYPED_POOL(gpu_texture, texture); */
-
-/* struct resource_pools { */
-/* buffer_pool buffers; */
-/* texture_pool textures; */
-/* }; */
diff --git a/src/renderer/ral.h b/src/renderer/ral.h
index da9eb93..48be83a 100644
--- a/src/renderer/ral.h
+++ b/src/renderer/ral.h
@@ -30,6 +30,7 @@ typedef struct gpu_renderpass gpu_renderpass;
typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording
typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission
typedef struct gpu_buffer gpu_buffer;
+typedef struct gpu_texture gpu_texture;
#define MAX_SHADER_DATA_LAYOUTS 5
#define MAX_BUFFERS 256
@@ -174,3 +175,9 @@ struct resource_pools {
// Must be implemented by backends
void resource_pools_init(arena* a, struct resource_pools* res_pools);
+
+void copy_buffer_to_buffer_oneshot(buffer_handle src, u64 src_offset, buffer_handle dst, u64 dst_offset,
+ u64 copy_size);
+void copy_buffer_to_image_oneshot(buffer_handle src, texture_handle dst);
+
+// --- Helpers
diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h
index 5d4e88a..fc8bb8b 100644
--- a/src/renderer/ral_types.h
+++ b/src/renderer/ral_types.h
@@ -66,9 +66,6 @@ typedef struct texture_desc {
u32x2 extents;
} texture_desc;
-typedef struct gpu_texture {
-} gpu_texture;
-
typedef enum gpu_buffer_type {
CEL_BUFFER_DEFAULT, // on Vulkan this would be a storage buffer?
CEL_BUFFER_VERTEX,
diff --git a/src/renderer/render.c b/src/renderer/render.c
index b06620b..fc45093 100644
--- a/src/renderer/render.c
+++ b/src/renderer/render.c
@@ -1,11 +1,15 @@
-#include "render.h"
#include <glfw3.h>
+#include "maths_types.h"
+#define STB_IMAGE_IMPLEMENTATION
+#include <stb_image.h>
+
#include "camera.h"
#include "file.h"
#include "log.h"
#include "mem.h"
#include "ral.h"
#include "ral_types.h"
+#include "render.h"
/** @brief Creates the pipelines built into Celeritas such as rendering static opaque geometry,
debug visualisations, immediate mode UI, etc */
@@ -194,3 +198,41 @@ mesh mesh_create(geometry_data* geometry, bool free_on_upload) {
return m;
}
+
+// --- Textures
+
+texture_data texture_data_load(const char* path, bool invert_y) {
+ TRACE("Load texture %s", path);
+
+ // load the file data
+ int width, height, num_channels;
+ stbi_set_flip_vertically_on_load(invert_y);
+
+#pragma GCC diagnostic ignored "-Wpointer-sign"
+ char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha);
+ if (data) {
+ DEBUG("loaded texture: %s", path);
+ } else {
+ WARN("failed to load texture");
+ }
+
+ unsigned int channel_type;
+ if (num_channels == 4) {
+ channel_type = GL_RGBA;
+ } else {
+ channel_type = GL_RGB;
+ }
+ texture_desc desc = { .extents = { width, height },
+ .format = CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM,
+ .tex_type = CEL_TEXTURE_TYPE_2D };
+
+ return (texture_data){ .description = desc, .image_data = data };
+}
+
+texture_handle texture_data_upload(texture_data data, bool free_on_upload) {
+ texture_handle handle = gpu_texture_create(data.description, data.image_data);
+ if (free_on_upload) {
+ stbi_image_free(data.image_data);
+ }
+ return handle;
+}
diff --git a/src/renderer/render.h b/src/renderer/render.h
index 5657fc1..9a7ff2f 100644
--- a/src/renderer/render.h
+++ b/src/renderer/render.h
@@ -34,9 +34,17 @@ typedef struct render_ctx {
texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data);
// Frontend Resources
-// TODO: void texture_data_upload(texture_handle texture);
-void texture_data_upload(texture* tex);
-texture texture_data_load(const char* path, bool invert_y);
+texture_data texture_data_load(const char* path, bool invert_y);
+
+/**
+ * @brief
+ *
+ * @param data
+ * @param free_on_upload frees the CPU-side pixel data stored in `data`
+ * @return texture_handle
+ */
+texture_handle texture_data_upload(texture_data data, bool free_on_upload);
+
buffer_handle buffer_create(const char* debug_name, u64 size);
bool buffer_destroy(buffer_handle buffer);
sampler_handle sampler_create();
@@ -49,7 +57,7 @@ void shader_hot_reload(const char* filepath);
* @brief Creates buffers and returns a struct that holds handles to our resources
*
* @param geometry
- * @param free_on_upload frees the CPU-side vertex/index data stored in geometry_data when we
+ * @param free_on_upload frees the CPU-side vertex/index data stored in `geometry` when we
successfully upload that data to the GPU-side buffer
* @return mesh
*/
diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h
index bd9ef3c..c6aec8e 100644
--- a/src/renderer/render_types.h
+++ b/src/renderer/render_types.h
@@ -69,16 +69,13 @@ typedef struct model {
u32 mesh_count;
} model;
-typedef struct texture {
- u32 texture_id;
- char name[256];
+typedef struct texture {} texture;
+
+typedef struct texture_data {
+ texture_desc description;
void* image_data;
- void* backend_data;
- u32 width;
- u32 height;
- u8 channel_count;
- u32 channel_type;
-} texture;
+} texture_data;
+
typedef struct blinn_phong_material {
char name[256];