Compare commits
2 Commits
da5fce383d
...
d99da864da
| Author | SHA1 | Date | |
|---|---|---|---|
| d99da864da | |||
|
5f07239374
|
91
code/core/arena.h
Normal file
91
code/core/arena.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#if !defined(LD_CORE_ARENA_H_)
|
||||
#define LD_CORE_ARENA_H_
|
||||
|
||||
#define AlignUp(x, a) (((x) + ~((a) - 1)) & ~((a) - 1))
|
||||
#define AlignDown(x, a) (((x)) & ~((a) - 1))
|
||||
|
||||
#define KB(x) ((U64) (x) << 10)
|
||||
#define MB(x) ((U64) (x) << 20)
|
||||
#define GB(x) ((U64) (x) << 30)
|
||||
|
||||
#if !defined(M_ARENA_CHAIN_RESERVE)
|
||||
#define M_ARENA_CHAIN_RESERVE MB(4)
|
||||
#endif
|
||||
|
||||
function void *M_ZeroSize(void *base, U64 size);
|
||||
function void *M_CopySize(void *dst, void *src, U64 size);
|
||||
|
||||
typedef U32 M_ArenaFlags;
|
||||
enum {
|
||||
// Arena is fixed size, so will not chain
|
||||
M_ARENA_FIXED_SIZE = (1 << 0),
|
||||
// Don't clear allocation
|
||||
M_ARENA_NO_ZERO = (1 << 1)
|
||||
|
||||
};
|
||||
|
||||
typedef union M_Arena M_Arena;
|
||||
union M_Arena {
|
||||
struct {
|
||||
M_Arena *current;
|
||||
M_Arena *prev;
|
||||
|
||||
U64 base;
|
||||
U64 limit;
|
||||
U64 offset;
|
||||
|
||||
U64 committed;
|
||||
U64 increment;
|
||||
|
||||
M_ArenaFlags flags;
|
||||
};
|
||||
|
||||
U8 __pad[64];
|
||||
};
|
||||
|
||||
typedef struct M_ArenaOpts M_ArenaOpts;
|
||||
struct M_ArenaOpts {
|
||||
U64 initial;
|
||||
U64 increment;
|
||||
|
||||
M_ArenaFlags flags;
|
||||
};
|
||||
|
||||
typedef struct M_ArenaPushOpts M_ArenaPushOpts;
|
||||
struct M_ArenaPushOpts {
|
||||
U64 count;
|
||||
U64 align;
|
||||
|
||||
M_ArenaFlags flags;
|
||||
};
|
||||
|
||||
function M_Arena *_M_ArenaAlloc(U64 limit, M_ArenaOpts *opts);
|
||||
function void *_M_ArenaPush(M_Arena *arena, U64 esize, M_ArenaPushOpts *opts);
|
||||
function void *_M_ArenaPushCopy(M_Arena *arena, void *src, U64 esize, M_ArenaPushOpts *opts);
|
||||
|
||||
#define M_ArenaAlloc(limit, ...) _M_ArenaAlloc(limit, &(M_ArenaOpts) { .initial = MB(1), .increment = KB(64), ##__VA_ARGS__ })
|
||||
#define M_ArenaPush(arena, T, ...) (T *) _M_ArenaPush(arena, sizeof(T), &(M_ArenaOpts) { .count = 1, .align = Alignof(T), ##__VA_ARGS__ })
|
||||
#define M_ArenaPushCopy(arena, T, src, ...) (T *) _M_ArenaPush(arena, src, sizeof(T), &(M_ArenaOpts) { .count = 1, .align = Alignof(T), ##__VA_ARGS__ })
|
||||
|
||||
function void M_ArenaReset(M_Arena *arena);
|
||||
function void M_ArenaRelease(M_Arena *arena);
|
||||
|
||||
function U64 M_ArenaOffset(M_Arena *arena);
|
||||
|
||||
function void M_ArenaPop(M_Arena *arena, U64 offset);
|
||||
function void M_ArenaPopSize(M_Arena *arena, U64 size);
|
||||
|
||||
// Temporary memory
|
||||
|
||||
typedef struct M_Temp M_Temp;
|
||||
struct M_Temp {
|
||||
M_Arena *arena;
|
||||
U64 offset;
|
||||
};
|
||||
|
||||
function M_Temp M_TempAcquire(U64 count, M_Arena **conflicts);
|
||||
function void M_TempRelease(M_Temp temp);
|
||||
|
||||
#define M_TempScope(n, c) for (M_Temp temp = M_TempAcquire(n, c); temp.arena != 0; M_TempRelease(temp), temp.arena = 0)
|
||||
|
||||
#endif // LD_CORE_ARENA_H_
|
||||
1
code/core/core.c
Normal file
1
code/core/core.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "impl/arena.c"
|
||||
9
code/core/core.h
Normal file
9
code/core/core.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#if !defined(LD_CORE_CORE_H_)
|
||||
#define LD_CORE_CORE_H_
|
||||
|
||||
#include "types.h"
|
||||
#include "platform.h"
|
||||
#include "macros.h"
|
||||
#include "arena.h"
|
||||
|
||||
#endif // LD_CORE_CORE_H_
|
||||
210
code/core/impl/arena.c
Normal file
210
code/core/impl/arena.c
Normal file
@@ -0,0 +1,210 @@
|
||||
void *M_ZeroSize(void *base, U64 size) {
|
||||
U8 *bytes = (U8 *) base;
|
||||
|
||||
while (size--) {
|
||||
*bytes++ = 0;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
void *M_CopySize(void *dst, void *src, U64 size) {
|
||||
U8 *se = (U8 *) src + (size - 1);
|
||||
U8 *de = (U8 *) dst + (size - 1);
|
||||
|
||||
while (size--) {
|
||||
*de-- = *se--;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
M_Arena *_M_ArenaAlloc(U64 limit, M_ArenaOpts *opts) {
|
||||
M_Arena *result = 0;
|
||||
|
||||
local_persist M_ArenaOpts _opts;
|
||||
if (!opts) {
|
||||
opts = &_opts;
|
||||
}
|
||||
|
||||
U64 page_size = VM_PageSize();
|
||||
U64 granularity = VM_AllocationGranularity();
|
||||
|
||||
U64 reserve = Max(AlignUp(limit, granularity), granularity);
|
||||
U64 initial = Clamp(page_size, AlignUp(opts->initial, page_size), reserve);
|
||||
|
||||
void *base = VM_Reserve(reserve);
|
||||
if (base != 0) {
|
||||
if (VM_Commit(base, initial)) {
|
||||
result = cast(M_Arena *) base;
|
||||
|
||||
result->current = result;
|
||||
result->prev = 0;
|
||||
|
||||
result->base = 0;
|
||||
result->offset = sizeof(M_Arena);
|
||||
result->limit = reserve;
|
||||
|
||||
result->committed = initial;
|
||||
result->increment = Max(AlignUp(opts->increment, page_size), page_size);
|
||||
|
||||
result->flags = opts->flags;
|
||||
}
|
||||
else {
|
||||
VM_Release(base, reserve);
|
||||
}
|
||||
}
|
||||
|
||||
Assert(result != 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *_M_ArenaPush(M_Arena *arena, U64 esize, M_ArenaPushOpts *opts) {
|
||||
void *result = 0;
|
||||
|
||||
local_persist M_ArenaPushOpts _opts = { .count = 1, .align = 8 };
|
||||
if (!opts) {
|
||||
opts = &_opts;
|
||||
}
|
||||
|
||||
U64 alignment = Clamp(1, opts->align, 4096);
|
||||
M_Arena *current = arena->current;
|
||||
|
||||
U64 total = esize * opts->count;
|
||||
U64 offset = AlignUp(current->offset, alignment);
|
||||
U64 end = offset + total;
|
||||
|
||||
if (end > current->limit) {
|
||||
// Not enough space, chain a new arena if flags allow
|
||||
if ((arena->flags & M_ARENA_FIXED_SIZE) == 0) {
|
||||
U64 reserve = Min(total + sizeof(M_Arena), M_ARENA_CHAIN_RESERVE);
|
||||
M_Arena *next = M_ArenaAlloc(reserve, .flags = arena->flags);
|
||||
|
||||
next->base = current->base + current->limit;
|
||||
|
||||
SLL_PushN(arena->current, next, prev);
|
||||
|
||||
current = next;
|
||||
offset = AlignUp(current->offset, alignment);
|
||||
end = offset + total;
|
||||
}
|
||||
}
|
||||
|
||||
if (end > current->committed) {
|
||||
// Not enough committed, commit more memory
|
||||
U64 commit_offset = AlignUp(end, current->increment);
|
||||
U64 commit_limit = Min(commit_offset, current->limit);
|
||||
|
||||
U8 *commit_base = cast(U8 *) current + current->committed;
|
||||
U64 commit_size = commit_limit - current->committed;
|
||||
|
||||
if (VM_Commit(commit_base, commit_size)) {
|
||||
current->committed = commit_limit;
|
||||
}
|
||||
}
|
||||
|
||||
if (end <= current->committed) {
|
||||
// Successfully got enough memory, push the allocation
|
||||
result = cast(U8 *) current + offset;
|
||||
current->offset = end;
|
||||
|
||||
if (((opts->flags | arena->flags) & M_ARENA_NO_ZERO) == 0){
|
||||
M_ZeroSize(result, total);
|
||||
}
|
||||
}
|
||||
|
||||
Assert(result != 0);
|
||||
Assert(((U64) result & (alignment - 1)) == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *_M_ArenaPushCopy(M_Arena *arena, void *from, U64 size, M_ArenaPushOpts *opts) {
|
||||
void *result = M_CopySize(_M_ArenaPush(arena, size, opts), from, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
void M_ArenaReset(M_Arena *arena) {
|
||||
M_Arena *base = arena->current;
|
||||
while (base->base != 0) {
|
||||
M_Arena *prev = base->prev;
|
||||
|
||||
VM_Release(base, base->limit);
|
||||
base = prev;
|
||||
}
|
||||
|
||||
Assert(arena == base);
|
||||
|
||||
// @Todo: We could decommit some of the memory in the base arena, do we want to give a
|
||||
// parameter to choose how much :decommit
|
||||
base->offset = sizeof(M_Arena);
|
||||
arena->current = base;
|
||||
}
|
||||
|
||||
void M_ArenaRelease(M_Arena *arena) {
|
||||
M_ArenaReset(arena);
|
||||
VM_Release(arena, arena->limit);
|
||||
}
|
||||
|
||||
U64 M_ArenaOffset(M_Arena *arena) {
|
||||
U64 result = arena->current->base + arena->current->offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
void M_ArenaPop(M_Arena *arena, U64 offset) {
|
||||
M_Arena *base = arena->current;
|
||||
while (base->base > offset) {
|
||||
M_Arena *prev = base->prev;
|
||||
|
||||
VM_Release(base, base->limit);
|
||||
base = prev;
|
||||
}
|
||||
|
||||
// :decommit
|
||||
arena->current = base;
|
||||
base->offset = Max(offset - base->base, sizeof(M_Arena));
|
||||
}
|
||||
|
||||
void M_ArenaPopSize(M_Arena *arena, U64 size) {
|
||||
U64 offset = M_ArenaOffset(arena);
|
||||
offset -= Min(offset, size);
|
||||
|
||||
M_ArenaPop(arena, offset);
|
||||
}
|
||||
|
||||
#define M_TEMP_ARENA_LIMIT GB(4)
|
||||
static thread_var M_Arena *__tls_temp[2];
|
||||
|
||||
M_Temp M_TempAcquire(U64 count, M_Arena **conflicts) {
|
||||
M_Temp result = { 0 };
|
||||
|
||||
for (U32 it = 0; it < ArraySize(__tls_temp); ++it) {
|
||||
if (!__tls_temp[it]) {
|
||||
__tls_temp[it] = M_ArenaAlloc(M_TEMP_ARENA_LIMIT, .initial = MB(1), .increment = MB(1));
|
||||
}
|
||||
|
||||
result.arena = __tls_temp[it];
|
||||
|
||||
for (U32 c = 0; c < count; ++c) {
|
||||
if (__tls_temp[it] == conflicts[c]) {
|
||||
result.arena = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.arena) {
|
||||
result.offset = M_ArenaOffset(result.arena);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assert(result.arena != 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void M_TempRelease(M_Temp temp) {
|
||||
M_ArenaPop(temp.arena, temp.offset);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
#if !defined(LD_CORE_MACROS_H_)
|
||||
#define LD_CORE_MACROS_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define Assert(exp) assert(exp)
|
||||
|
||||
#define ArraySize(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define Min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define Max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define Clamp(min, x, max) (Min(Max(min, x), max))
|
||||
#define Clamp01(x) Clamp(0, x, 1)
|
||||
|
||||
#define cast(x) (x)
|
||||
|
||||
#define _Glue(a, b) a##b
|
||||
#define _Stringify(x) #x
|
||||
@@ -11,5 +19,30 @@
|
||||
#define Glue(a, b) _Glue(a, b)
|
||||
#define Stringify(x) _Stringify(x)
|
||||
|
||||
#if LANG_CPP
|
||||
#define Alignof(x) alignof(x)
|
||||
#else
|
||||
#define Alignof(x) _Alignof(x)
|
||||
#endif
|
||||
|
||||
// Singly linked lists (named members)
|
||||
//
|
||||
#define SLL_EnqueueN(h, t, n, next) (((h) == 0) ? ((h) = (t) = (n), (n)->next = 0) : ((t)->next = (n), (t) = (n), (n)->next = 0))
|
||||
#define SLL_EnqueueFrontN(h, t, n, next) (((h) == 0) ? ((h) = (t) = (n), (n)->next = 0) : ((n)->next = (h), (h) = (n)))
|
||||
#define SLL_DequeueN(h, t, next) ((h) == (t) ? ((h) = 0, (t) = 0) : ((h) = (h)->next))
|
||||
|
||||
#define SLL_PushN(h, n, next) ((n)->next = (h), (h) = (n))
|
||||
#define SLL_PopN(h, next) (((h) != 0) ? (h) = (h)->next : 0)
|
||||
|
||||
#define function static
|
||||
#define internal static
|
||||
#define global_var static
|
||||
#define local_persist static
|
||||
|
||||
#if COMPILER_CL
|
||||
#define thread_var __declspec(thread)
|
||||
#else
|
||||
#define thread_var __thread
|
||||
#endif
|
||||
|
||||
#endif // LD_CORE_MACROS_H_
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
#if OS_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#pragma warning(disable : 4201)
|
||||
#elif OS_LINUX
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "core/types.h"
|
||||
#include "core/platform.h"
|
||||
#include "core/macros.h"
|
||||
#include "core/core.h"
|
||||
#include "os/core.h"
|
||||
|
||||
#include "vulkan/core.h"
|
||||
|
||||
@@ -114,4 +113,6 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "core/core.c"
|
||||
#include "os/core.c"
|
||||
#include "vulkan/core.c"
|
||||
|
||||
3
code/os/core.c
Normal file
3
code/os/core.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#if OS_WINDOWS
|
||||
#include "impl/windows/core.c"
|
||||
#endif
|
||||
14
code/os/core.h
Normal file
14
code/os/core.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#if !defined(LD_OS_CORE_H_)
|
||||
#define LD_OS_CORE_H_
|
||||
|
||||
// Virtual memory
|
||||
|
||||
function U64 VM_PageSize();
|
||||
function U64 VM_AllocationGranularity();
|
||||
|
||||
function void *VM_Reserve(U64 size);
|
||||
function B32 VM_Commit(void *base, U64 size);
|
||||
function void VM_Decommit(void *base, U64 size);
|
||||
function void VM_Release(void *base, U64 size);
|
||||
|
||||
#endif // LD_OS_CORE_H_
|
||||
38
code/os/impl/windows/core.c
Normal file
38
code/os/impl/windows/core.c
Normal file
@@ -0,0 +1,38 @@
|
||||
// Virtual memory
|
||||
|
||||
U64 VM_PageSize() {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
|
||||
U64 result = info.dwPageSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
U64 VM_AllocationGranularity() {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
|
||||
U64 result = info.dwAllocationGranularity;
|
||||
return result;
|
||||
}
|
||||
|
||||
void *VM_Reserve(U64 size) {
|
||||
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
return result;
|
||||
}
|
||||
|
||||
B32 VM_Commit(void *base, U64 size) {
|
||||
B32 result = VirtualAlloc(base, size, MEM_COMMIT, PAGE_READWRITE) != 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void VM_Decommit(void *base, U64 size) {
|
||||
VirtualFree(base, size, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
void VM_Release(void *base, U64 size) {
|
||||
(void) size;
|
||||
|
||||
VirtualFree(base, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
@@ -294,10 +294,16 @@ bool Vk_Setup(SDL_Window *window) {
|
||||
vk.GetSwapchainImagesKHR(vk.device, vk.swapchain.handle, &n_images, 0);
|
||||
vk.GetSwapchainImagesKHR(vk.device, vk.swapchain.handle, &n_images, vk.swapchain.images);
|
||||
|
||||
vk.in_flight = n_images + 1;
|
||||
|
||||
if (n_images != vk.swapchain.n_images) {
|
||||
printf("[Warn] :: Swapchain image count mismatch\n");
|
||||
vk.swapchain.n_images = n_images;
|
||||
}
|
||||
else if (n_images >= VK_MAX_FRAMES_IN_FLIGHT) {
|
||||
printf("[Warn] :: Min image count too high: %d\n", n_images);
|
||||
vk.in_flight = VK_MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo create_info = { 0 };
|
||||
create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
@@ -314,7 +320,7 @@ bool Vk_Setup(SDL_Window *window) {
|
||||
}
|
||||
}
|
||||
|
||||
for (U32 it = 0; it < VK_FRAMES_IN_FLIGHT && vk.err == VK_SUCCESS; ++it) {
|
||||
for (U32 it = 0; it < vk.in_flight && vk.err == VK_SUCCESS; ++it) {
|
||||
Vk_Frame *frame = &vk.frames[it];
|
||||
|
||||
VkCommandPoolCreateInfo pool = { 0 };
|
||||
@@ -353,7 +359,7 @@ bool Vk_Setup(SDL_Window *window) {
|
||||
|
||||
Vk_Frame *Vk_FrameBegin(SDL_Window *window) {
|
||||
(void) window; // might need this for the resize later
|
||||
Vk_Frame *frame = &vk.frames[vk.n_frames & 1];
|
||||
Vk_Frame *frame = &vk.frames[vk.n_frames % vk.in_flight];
|
||||
|
||||
vk.WaitForFences(vk.device, 1, &frame->fence, VK_TRUE, UINT64_MAX);
|
||||
|
||||
@@ -372,7 +378,7 @@ Vk_Frame *Vk_FrameBegin(SDL_Window *window) {
|
||||
}
|
||||
|
||||
void Vk_FrameEnd() {
|
||||
Vk_Frame *frame = &vk.frames[vk.n_frames & 1];
|
||||
Vk_Frame *frame = &vk.frames[vk.n_frames % vk.in_flight];
|
||||
|
||||
vk.EndCommandBuffer(frame->cmd);
|
||||
|
||||
|
||||
@@ -13,10 +13,16 @@
|
||||
#define VK_USE_PLATFORM_WAYLAND_KHR 1
|
||||
#endif
|
||||
|
||||
#if defined(function)
|
||||
#undef function
|
||||
#endif
|
||||
|
||||
#define VK_NO_PROTOTYPES 1
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define VK_FRAMES_IN_FLIGHT 2
|
||||
#define function static
|
||||
|
||||
#define VK_MAX_FRAMES_IN_FLIGHT 8
|
||||
|
||||
typedef struct Vk_Frame Vk_Frame;
|
||||
struct Vk_Frame {
|
||||
@@ -50,7 +56,9 @@ struct Vk_Context {
|
||||
VkDevice device;
|
||||
|
||||
U32 n_frames; // monotonically increasing
|
||||
Vk_Frame frames[VK_FRAMES_IN_FLIGHT];
|
||||
U32 in_flight; // number of frames in flight, number of swapchain images + 1
|
||||
|
||||
Vk_Frame frames[VK_MAX_FRAMES_IN_FLIGHT];
|
||||
|
||||
struct {
|
||||
U32 family;
|
||||
@@ -73,8 +81,9 @@ struct Vk_Context {
|
||||
|
||||
extern Vk_Context vk;
|
||||
|
||||
static bool Vk_Setup(SDL_Window *window);
|
||||
static Vk_Frame *Vk_FrameBegin(SDL_Window *window);
|
||||
static void Vk_FrameEnd();
|
||||
function bool Vk_Setup(SDL_Window *window);
|
||||
|
||||
function Vk_Frame *Vk_FrameBegin(SDL_Window *window);
|
||||
function void Vk_FrameEnd();
|
||||
|
||||
#endif // LD_VULKAN_CORE_H_
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
VK_FUNC(QueuePresentKHR);
|
||||
VK_FUNC(BeginCommandBuffer);
|
||||
VK_FUNC(EndCommandBuffer);
|
||||
VK_FUNC(DeviceWaitIdle);
|
||||
|
||||
VK_FUNC(CmdPipelineBarrier2);
|
||||
VK_FUNC(CmdBeginRendering);
|
||||
|
||||
Reference in New Issue
Block a user