Fixed memory bug & window placement
- Improved assert messages to be more clear about what might be happening if they fail - Added more checks in debug to detect heap corruption and what not - Fixed a bug where the program would crash because a heap block was perfectly full - Fixed Y placement of window when changing the window rect - Fixed window sizing when setting scaled_width or scaled_height - Updated readme
This commit is contained in:
parent
aee3f78bd5
commit
a805557a76
9 changed files with 199 additions and 99 deletions
64
README.md
Normal file
64
README.md
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
ooga booga
|
||||||
|
|
||||||
|
## TOC
|
||||||
|
- [Getting started](#getting-started)
|
||||||
|
- [What is ooga booga?](#what-is-ooga-booga)
|
||||||
|
- [Quickstart](#quickstart)
|
||||||
|
- [The "Build System"](#the-build-system)
|
||||||
|
- [Examples & Documentation](#examples--documentation)
|
||||||
|
- [Licensing](#licensing)
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
If you'd like to learn how to use the engine to build a game, there's a completely free course in the [Skool community](https://www.skool.com/game-dev)
|
||||||
|
|
||||||
|
You can find all tutorials and resources for getting started within the community.
|
||||||
|
|
||||||
|
## What is ooga booga?
|
||||||
|
|
||||||
|
Ooga booga, often referred to as a *game engine* for simplicity, is more so designed to be a new C Standard, i.e. a new way to develop software from scratch in C. Other than `<math.h>` we don't include a single C std header, but are instead writing a better standard library heavily optimized for developing games. Except for some image & audio file decoding, Ooga booga does not rely on any other third party code.
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
1. Install clang, add to path
|
||||||
|
2. Clone repo to <project_dir>
|
||||||
|
3. Make a file my_file.c in <project_dir>
|
||||||
|
```
|
||||||
|
int entry(int argc, char **argv) {
|
||||||
|
print("Ooga, booga!\n");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
4. in build.c add this line to the bottom
|
||||||
|
```
|
||||||
|
#include "my_file.c"
|
||||||
|
```
|
||||||
|
5. Run `build.bat`
|
||||||
|
6. Run build/cgame.exe
|
||||||
|
7. profit
|
||||||
|
|
||||||
|
## The "Build System"
|
||||||
|
|
||||||
|
Our build system is a build.c and a build.bat which invokes the clang compiler on build.c. That's it. And we highly discourage anyone from introducing unnecessary complexity like a third party build system (cmake, premake) or to use header files at all whatsoever.
|
||||||
|
|
||||||
|
This might sound like we are breaking some law, but we're not. We're using a compiler to compile a file which includes all the other files, it doesn't get simpler. We are NOT using third party software to run the same compiler to compile the same files over and over again and write it all to disk to then try and link it together. That's what we call silly business (and unreasonably slow compile times, without any real benefit).
|
||||||
|
## Examples & Documentation
|
||||||
|
|
||||||
|
Documentation will come in the form of a lot of examples because that's the best way to learn and understand how everything works.
|
||||||
|
|
||||||
|
See [examples](oogabooga/examples).
|
||||||
|
|
||||||
|
Simply add `#include "oogabooga/examples/some_example.c"` to build.c and compile & run to see the example code in action.
|
||||||
|
|
||||||
|
Other than examples, a great way to learn is to delve into the code of whatever module you're using. The codebase is written with this in mind.
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
By default, the repository has an educational license that makes the engine free to use for personal projects.
|
||||||
|
|
||||||
|
[Educational license terms](https://github.com/alpinestudios/oogabooga/blob/master/LICENSE.md)
|
||||||
|
|
||||||
|
When you're ready to take the next step and work on a commercial game, you can upgrade to the full commercial license.
|
||||||
|
|
||||||
|
Here are the benefits of obtaining the full license:
|
||||||
|
- Permanent Ownership: You completely own the source code for life.
|
||||||
|
- No Recurring Fees or Royalties: Just an affordable one-time payment.
|
||||||
|
- It qualifies you to enter the private Skool community, where there's daily calls with Randy & Charlie, to help speedrun your game's development
|
||||||
|
|
||||||
|
You can [contact us](https://randy.gg/contact) to find out more.
|
4
build.c
4
build.c
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#define RUN_TESTS 0
|
#define RUN_TESTS 0
|
||||||
|
|
||||||
|
#define VERY_DEBUG 0
|
||||||
|
|
||||||
#define ENABLE_PROFILING 0
|
#define ENABLE_PROFILING 0
|
||||||
|
|
||||||
// ENABLE_SIMD Requires CPU to support at least SSE1 but I will be very surprised if you find a system today which doesn't
|
// ENABLE_SIMD Requires CPU to support at least SSE1 but I will be very surprised if you find a system today which doesn't
|
||||||
|
@ -41,7 +43,7 @@ typedef struct Context_Extra {
|
||||||
// #include "oogabooga/examples/text_rendering.c"
|
// #include "oogabooga/examples/text_rendering.c"
|
||||||
|
|
||||||
// An engine dev stress test for rendering
|
// An engine dev stress test for rendering
|
||||||
#include "oogabooga/examples/renderer_stress_test.c"
|
#include "oogabooga/examples/renderer_stress_test.c"
|
||||||
|
|
||||||
// Randy's example game that he's building out as a tutorial for using the engine
|
// Randy's example game that he's building out as a tutorial for using the engine
|
||||||
// #include "entry_randygame.c"
|
// #include "entry_randygame.c"
|
||||||
|
|
|
@ -14,8 +14,18 @@ Third party:
|
||||||
- Made a global thread_local "third_party_allocator" which is set when third party libraries are used so all memory still goes through our *program_memory
|
- Made a global thread_local "third_party_allocator" which is set when third party libraries are used so all memory still goes through our *program_memory
|
||||||
- Stripped all third party libraries of external dependencies (C headers) & noise
|
- Stripped all third party libraries of external dependencies (C headers) & noise
|
||||||
|
|
||||||
|
Memory:
|
||||||
|
- Improved assert messages to be more clear about what might be happening if they fail
|
||||||
|
- Added more checks in debug to detect heap corruption and what not
|
||||||
|
- Fixed a bug where the program would crash because a heap block was perfectly full
|
||||||
|
|
||||||
Misc:
|
Misc:
|
||||||
- Fix typos in examples/text_rendering.c
|
- Fixed typos in examples/text_rendering.c
|
||||||
|
- Fixed Y placement of window when changing the window rect
|
||||||
|
- Fixed window sizing when setting scaled_width or scaled_height
|
||||||
|
- Updated readme
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## v0.00.002 - Text rendering, image manipulation, hash tables
|
## v0.00.002 - Text rendering, image manipulation, hash tables
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ Usage:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define QUADS_PER_BLOCK 1024
|
#define QUADS_PER_BLOCK 16
|
||||||
typedef struct Draw_Quad {
|
typedef struct Draw_Quad {
|
||||||
Vector2 bottom_left, top_left, top_right, bottom_right;
|
Vector2 bottom_left, top_left, top_right, bottom_right;
|
||||||
// r, g, b, a
|
// r, g, b, a
|
||||||
|
|
|
@ -6,7 +6,7 @@ int entry(int argc, char **argv) {
|
||||||
window.width = 1280;
|
window.width = 1280;
|
||||||
window.height = 720;
|
window.height = 720;
|
||||||
window.x = 200;
|
window.x = 200;
|
||||||
window.y = 0;
|
window.y = 200;
|
||||||
|
|
||||||
window.clear_color = hex_to_rgba(0x2a2d3aff);
|
window.clear_color = hex_to_rgba(0x2a2d3aff);
|
||||||
|
|
||||||
|
@ -56,11 +56,11 @@ int entry(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_key_just_pressed(KEY_ARROW_LEFT)) {
|
if (is_key_just_pressed(KEY_ARROW_LEFT)) {
|
||||||
window.width += 10;
|
window.scaled_width += 10;
|
||||||
window.x -= 10;
|
window.x -= 10;
|
||||||
}
|
}
|
||||||
if (is_key_just_pressed(KEY_ARROW_RIGHT)) {
|
if (is_key_just_pressed(KEY_ARROW_RIGHT)) {
|
||||||
window.width += 10;
|
window.scaled_width += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_key_just_released('Q')) {
|
if (is_key_just_released('Q')) {
|
||||||
|
@ -89,7 +89,7 @@ int entry(int argc, char **argv) {
|
||||||
draw_frame.view = camera_view;
|
draw_frame.view = camera_view;
|
||||||
|
|
||||||
seed_for_random = 69;
|
seed_for_random = 69;
|
||||||
for (u64 i = 0; i < 10000; i++) {
|
for (u64 i = 0; i < 100000; i++) {
|
||||||
float32 aspect = (float32)window.width/(float32)window.height;
|
float32 aspect = (float32)window.width/(float32)window.height;
|
||||||
float min_x = -aspect;
|
float min_x = -aspect;
|
||||||
float max_x = aspect;
|
float max_x = aspect;
|
||||||
|
|
|
@ -539,27 +539,10 @@ void d3d11_draw_call(int number_of_rendered_quads, ID3D11ShaderResourceView **te
|
||||||
VTABLE(Draw, d3d11_context, number_of_rendered_quads * 6, 0);
|
VTABLE(Draw, d3d11_context, number_of_rendered_quads * 6, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_update() {
|
void d3d11_process_draw_frame() {
|
||||||
if (window.should_close) return;
|
|
||||||
|
|
||||||
VTABLE(ClearRenderTargetView, d3d11_context, d3d11_window_render_target_view, (float*)&window.clear_color);
|
|
||||||
|
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
tm_scope_cycles("Frame setup") {
|
|
||||||
|
|
||||||
///
|
|
||||||
// Maybe resize swap chain
|
|
||||||
RECT client_rect;
|
|
||||||
bool ok = GetClientRect(window._os_handle, &client_rect);
|
|
||||||
assert(ok, "GetClientRect failed with error code %lu", GetLastError());
|
|
||||||
u32 window_width = client_rect.right-client_rect.left;
|
|
||||||
u32 window_height = client_rect.bottom-client_rect.top;
|
|
||||||
if (window_width != d3d11_swap_chain_width || window_height != d3d11_swap_chain_height) {
|
|
||||||
d3d11_update_swapchain();
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
// Maybe grow quad vbo
|
// Maybe grow quad vbo
|
||||||
u32 required_size = sizeof(D3D11_Vertex) * draw_frame.num_blocks*QUADS_PER_BLOCK*6;
|
u32 required_size = sizeof(D3D11_Vertex) * draw_frame.num_blocks*QUADS_PER_BLOCK*6;
|
||||||
|
@ -583,7 +566,6 @@ void gfx_update() {
|
||||||
|
|
||||||
log_verbose("Grew quad vbo to %d bytes.", d3d11_quad_vbo_size);
|
log_verbose("Grew quad vbo to %d bytes.", d3d11_quad_vbo_size);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (draw_frame.num_blocks > 0) {
|
if (draw_frame.num_blocks > 0) {
|
||||||
///
|
///
|
||||||
|
@ -731,11 +713,30 @@ void gfx_update() {
|
||||||
tm_scope_cycles("Draw call") d3d11_draw_call(number_of_rendered_quads, textures, num_textures);
|
tm_scope_cycles("Draw call") d3d11_draw_call(number_of_rendered_quads, textures, num_textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
tm_scope_cycles("Present") {
|
reset_draw_frame(&draw_frame);
|
||||||
hr = VTABLE(Present, d3d11_swap_chain, window.enable_vsync, window.enable_vsync ? 0 : DXGI_PRESENT_ALLOW_TEARING);
|
}
|
||||||
win32_check_hr(hr);
|
|
||||||
|
void gfx_update() {
|
||||||
|
if (window.should_close) return;
|
||||||
|
|
||||||
|
VTABLE(ClearRenderTargetView, d3d11_context, d3d11_window_render_target_view, (float*)&window.clear_color);
|
||||||
|
|
||||||
|
HRESULT hr;
|
||||||
|
///
|
||||||
|
// Maybe resize swap chain
|
||||||
|
RECT client_rect;
|
||||||
|
bool ok = GetClientRect(window._os_handle, &client_rect);
|
||||||
|
assert(ok, "GetClientRect failed with error code %lu", GetLastError());
|
||||||
|
u32 window_width = client_rect.right-client_rect.left;
|
||||||
|
u32 window_height = client_rect.bottom-client_rect.top;
|
||||||
|
if (window_width != d3d11_swap_chain_width || window_height != d3d11_swap_chain_height) {
|
||||||
|
d3d11_update_swapchain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d3d11_process_draw_frame();
|
||||||
|
|
||||||
|
VTABLE(Present, d3d11_swap_chain, window.enable_vsync, window.enable_vsync ? 0 : DXGI_PRESENT_ALLOW_TEARING);
|
||||||
|
|
||||||
#if CONFIGURATION == DEBUG
|
#if CONFIGURATION == DEBUG
|
||||||
///
|
///
|
||||||
// Check debug messages, output to stdout
|
// Check debug messages, output to stdout
|
||||||
|
@ -757,8 +758,6 @@ void gfx_update() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
reset_draw_frame(&draw_frame);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,9 +73,14 @@ typedef struct Heap_Block {
|
||||||
// 32 bytes !!
|
// 32 bytes !!
|
||||||
} Heap_Block;
|
} Heap_Block;
|
||||||
|
|
||||||
|
#define HEAP_META_SIGNATURE 6969694206942069ull
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u64 size;
|
u64 size;
|
||||||
Heap_Block *block;
|
Heap_Block *block;
|
||||||
|
#if CONFIGURATION == DEBUG
|
||||||
|
u64 signature;
|
||||||
|
u64 padding;
|
||||||
|
#endif
|
||||||
} Heap_Allocation_Metadata;
|
} Heap_Allocation_Metadata;
|
||||||
|
|
||||||
Heap_Block *heap_head;
|
Heap_Block *heap_head;
|
||||||
|
@ -114,19 +119,24 @@ void santiy_check_free_node_tree(Heap_Block *block) {
|
||||||
Heap_Free_Node *other_node = node->next;
|
Heap_Free_Node *other_node = node->next;
|
||||||
|
|
||||||
while (other_node != 0) {
|
while (other_node != 0) {
|
||||||
assert(other_node != node, "Circular reference in heap free node tree. That's bad.");
|
assert(other_node != node, "Circular reference in heap free node tree. This is probably an internal error, or an extremely unlucky result from heap corruption.");
|
||||||
other_node = other_node->next;
|
other_node = other_node->next;
|
||||||
}
|
}
|
||||||
total_free += node->size;
|
total_free += node->size;
|
||||||
assert(total_free <= block->size, "Free nodes are fucky wucky");
|
assert(total_free <= block->size, "Free nodes are fucky wucky. This might be heap corruption, or possibly an internal error.");
|
||||||
node = node->next;
|
node = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
inline void check_meta(Heap_Allocation_Metadata *meta) {
|
inline void check_meta(Heap_Allocation_Metadata *meta) {
|
||||||
|
#if CONFIGURATION == DEBUG
|
||||||
|
assert(meta->signature == HEAP_META_SIGNATURE, "Heap error. Either 1) You passed a bad pointer to dealloc or 2) You corrupted the heap.");
|
||||||
|
#endif
|
||||||
// If > 256GB then prolly not legit lol
|
// If > 256GB then prolly not legit lol
|
||||||
assert(meta->size < 1024ULL*1024ULL*1024ULL*256ULL, "Garbage pointer passed to heap_dealloc !!! Or could be corrupted memory.");
|
assert(meta->size < 1024ULL*1024ULL*1024ULL*256ULL, "Heap error. Either 1) You passed a bad pointer to dealloc or 2) You corrupted the heap.");
|
||||||
assert(is_pointer_in_program_memory(meta->block), "Garbage pointer passed to heap_dealloc !!! Or could be corrupted memory.");
|
assert(is_pointer_in_program_memory(meta->block), "Heap error. Either 1) You passed a bad pointer to dealloc or 2) You corrupted the heap.");
|
||||||
|
|
||||||
|
assert((u64)meta >= (u64)meta->block->start && (u64)meta < (u64)meta->block->start+meta->block->size, "Heap error: Pointer is not in it's metadata block. This could be heap corruption but it's more likely an internal error. That's not good.");
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -152,7 +162,7 @@ Heap_Search_Result search_heap_block(Heap_Block *block, u64 size) {
|
||||||
result.best_fit = node;
|
result.best_fit = node;
|
||||||
result.previous = previous;
|
result.previous = previous;
|
||||||
result.delta = 0;
|
result.delta = 0;
|
||||||
assert(result.previous != result.best_fit);
|
assert(result.previous != result.best_fit, "Internal goof");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +186,7 @@ Heap_Search_Result search_heap_block(Heap_Block *block, u64 size) {
|
||||||
result.best_fit = best_fit;
|
result.best_fit = best_fit;
|
||||||
result.previous = before_best_fit;
|
result.previous = before_best_fit;
|
||||||
result.delta = best_fit_delta;
|
result.delta = best_fit_delta;
|
||||||
assert(result.previous != result.best_fit);
|
assert(result.previous != result.best_fit, "Internal goof");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,11 +208,11 @@ Heap_Block *make_heap_block(Heap_Block *parent, u64 size) {
|
||||||
if (((u8*)block)+size >= ((u8*)program_memory)+program_memory_size) {
|
if (((u8*)block)+size >= ((u8*)program_memory)+program_memory_size) {
|
||||||
u64 minimum_size = ((u8*)block+size) - (u8*)program_memory + 1;
|
u64 minimum_size = ((u8*)block+size) - (u8*)program_memory + 1;
|
||||||
u64 new_program_size = get_next_power_of_two(minimum_size);
|
u64 new_program_size = get_next_power_of_two(minimum_size);
|
||||||
assert(new_program_size >= minimum_size, "Bröd");
|
assert(new_program_size >= minimum_size, "Internal goof");
|
||||||
const u64 ATTEMPTS = 1000;
|
const u64 ATTEMPTS = 1000;
|
||||||
for (u64 i = 0; i <= ATTEMPTS; i++) {
|
for (u64 i = 0; i <= ATTEMPTS; i++) {
|
||||||
if (program_memory_size >= new_program_size) break; // Another thread might have resized already, causing it to fail here.
|
if (program_memory_size >= new_program_size) break; // Another thread might have resized already, causing it to fail here.
|
||||||
assert(i < ATTEMPTS, "OS is not letting us allocate more memory. Maybe we are out of memory?");
|
assert(i < ATTEMPTS, "OS is not letting us allocate more memory. Maybe we are out of memory? You sure must be using a lot of memory then.");
|
||||||
if (os_grow_program_memory(new_program_size))
|
if (os_grow_program_memory(new_program_size))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -236,6 +246,8 @@ void *heap_alloc(u64 size) {
|
||||||
// #Sync #Speed oof
|
// #Sync #Speed oof
|
||||||
os_spinlock_lock(heap_lock);
|
os_spinlock_lock(heap_lock);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size += sizeof(Heap_Allocation_Metadata);
|
size += sizeof(Heap_Allocation_Metadata);
|
||||||
|
|
||||||
size = (size+HEAP_ALIGNMENT) & ~(HEAP_ALIGNMENT-1);
|
size = (size+HEAP_ALIGNMENT) & ~(HEAP_ALIGNMENT-1);
|
||||||
|
@ -291,10 +303,7 @@ void *heap_alloc(u64 size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ideally this should not be possible.
|
assert(best_fit != 0, "Internal heap error");
|
||||||
// If we run out of program_memory, we should just grow it and if that fails
|
|
||||||
// we crash because out of memory.
|
|
||||||
assert(best_fit != 0, "Internal heap allocation failed");
|
|
||||||
|
|
||||||
Heap_Free_Node *new_free_node = 0;
|
Heap_Free_Node *new_free_node = 0;
|
||||||
if (size != best_fit->size) {
|
if (size != best_fit->size) {
|
||||||
|
@ -305,10 +314,10 @@ void *heap_alloc(u64 size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previous && new_free_node) {
|
if (previous && new_free_node) {
|
||||||
assert(previous->next == best_fit, "Bro what");
|
assert(previous->next == best_fit, "Internal heap error");
|
||||||
previous->next = new_free_node;
|
previous->next = new_free_node;
|
||||||
} else if (previous) {
|
} else if (previous) {
|
||||||
assert(previous->next == best_fit, "Bro what");
|
assert(previous->next == best_fit, "Internal heap error");
|
||||||
previous->next = best_fit->next;
|
previous->next = best_fit->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,8 +333,13 @@ void *heap_alloc(u64 size) {
|
||||||
Heap_Allocation_Metadata *meta = (Heap_Allocation_Metadata*)best_fit;
|
Heap_Allocation_Metadata *meta = (Heap_Allocation_Metadata*)best_fit;
|
||||||
meta->size = size;
|
meta->size = size;
|
||||||
meta->block = best_fit_block;
|
meta->block = best_fit_block;
|
||||||
|
#if CONFIGURATION == DEBUG
|
||||||
|
meta->signature = HEAP_META_SIGNATURE;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIGURATION == VERY_DEBUG
|
check_meta(meta);
|
||||||
|
|
||||||
|
#if VERY_DEBUG
|
||||||
santiy_check_free_node_tree(meta->block);
|
santiy_check_free_node_tree(meta->block);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -334,7 +348,7 @@ void *heap_alloc(u64 size) {
|
||||||
|
|
||||||
|
|
||||||
void *p = ((u8*)meta)+sizeof(Heap_Allocation_Metadata);
|
void *p = ((u8*)meta)+sizeof(Heap_Allocation_Metadata);
|
||||||
assert((u64)p % HEAP_ALIGNMENT == 0);
|
assert((u64)p % HEAP_ALIGNMENT == 0, "Internal heap error. Result pointer is not aligned to HEAP_ALIGNMENT");
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
void heap_dealloc(void *p) {
|
void heap_dealloc(void *p) {
|
||||||
|
@ -344,17 +358,19 @@ void heap_dealloc(void *p) {
|
||||||
|
|
||||||
os_spinlock_lock(heap_lock);
|
os_spinlock_lock(heap_lock);
|
||||||
|
|
||||||
assert(is_pointer_in_program_memory(p), "Garbage pointer; out of program memory bounds!");
|
assert(is_pointer_in_program_memory(p), "A bad pointer was passed tp heap_dealloc: it is out of program memory bounds!");
|
||||||
p = (u8*)p-sizeof(Heap_Allocation_Metadata);
|
p = (u8*)p-sizeof(Heap_Allocation_Metadata);
|
||||||
Heap_Allocation_Metadata *meta = (Heap_Allocation_Metadata*)(p);
|
Heap_Allocation_Metadata *meta = (Heap_Allocation_Metadata*)(p);
|
||||||
check_meta(meta);
|
check_meta(meta);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Yoink meta data before we start overwriting it
|
// Yoink meta data before we start overwriting it
|
||||||
Heap_Block *block = meta->block;
|
Heap_Block *block = meta->block;
|
||||||
u64 size = meta->size;
|
u64 size = meta->size;
|
||||||
|
|
||||||
|
#if VERY_DEBUG
|
||||||
|
santiy_check_free_node_tree(block);
|
||||||
|
#endif
|
||||||
|
|
||||||
Heap_Free_Node *new_node = cast(Heap_Free_Node*)p;
|
Heap_Free_Node *new_node = cast(Heap_Free_Node*)p;
|
||||||
new_node->size = size;
|
new_node->size = size;
|
||||||
|
|
||||||
|
@ -368,14 +384,25 @@ void heap_dealloc(void *p) {
|
||||||
block->free_head = new_node;
|
block->free_head = new_node;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Heap_Free_Node *node = block->free_head;
|
|
||||||
|
|
||||||
|
if (!block->free_head) {
|
||||||
|
block->free_head = new_node;
|
||||||
|
new_node->next = 0;
|
||||||
|
} else {
|
||||||
|
Heap_Free_Node *node = block->free_head;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
assert(node != 0, "We didn't find where the free node should be! uh oh");
|
assert(node != 0, "We didn't find where the free node should be! This is likely heap corruption (or, hopefully not, an internal error)");
|
||||||
|
|
||||||
if (new_node > node) {
|
// In retrospect, I don't remember a good reason to care about where the
|
||||||
|
// free nodes are... maybe I'm just dumb right now? #Speed #Memory
|
||||||
|
// ... ACtually, it's probably to easily know when to merge free nodes.
|
||||||
|
// BUT. Maybe it's not worth the performance hit? Then again, if the heap
|
||||||
|
// allocator slows down your program you should rethink your memory management
|
||||||
|
// anyways...
|
||||||
|
|
||||||
|
if (new_node >= node) {
|
||||||
u8* node_tail = (u8*)node + node->size;
|
u8* node_tail = (u8*)node + node->size;
|
||||||
if (cast(u8*)new_node == node_tail) {
|
if (cast(u8*)new_node == node_tail) {
|
||||||
node->size += new_node->size;
|
node->size += new_node->size;
|
||||||
|
@ -396,10 +423,9 @@ void heap_dealloc(void *p) {
|
||||||
node = node->next;
|
node = node->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if CONFIGURATION == VERY_DEBUG
|
|
||||||
santiy_check_free_node_tree(block);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// #Sync #Speed oof
|
// #Sync #Speed oof
|
||||||
os_spinlock_unlock(heap_lock);
|
os_spinlock_unlock(heap_lock);
|
||||||
|
|
|
@ -152,7 +152,6 @@ typedef u8 bool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#define VERY_DEBUG 1
|
|
||||||
#define RELEASE 2
|
#define RELEASE 2
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
|
|
|
@ -947,8 +947,8 @@ void os_update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_window.scaled_width != window.scaled_width || last_window.scaled_height != window.scaled_height) {
|
if (last_window.scaled_width != window.scaled_width || last_window.scaled_height != window.scaled_height) {
|
||||||
window.width = window.scaled_width*dpi_scale_factor;
|
window.width = window.scaled_width/dpi_scale_factor;
|
||||||
window.height = window.scaled_height*dpi_scale_factor;
|
window.height = window.scaled_height/dpi_scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ok;
|
BOOL ok;
|
||||||
|
@ -966,7 +966,7 @@ void os_update() {
|
||||||
assert(ok != 0, "AdjustWindowRectEx failed with error code %lu", GetLastError());
|
assert(ok != 0, "AdjustWindowRectEx failed with error code %lu", GetLastError());
|
||||||
|
|
||||||
u32 actual_x = update_rect.left;
|
u32 actual_x = update_rect.left;
|
||||||
u32 actual_y = update_rect.top;
|
u32 actual_y = screen_height - update_rect.top - window.height;
|
||||||
u32 actual_width = update_rect.right - update_rect.left;
|
u32 actual_width = update_rect.right - update_rect.left;
|
||||||
u32 actual_height = update_rect.bottom - update_rect.top;
|
u32 actual_height = update_rect.bottom - update_rect.top;
|
||||||
|
|
||||||
|
|
Reference in a new issue