diff --git a/arena.c b/arena.c new file mode 100644 index 0000000..4773eac --- /dev/null +++ b/arena.c @@ -0,0 +1,52 @@ +#include "arena.h" + +#include +#include +#include + +static bool is_power_of_two(uintptr_t x) { return (x & (x - 1)) == 0; } + +static uintptr_t align_forward(uintptr_t ptr, size_t alignment) { + assert(is_power_of_two(alignment)); + + uintptr_t modulo = ptr & (alignment - 1); /* = ptr % alignment */ + if (modulo != 0) + ptr += alignment - modulo; + return ptr; +} + +void arena_init(Arena *arena, void *buffer, size_t buffer_length) { + arena->buffer = buffer; + arena->buffer_length = buffer_length; + arena->offset = 0; +} + +#ifndef DEFAULT_ALIGNMENT +#define DEFAULT_ALIGNMENT (2 * sizeof(void *)) +#endif + +void *arena_alloc(Arena *arena, size_t size) { + return arena_alloc_align(arena, size, DEFAULT_ALIGNMENT); +} + +void *arena_alloc_align(Arena *arena, size_t size, size_t alignment) { + /* Align the current offset to the specified alignment */ + uintptr_t curr_ptr = (uintptr_t)arena->buffer + arena->offset; + uintptr_t offset = align_forward(curr_ptr, alignment); + offset -= (uintptr_t)arena->buffer; + + /* Check to see if there is some memory left */ + if (offset <= arena->buffer_length - size) { + void *ptr = &arena->buffer[offset]; + arena->offset = offset + size; + + /* Zero out newly allocated memory */ + memset(ptr, 0, size); + assert(ptr != 0); + return ptr; + } + + abort(); +} + +void arena_clear(Arena *arena) { arena->offset = 0; } diff --git a/arena.h b/arena.h new file mode 100644 index 0000000..22e650f --- /dev/null +++ b/arena.h @@ -0,0 +1,20 @@ +#ifndef INCLUDED_ARENA_H +#define INCLUDED_ARENA_H + +#include +#include +#include + +typedef struct Arena { + unsigned char *buffer; + size_t buffer_length; + size_t offset; +} Arena; + +void arena_init(Arena *arena, void *buffer, size_t buffer_length); + +void *arena_alloc(Arena *arena, size_t size); +void *arena_alloc_align(Arena *arena, size_t size, size_t alignment); +void arena_clear(Arena *arena); + +#endif /* INCLUDED_ARENA_H */ diff --git a/hittable.c b/hittable.c index cd9aa1d..808d41c 100644 --- a/hittable.c +++ b/hittable.c @@ -4,6 +4,7 @@ #include #include +#include void hit_record_set_face_normal(HitRecord *record, Ray r, Vec3 outward_normal) { record->front_face = vec3_dot(r.direction, outward_normal) < 0; @@ -23,24 +24,24 @@ bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max, return false; } -static void hittable_list_grow(HittableList *list, size_t n) { +static void hittable_list_grow(HittableList *list, size_t n, Arena *arena) { if (list->objects) { - list->objects = realloc(list->objects, n * sizeof(Hittable *)); - if (!list->objects) - abort(); - list->capacity = n; + const Hittable **new_objects = + arena_alloc(arena, (list->capacity + n) * sizeof(Hittable *)); + memcpy(new_objects, list->objects, list->size * sizeof(Hittable *)); + list->objects = new_objects; + list->capacity += n; } else { - list->objects = malloc(n * sizeof(Hittable *)); - if (!list->objects) - abort(); + list->objects = arena_alloc(arena, n * sizeof(Hittable *)); list->capacity = n; list->size = 0; } } -void hittable_list_add(HittableList *list, const Hittable *hittable) { +void hittable_list_add(HittableList *list, const Hittable *hittable, + Arena *arena) { if (list->capacity == list->size) - hittable_list_grow(list, list->capacity == 0 ? 16 : list->capacity); + hittable_list_grow(list, list->capacity == 0 ? 16 : list->capacity, arena); list->objects[list->size++] = hittable; } @@ -59,11 +60,6 @@ bool hittable_list_hit(const HittableList *list, Ray r, double t_min, return hit_anything; } -void hittable_list_free(HittableList *list) { - free(list->objects); - list->objects = 0; -} - bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max, HitRecord *record) { Vec3 oc = point3_sub(r.origin, sphere->center); diff --git a/hittable.h b/hittable.h index cac305b..9539894 100644 --- a/hittable.h +++ b/hittable.h @@ -1,10 +1,11 @@ #ifndef INCLUDED_HITTABLE_H #define INCLUDED_HITTABLE_H +#include "arena.h" +#include "material.h" #include "point3.h" #include "ray.h" #include "vec3.h" -#include "material.h" #include #include @@ -38,10 +39,10 @@ typedef struct HittableList { size_t capacity; } HittableList; -void hittable_list_add(HittableList *list, const Hittable *hittable); +void hittable_list_add(HittableList *list, const Hittable *hittable, + Arena *arena); bool hittable_list_hit(const HittableList *list, Ray r, double t_min, double t_max, HitRecord *record); -void hittable_list_free(HittableList *list); typedef struct Sphere { HittableType type; diff --git a/main.c b/main.c index 289f96e..600a5ac 100644 --- a/main.c +++ b/main.c @@ -4,6 +4,7 @@ #include #include +#include "arena.h" #include "camera.h" #include "color.h" #include "hittable.h" @@ -33,19 +34,17 @@ static Color ray_color(Ray r, const Hittable *world, int depth) { return color_lerp(gradient1, gradient2, t); } -static const Hittable *generate_random_scene(void) { +static const Hittable *generate_random_scene(Arena *arena) { static HittableList world = {.type = HITTABLE_LIST}; - /* FIXME: Use arena allocators to be able to free memory */ - static Lambertian ground_material = {.type = MATERIAL_LAMBERTIAN, .albedo = (Color){0.5, 0.5, 0.5}}; - Sphere *ground_sphere = malloc(sizeof(Sphere)); + Sphere *ground_sphere = arena_alloc(arena, sizeof(Sphere)); ground_sphere->type = HITTABLE_SPHERE; ground_sphere->center = (Point3){0.0, -1000.0, 0.0}; ground_sphere->radius = 1000.0; ground_sphere->material = (const Material *)&ground_material; - hittable_list_add(&world, (const Hittable *)ground_sphere); + hittable_list_add(&world, (const Hittable *)ground_sphere, arena); static Lambertian lambertian = {.type = MATERIAL_LAMBERTIAN, .albedo = {0.4, 0.2, 0.1}}; @@ -62,66 +61,76 @@ static const Hittable *generate_random_scene(void) { if (vec3_length(point3_sub(center, (Point3){4.0, 0.2, 0.0})) > 0.9) { if (choose_material < 0.8) { Color albedo = color_mul(color_random(), color_random()); - Lambertian *material = malloc(sizeof(Lambertian)); + Lambertian *material = arena_alloc(arena, sizeof(Lambertian)); material->type = MATERIAL_LAMBERTIAN; material->albedo = albedo; - Sphere *sphere = malloc(sizeof(Sphere)); + Sphere *sphere = arena_alloc(arena, sizeof(Sphere)); sphere->type = HITTABLE_SPHERE; sphere->center = center; sphere->radius = 0.2; sphere->material = (const Material *)material; - hittable_list_add(&world, (const Hittable *)sphere); + hittable_list_add(&world, (const Hittable *)sphere, arena); } else if (choose_material < 0.95) { Color albedo = color_random_in_range(0.5, 1); double fuzziness = random_double_in_range(0.5, 1.0); - Metal *material = malloc(sizeof(Metal)); + Metal *material = arena_alloc(arena, sizeof(Metal)); material->type = MATERIAL_METAL; material->albedo = albedo; material->fuzziness = fuzziness; - Sphere *sphere = malloc(sizeof(Sphere)); + Sphere *sphere = arena_alloc(arena, sizeof(Sphere)); sphere->type = HITTABLE_SPHERE; sphere->center = center; sphere->radius = 0.2; sphere->material = (const Material *)material; - hittable_list_add(&world, (const Hittable *)sphere); + hittable_list_add(&world, (const Hittable *)sphere, arena); } else { - Sphere *sphere = malloc(sizeof(Sphere)); + Sphere *sphere = arena_alloc(arena, sizeof(Sphere)); sphere->type = HITTABLE_SPHERE; sphere->center = center; sphere->radius = 0.2; sphere->material = (const Material *)&glass; - hittable_list_add(&world, (const Hittable *)sphere); + hittable_list_add(&world, (const Hittable *)sphere, arena); } } } } - Sphere *sphere1 = malloc(sizeof(Sphere)); + Sphere *sphere1 = arena_alloc(arena, sizeof(Sphere)); sphere1->type = HITTABLE_SPHERE; sphere1->center = (Point3){0.0, 1.0, 0.0}; sphere1->radius = 1.0; sphere1->material = (const Material *)&glass; - hittable_list_add(&world, (const Hittable *)sphere1); - Sphere *sphere2 = malloc(sizeof(Sphere)); + hittable_list_add(&world, (const Hittable *)sphere1, arena); + Sphere *sphere2 = arena_alloc(arena, sizeof(Sphere)); sphere2->type = HITTABLE_SPHERE; sphere2->center = (Point3){-4.0, 1.0, 0.0}; sphere2->radius = 1.0; sphere2->material = (const Material *)&lambertian; - hittable_list_add(&world, (const Hittable *)sphere2); - Sphere *sphere3 = malloc(sizeof(Sphere)); + hittable_list_add(&world, (const Hittable *)sphere2, arena); + Sphere *sphere3 = arena_alloc(arena, sizeof(Sphere)); sphere3->type = HITTABLE_SPHERE; sphere3->center = (Point3){4.0, 1.0, 0.0}; sphere3->radius = 1.0; sphere3->material = (const Material *)&metal; - hittable_list_add(&world, (const Hittable *)sphere3); + hittable_list_add(&world, (const Hittable *)sphere3, arena); return (const Hittable *)&world; } int main(void) { + /* Memory management */ + + const unsigned int buffer_size = 1 * 1024 * 1024; + void *buffer = malloc(buffer_size); + if (!buffer) + abort(); + Arena arena = {0}; + arena_init(&arena, buffer, buffer_size); + /* Image parameters */ + const double aspect_ratio = 3.0 / 2.0; const int image_width = 1200; const int image_height = (int)(image_width / aspect_ratio); @@ -130,7 +139,7 @@ int main(void) { /* World */ - const Hittable *world = generate_random_scene(); + const Hittable *world = generate_random_scene(&arena); /* Camera */ @@ -162,9 +171,12 @@ int main(void) { fprintf(stderr, "\nDone.\n"); + free(buffer); + return 0; } +#include "arena.c" #include "camera.c" #include "color.c" #include "hittable.c"