Introduce memory arenas

This commit is contained in:
Jean-Michel Gorius 2022-11-12 14:08:11 +01:00
parent c97d9664e0
commit 67cf29b684
5 changed files with 119 additions and 38 deletions

52
arena.c Normal file
View File

@ -0,0 +1,52 @@
#include "arena.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
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; }

20
arena.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef INCLUDED_ARENA_H
#define INCLUDED_ARENA_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
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 */

View File

@ -4,6 +4,7 @@
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
void hit_record_set_face_normal(HitRecord *record, Ray r, Vec3 outward_normal) { void hit_record_set_face_normal(HitRecord *record, Ray r, Vec3 outward_normal) {
record->front_face = vec3_dot(r.direction, outward_normal) < 0; 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; 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) { if (list->objects) {
list->objects = realloc(list->objects, n * sizeof(Hittable *)); const Hittable **new_objects =
if (!list->objects) arena_alloc(arena, (list->capacity + n) * sizeof(Hittable *));
abort(); memcpy(new_objects, list->objects, list->size * sizeof(Hittable *));
list->capacity = n; list->objects = new_objects;
list->capacity += n;
} else { } else {
list->objects = malloc(n * sizeof(Hittable *)); list->objects = arena_alloc(arena, n * sizeof(Hittable *));
if (!list->objects)
abort();
list->capacity = n; list->capacity = n;
list->size = 0; 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) 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; list->objects[list->size++] = hittable;
} }
@ -59,11 +60,6 @@ bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
return hit_anything; 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, bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max,
HitRecord *record) { HitRecord *record) {
Vec3 oc = point3_sub(r.origin, sphere->center); Vec3 oc = point3_sub(r.origin, sphere->center);

View File

@ -1,10 +1,11 @@
#ifndef INCLUDED_HITTABLE_H #ifndef INCLUDED_HITTABLE_H
#define INCLUDED_HITTABLE_H #define INCLUDED_HITTABLE_H
#include "arena.h"
#include "material.h"
#include "point3.h" #include "point3.h"
#include "ray.h" #include "ray.h"
#include "vec3.h" #include "vec3.h"
#include "material.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -38,10 +39,10 @@ typedef struct HittableList {
size_t capacity; size_t capacity;
} HittableList; } 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, bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
double t_max, HitRecord *record); double t_max, HitRecord *record);
void hittable_list_free(HittableList *list);
typedef struct Sphere { typedef struct Sphere {
HittableType type; HittableType type;

52
main.c
View File

@ -4,6 +4,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "arena.h"
#include "camera.h" #include "camera.h"
#include "color.h" #include "color.h"
#include "hittable.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); 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}; static HittableList world = {.type = HITTABLE_LIST};
/* FIXME: Use arena allocators to be able to free memory */
static Lambertian ground_material = {.type = MATERIAL_LAMBERTIAN, static Lambertian ground_material = {.type = MATERIAL_LAMBERTIAN,
.albedo = (Color){0.5, 0.5, 0.5}}; .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->type = HITTABLE_SPHERE;
ground_sphere->center = (Point3){0.0, -1000.0, 0.0}; ground_sphere->center = (Point3){0.0, -1000.0, 0.0};
ground_sphere->radius = 1000.0; ground_sphere->radius = 1000.0;
ground_sphere->material = (const Material *)&ground_material; 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, static Lambertian lambertian = {.type = MATERIAL_LAMBERTIAN,
.albedo = {0.4, 0.2, 0.1}}; .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 (vec3_length(point3_sub(center, (Point3){4.0, 0.2, 0.0})) > 0.9) {
if (choose_material < 0.8) { if (choose_material < 0.8) {
Color albedo = color_mul(color_random(), color_random()); 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->type = MATERIAL_LAMBERTIAN;
material->albedo = albedo; material->albedo = albedo;
Sphere *sphere = malloc(sizeof(Sphere)); Sphere *sphere = arena_alloc(arena, sizeof(Sphere));
sphere->type = HITTABLE_SPHERE; sphere->type = HITTABLE_SPHERE;
sphere->center = center; sphere->center = center;
sphere->radius = 0.2; sphere->radius = 0.2;
sphere->material = (const Material *)material; 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) { } else if (choose_material < 0.95) {
Color albedo = color_random_in_range(0.5, 1); Color albedo = color_random_in_range(0.5, 1);
double fuzziness = random_double_in_range(0.5, 1.0); 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->type = MATERIAL_METAL;
material->albedo = albedo; material->albedo = albedo;
material->fuzziness = fuzziness; material->fuzziness = fuzziness;
Sphere *sphere = malloc(sizeof(Sphere)); Sphere *sphere = arena_alloc(arena, sizeof(Sphere));
sphere->type = HITTABLE_SPHERE; sphere->type = HITTABLE_SPHERE;
sphere->center = center; sphere->center = center;
sphere->radius = 0.2; sphere->radius = 0.2;
sphere->material = (const Material *)material; sphere->material = (const Material *)material;
hittable_list_add(&world, (const Hittable *)sphere); hittable_list_add(&world, (const Hittable *)sphere, arena);
} else { } else {
Sphere *sphere = malloc(sizeof(Sphere)); Sphere *sphere = arena_alloc(arena, sizeof(Sphere));
sphere->type = HITTABLE_SPHERE; sphere->type = HITTABLE_SPHERE;
sphere->center = center; sphere->center = center;
sphere->radius = 0.2; sphere->radius = 0.2;
sphere->material = (const Material *)&glass; 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->type = HITTABLE_SPHERE;
sphere1->center = (Point3){0.0, 1.0, 0.0}; sphere1->center = (Point3){0.0, 1.0, 0.0};
sphere1->radius = 1.0; sphere1->radius = 1.0;
sphere1->material = (const Material *)&glass; sphere1->material = (const Material *)&glass;
hittable_list_add(&world, (const Hittable *)sphere1); hittable_list_add(&world, (const Hittable *)sphere1, arena);
Sphere *sphere2 = malloc(sizeof(Sphere)); Sphere *sphere2 = arena_alloc(arena, sizeof(Sphere));
sphere2->type = HITTABLE_SPHERE; sphere2->type = HITTABLE_SPHERE;
sphere2->center = (Point3){-4.0, 1.0, 0.0}; sphere2->center = (Point3){-4.0, 1.0, 0.0};
sphere2->radius = 1.0; sphere2->radius = 1.0;
sphere2->material = (const Material *)&lambertian; sphere2->material = (const Material *)&lambertian;
hittable_list_add(&world, (const Hittable *)sphere2); hittable_list_add(&world, (const Hittable *)sphere2, arena);
Sphere *sphere3 = malloc(sizeof(Sphere)); Sphere *sphere3 = arena_alloc(arena, sizeof(Sphere));
sphere3->type = HITTABLE_SPHERE; sphere3->type = HITTABLE_SPHERE;
sphere3->center = (Point3){4.0, 1.0, 0.0}; sphere3->center = (Point3){4.0, 1.0, 0.0};
sphere3->radius = 1.0; sphere3->radius = 1.0;
sphere3->material = (const Material *)&metal; sphere3->material = (const Material *)&metal;
hittable_list_add(&world, (const Hittable *)sphere3); hittable_list_add(&world, (const Hittable *)sphere3, arena);
return (const Hittable *)&world; return (const Hittable *)&world;
} }
int main(void) { 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 */ /* Image parameters */
const double aspect_ratio = 3.0 / 2.0; const double aspect_ratio = 3.0 / 2.0;
const int image_width = 1200; const int image_width = 1200;
const int image_height = (int)(image_width / aspect_ratio); const int image_height = (int)(image_width / aspect_ratio);
@ -130,7 +139,7 @@ int main(void) {
/* World */ /* World */
const Hittable *world = generate_random_scene(); const Hittable *world = generate_random_scene(&arena);
/* Camera */ /* Camera */
@ -162,9 +171,12 @@ int main(void) {
fprintf(stderr, "\nDone.\n"); fprintf(stderr, "\nDone.\n");
free(buffer);
return 0; return 0;
} }
#include "arena.c"
#include "camera.c" #include "camera.c"
#include "color.c" #include "color.c"
#include "hittable.c" #include "hittable.c"