Skip to content

Commit

Permalink
stack allocator -> arena allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
erincatto committed Dec 22, 2024
1 parent f377034 commit 0a6553a
Show file tree
Hide file tree
Showing 19 changed files with 229 additions and 221 deletions.
23 changes: 12 additions & 11 deletions include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ typedef bool b2OverlapResultFcn( b2ShapeId shapeId, void* context );
/// @ingroup world
typedef float b2CastResultFcn( b2ShapeId shapeId, b2Vec2 point, b2Vec2 normal, float fraction, void* context );

/// These colors are used for debug draw.
/// These colors are used for debug draw and mostly match the named SVG colors.
/// See https://www.rapidtables.com/web/color/index.html
/// https://johndecember.com/html/spec/colorsvg.html
/// https://upload.wikimedia.org/wikipedia/commons/2/2b/SVG_Recognized_color_keyword_names.svg
Expand Down Expand Up @@ -1323,6 +1323,7 @@ typedef enum b2HexColor
b2_colorWhiteSmoke = 0xF5F5F5,
b2_colorYellow = 0xFFFF00,
b2_colorYellowGreen = 0x9ACD32,

b2_colorBox2DRed = 0xDC3132,
b2_colorBox2DBlue = 0x30AEBF,
b2_colorBox2DGreen = 0x8CC924,
Expand All @@ -1335,32 +1336,32 @@ typedef enum b2HexColor
typedef struct b2DebugDraw
{
/// Draw a closed polygon provided in CCW order.
void ( *DrawPolygon )( const b2Vec2* vertices, int vertexCount, b2HexColor color, void* context );
void ( *drawPolygon )( const b2Vec2* vertices, int vertexCount, b2HexColor color, void* context );

/// Draw a solid closed polygon provided in CCW order.
void ( *DrawSolidPolygon )( b2Transform transform, const b2Vec2* vertices, int vertexCount, float radius, b2HexColor color,
void ( *drawSolidPolygon )( b2Transform transform, const b2Vec2* vertices, int vertexCount, float radius, b2HexColor color,
void* context );

/// Draw a circle.
void ( *DrawCircle )( b2Vec2 center, float radius, b2HexColor color, void* context );
void ( *drawCircle )( b2Vec2 center, float radius, b2HexColor color, void* context );

/// Draw a solid circle.
void ( *DrawSolidCircle )( b2Transform transform, float radius, b2HexColor color, void* context );
void ( *drawSolidCircle )( b2Transform transform, float radius, b2HexColor color, void* context );

/// Draw a solid capsule.
void ( *DrawSolidCapsule )( b2Vec2 p1, b2Vec2 p2, float radius, b2HexColor color, void* context );
void ( *drawSolidCapsule )( b2Vec2 p1, b2Vec2 p2, float radius, b2HexColor color, void* context );

/// Draw a line segment.
void ( *DrawSegment )( b2Vec2 p1, b2Vec2 p2, b2HexColor color, void* context );
void ( *drawSegment )( b2Vec2 p1, b2Vec2 p2, b2HexColor color, void* context );

/// Draw a transform. Choose your own length scale.
void ( *DrawTransform )( b2Transform transform, void* context );
void ( *drawTransform )( b2Transform transform, void* context );

/// Draw a point.
void ( *DrawPoint )( b2Vec2 p, float size, b2HexColor color, void* context );
void ( *drawPoint )( b2Vec2 p, float size, b2HexColor color, void* context );

/// Draw a string.
void ( *DrawString )( b2Vec2 p, const char* s, void* context );
/// Draw a string in world space
void ( *drawString )( b2Vec2 p, const char* s, b2HexColor color, void* context );

/// Bounds to use if restricting drawing to a rectangular region
b2AABB drawingBounds;
Expand Down
50 changes: 27 additions & 23 deletions samples/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,7 @@ void DrawPointFcn( b2Vec2 p, float size, b2HexColor color, void* context )
static_cast<Draw*>( context )->DrawPoint( p, size, color );
}

void DrawStringFcn( b2Vec2 p, const char* s, void* context )
void DrawStringFcn( b2Vec2 p, const char* s, b2HexColor color, void* context )
{
static_cast<Draw*>( context )->DrawString( p, s );
}
Expand Down Expand Up @@ -1365,28 +1365,32 @@ void Draw::Create()

b2AABB bounds = { { -FLT_MAX, -FLT_MAX }, { FLT_MAX, FLT_MAX } };

m_debugDraw = { DrawPolygonFcn,
DrawSolidPolygonFcn,
DrawCircleFcn,
DrawSolidCircleFcn,
DrawSolidCapsuleFcn,
DrawSegmentFcn,
DrawTransformFcn,
DrawPointFcn,
DrawStringFcn,
bounds,
false, // drawUsingBounds
true, // shapes
true, // joints
false, // joint extras
false, // aabbs
false, // mass
false, // contacts
false, // colors
false, // normals
false, // impulse
false, // friction
this };
m_debugDraw = {};

m_debugDraw.drawPolygon = DrawPolygonFcn;
m_debugDraw.drawSolidPolygon = DrawSolidPolygonFcn;
m_debugDraw.drawCircle = DrawCircleFcn;
m_debugDraw.drawSolidCircle = DrawSolidCircleFcn;
m_debugDraw.drawSolidCapsule = DrawSolidCapsuleFcn;
m_debugDraw.drawSegment = DrawSegmentFcn;
m_debugDraw.drawTransform = DrawTransformFcn;
m_debugDraw.drawPoint = DrawPointFcn;
m_debugDraw.drawString = DrawStringFcn;
m_debugDraw.drawingBounds = bounds;

m_debugDraw.useDrawingBounds = false;
m_debugDraw.drawShapes = true;
m_debugDraw.drawJoints = true;
m_debugDraw.drawJointExtras = false;
m_debugDraw.drawAABBs = false;
m_debugDraw.drawMass = false;
m_debugDraw.drawContacts = false;
m_debugDraw.drawGraphColors = false;
m_debugDraw.drawContactNormals = false;
m_debugDraw.drawContactImpulses = false;
m_debugDraw.drawFrictionImpulses = false;

m_debugDraw.context = this;
}

void Draw::Destroy()
Expand Down
6 changes: 4 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
set(BOX2D_SOURCE_FILES
aabb.c
aabb.h
arena_allocator.c
arena_allocator.h
array.c
array.h
bitset.c
Expand Down Expand Up @@ -42,8 +44,6 @@ set(BOX2D_SOURCE_FILES
solver.h
solver_set.c
solver_set.h
stack_allocator.c
stack_allocator.h
table.c
table.h
timer.c
Expand Down Expand Up @@ -155,11 +155,13 @@ elseif (MINGW)
endif()
elseif (APPLE)
message(STATUS "Box2D on Apple")
target_compile_options(box2d PRIVATE -Wmissing-prototypes)
elseif (EMSCRIPTEN)
message(STATUS "Box2D on Emscripten")
target_compile_options(box2d PRIVATE -msimd128 -msse2)
elseif (UNIX)
message(STATUS "Box2D using Unix")
target_compile_options(box2d PRIVATE -Wmissing-prototypes)
if ("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "aarch64")
# raspberry pi
# -mfpu=neon
Expand Down
40 changes: 20 additions & 20 deletions src/stack_allocator.c → src/arena_allocator.c
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT

#include "stack_allocator.h"
#include "arena_allocator.h"

#include "array.h"
#include "core.h"

#include <stdbool.h>
#include <stddef.h>

typedef struct b2StackEntry
typedef struct b2ArenaEntry
{
char* data;
const char* name;
int size;
bool usedMalloc;
} b2StackEntry;
} b2ArenaEntry;

B2_ARRAY_INLINE( b2StackEntry, b2StackEntry );
B2_ARRAY_SOURCE( b2StackEntry, b2StackEntry );
B2_ARRAY_INLINE( b2ArenaEntry, b2ArenaEntry );
B2_ARRAY_SOURCE( b2ArenaEntry, b2ArenaEntry );

b2StackAllocator b2CreateStackAllocator( int capacity )
b2ArenaAllocator b2CreateArenaAllocator( int capacity )
{
B2_ASSERT( capacity >= 0 );
b2StackAllocator allocator = { 0 };
b2ArenaAllocator allocator = { 0 };
allocator.capacity = capacity;
allocator.data = b2Alloc( capacity );
allocator.allocation = 0;
allocator.maxAllocation = 0;
allocator.index = 0;
allocator.entries = b2StackEntryArray_Create( 32 );
allocator.entries = b2ArenaEntryArray_Create( 32 );
return allocator;
}

void b2DestroyStackAllocator( b2StackAllocator* allocator )
void b2DestroyArenaAllocator( b2ArenaAllocator* allocator )
{
b2StackEntryArray_Destroy( &allocator->entries );
b2ArenaEntryArray_Destroy( &allocator->entries );
b2Free( allocator->data, allocator->capacity );
}

void* b2AllocateStackItem( b2StackAllocator* alloc, int size, const char* name )
void* b2AllocateArenaItem( b2ArenaAllocator* alloc, int size, const char* name )
{
// ensure allocation is 32 byte aligned to support 256-bit SIMD
int size32 = ( ( size - 1 ) | 0x1F ) + 1;

b2StackEntry entry;
b2ArenaEntry entry;
entry.size = size32;
entry.name = name;
if ( alloc->index + size32 > alloc->capacity )
Expand All @@ -70,15 +70,15 @@ void* b2AllocateStackItem( b2StackAllocator* alloc, int size, const char* name )
alloc->maxAllocation = alloc->allocation;
}

b2StackEntryArray_Push( &alloc->entries, entry );
b2ArenaEntryArray_Push( &alloc->entries, entry );
return entry.data;
}

void b2FreeStackItem( b2StackAllocator* alloc, void* mem )
void b2FreeArenaItem( b2ArenaAllocator* alloc, void* mem )
{
int entryCount = alloc->entries.count;
B2_ASSERT( entryCount > 0 );
b2StackEntry* entry = alloc->entries.data + ( entryCount - 1 );
b2ArenaEntry* entry = alloc->entries.data + ( entryCount - 1 );
B2_ASSERT( mem == entry->data );
if ( entry->usedMalloc )
{
Expand All @@ -89,10 +89,10 @@ void b2FreeStackItem( b2StackAllocator* alloc, void* mem )
alloc->index -= entry->size;
}
alloc->allocation -= entry->size;
b2StackEntryArray_Pop( &alloc->entries );
b2ArenaEntryArray_Pop( &alloc->entries );
}

void b2GrowStack( b2StackAllocator* alloc )
void b2GrowArena( b2ArenaAllocator* alloc )
{
// Stack must not be in use
B2_ASSERT( alloc->allocation == 0 );
Expand All @@ -105,17 +105,17 @@ void b2GrowStack( b2StackAllocator* alloc )
}
}

int b2GetStackCapacity( b2StackAllocator* alloc )
int b2GetArenaCapacity( b2ArenaAllocator* alloc )
{
return alloc->capacity;
}

int b2GetStackAllocation( b2StackAllocator* alloc )
int b2GetArenaAllocation( b2ArenaAllocator* alloc )
{
return alloc->allocation;
}

int b2GetMaxStackAllocation( b2StackAllocator* alloc )
int b2GetMaxArenaAllocation( b2ArenaAllocator* alloc )
{
return alloc->maxAllocation;
}
38 changes: 38 additions & 0 deletions src/arena_allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT

#pragma once

#include "array.h"

B2_ARRAY_DECLARE( b2ArenaEntry, b2ArenaEntry );

// This is a stack-like arena allocator used for fast per step allocations.
// You must nest allocate/free pairs. The code will B2_ASSERT
// if you try to interleave multiple allocate/free pairs.
// This allocator uses the heap if space is insufficient.
// I could remove the need to free entries individually.
typedef struct b2ArenaAllocator
{
char* data;
int capacity;
int index;

int allocation;
int maxAllocation;

b2ArenaEntryArray entries;
} b2ArenaAllocator;

b2ArenaAllocator b2CreateArenaAllocator( int capacity );
void b2DestroyArenaAllocator( b2ArenaAllocator* allocator );

void* b2AllocateArenaItem( b2ArenaAllocator* alloc, int size, const char* name );
void b2FreeArenaItem( b2ArenaAllocator* alloc, void* mem );

// Grow the arena based on usage
void b2GrowArena( b2ArenaAllocator* alloc );

int b2GetArenaCapacity( b2ArenaAllocator* alloc );
int b2GetArenaAllocation( b2ArenaAllocator* alloc );
int b2GetMaxArenaAllocation( b2ArenaAllocator* alloc );
12 changes: 6 additions & 6 deletions src/broad_phase.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "contact.h"
#include "core.h"
#include "shape.h"
#include "stack_allocator.h"
#include "arena_allocator.h"
#include "world.h"

#include <stdatomic.h>
Expand Down Expand Up @@ -374,12 +374,12 @@ void b2UpdateBroadPhasePairs( b2World* world )

b2TracyCZoneNC( update_pairs, "Pairs", b2_colorMediumSlateBlue, true );

b2StackAllocator* alloc = &world->stackAllocator;
b2ArenaAllocator* alloc = &world->stackAllocator;

// todo these could be in the step context
bp->moveResults = b2AllocateStackItem( alloc, moveCount * sizeof( b2MoveResult ), "move results" );
bp->moveResults = b2AllocateArenaItem( alloc, moveCount * sizeof( b2MoveResult ), "move results" );
bp->movePairCapacity = 16 * moveCount;
bp->movePairs = b2AllocateStackItem( alloc, bp->movePairCapacity * sizeof( b2MovePair ), "move pairs" );
bp->movePairs = b2AllocateArenaItem( alloc, bp->movePairCapacity * sizeof( b2MovePair ), "move pairs" );
bp->movePairIndex = 0;

#ifndef NDEBUG
Expand Down Expand Up @@ -448,9 +448,9 @@ void b2UpdateBroadPhasePairs( b2World* world )
b2IntArray_Clear( &bp->moveArray );
b2ClearSet( &bp->moveSet );

b2FreeStackItem( alloc, bp->movePairs );
b2FreeArenaItem( alloc, bp->movePairs );
bp->movePairs = NULL;
b2FreeStackItem( alloc, bp->moveResults );
b2FreeArenaItem( alloc, bp->moveResults );
bp->moveResults = NULL;

b2ValidateSolverSets( world );
Expand Down
2 changes: 1 addition & 1 deletion src/broad_phase.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
typedef struct b2Shape b2Shape;
typedef struct b2MovePair b2MovePair;
typedef struct b2MoveResult b2MoveResult;
typedef struct b2StackAllocator b2StackAllocator;
typedef struct b2ArenaAllocator b2ArenaAllocator;
typedef struct b2World b2World;

// Store the proxy type in the lower 2 bits of the proxy key. This leaves 30 bits for the id.
Expand Down
2 changes: 1 addition & 1 deletion src/contact.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ void b2DestroyContact( b2World* world, b2Contact* contact, bool wakeBodies )
if ( ( flags & ( b2_contactTouchingFlag | b2_contactSensorTouchingFlag ) ) != 0 &&
( flags & ( b2_contactEnableContactEvents | b2_contactEnableSensorEvents ) ) != 0 )
{
int16_t worldId = world->worldId;
uint16_t worldId = world->worldId;
const b2Shape* shapeA = b2ShapeArray_Get( &world->shapes, contact->shapeIdA );
const b2Shape* shapeB = b2ShapeArray_Get( &world->shapes, contact->shapeIdB );
b2ShapeId shapeIdA = { shapeA->id + 1, worldId, shapeA->revision };
Expand Down
Loading

0 comments on commit 0a6553a

Please sign in to comment.