Skip to content

Commit

Permalink
More benchmarks (#153)
Browse files Browse the repository at this point in the history
New render primitives.
Large world testing.
Memory stats.
Bug fixes.
Option to disable automatic mass computation to avoid n-squared
computation on compounds.
Explosion function.
Per body sleep threshold that uses max extents for rotation sleeping
Hex color for all debug draw.
Option to draw using camera bounds for large world testing. Has minor
sorting problem.
Option to create contacts when static shapes are created or destroyed.
  • Loading branch information
erincatto authored May 5, 2024
1 parent 0c30b82 commit cc015ca
Show file tree
Hide file tree
Showing 67 changed files with 3,652 additions and 1,574 deletions.
62 changes: 60 additions & 2 deletions benchmark/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
#include <stdbool.h>
#include <stdio.h>

#if defined(_WIN64)
#include <windows.h>
#elif defined(__APPLE__)
// #include <sys/param.h>
// #include <sys/sysctl.h>
#include <unistd.h>
#elif defined(__linux__)
#include <unistd.h>
#endif

#define ARRAY_COUNT(A) (int)(sizeof(A) / sizeof(A[0]))
#define MAYBE_UNUSED(x) ((void)(x))

Expand Down Expand Up @@ -44,6 +54,39 @@ enkiTaskSet* tasks[MAX_TASKS];
TaskData taskData[MAX_TASKS];
int taskCount;

int GetNumberOfCores()
{
#if defined(_WIN64)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif defined(__APPLE__)
// int nm[2];
// size_t len = 4;
// uint32_t count;

// nm[0] = CTL_HW;
// nm[1] = HW_AVAILCPU;
// sysctl(nm, 2, &count, &len, NULL, 0);

// if (count < 1)
//{
// nm[1] = HW_NCPU;
// sysctl(nm, 2, &count, &len, NULL, 0);
// if (count < 1)
// {
// count = 1;
// }
// }
// return count;
return sysconf(_SC_NPROCESSORS_ONLN);
#elif defined(__linux__)
return sysconf(_SC_NPROCESSORS_ONLN);
#else
return 1;
#endif
}

void ExecuteRangeTask(uint32_t start, uint32_t end, uint32_t threadIndex, void* context)
{
TaskData* data = context;
Expand Down Expand Up @@ -92,13 +135,28 @@ static void FinishTask(void* userTask, void* userContext)

int main(int argc, char** argv)
{
int maxThreadCount = 8;
int maxThreadCount = GetNumberOfCores();
int runCount = 4;
b2Counters counters = {0};
bool enableContinuous = true;

assert(maxThreadCount <= THREAD_LIMIT);

for (int i = 1; i < argc; ++i)
{
const char* arg = argv[i];
if (strncmp(arg, "-t=", 3) == 0)
{
int threadCount = atoi(arg + 3);
maxThreadCount = B2_MIN(maxThreadCount, threadCount);
}
else if (strcmp(arg, "-h") == 0)
{
printf("Usage\n"
"-t=<thread count>: the maximum number of threads to use\n");
}
}

Benchmark benchmarks[] = {
{"joint_grid", JointGrid, 500},
{"large_pyramid", LargePyramid, 500},
Expand All @@ -121,7 +179,7 @@ int main(int argc, char** argv)
#endif

bool countersAcquired = false;

printf("benchmark: %s, steps = %d\n", benchmarks[benchmarkIndex].name, stepCount);

float maxFps[THREAD_LIMIT] = {0};
Expand Down
32 changes: 28 additions & 4 deletions include/box2d/box2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ B2_API void b2World_SetGravity(b2WorldId worldId, b2Vec2 gravity);
/// @return the gravity vector
B2_API b2Vec2 b2World_GetGravity(b2WorldId worldId);

/// Apply explosion
B2_API void b2World_Explode(b2WorldId worldId, b2Vec2 position, float radius, float impulse);

/// Adjust contact tuning parameters:
/// - hertz is the contact stiffness (cycles per second)
/// - damping ratio is the contact bounciness with 1 being critical damping (non-dimensional)
Expand All @@ -128,6 +131,9 @@ B2_API b2Profile b2World_GetProfile(b2WorldId worldId);
/// Get counters and sizes
B2_API b2Counters b2World_GetCounters(b2WorldId worldId);

/// Dump memory stats to box2d_memory.txt
B2_API void b2World_DumpMemoryStats(b2WorldId worldId);

/** @} */

/**
Expand All @@ -151,7 +157,8 @@ B2_API bool b2Body_IsValid(b2BodyId id);
/// Get the body type: static, kinematic, or dynamic
B2_API b2BodyType b2Body_GetType(b2BodyId bodyId);

/// Change the body type. This is an expensive operation.
/// Change the body type. This is an expensive operation. This automatically updates the mass
/// properties regardless of the automatic mass setting.
B2_API void b2Body_SetType(b2BodyId bodyId, b2BodyType type);

/// Set the user data for a body
Expand Down Expand Up @@ -263,10 +270,18 @@ B2_API void b2Body_SetMassData(b2BodyId bodyId, b2MassData massData);
/// Get the mass data for a body.
B2_API b2MassData b2Body_GetMassData(b2BodyId bodyId);

/// This resets the mass properties to the sum of the mass properties of the fixtures.
/// This resets the mass properties to the sum of the mass properties of the shapes.
/// This normally does not need to be called unless you called SetMassData to override
/// the mass and you later want to reset the mass.
B2_API void b2Body_ResetMassData(b2BodyId bodyId);
/// You may also use this when automatic mass computation has been disabled.
/// You should call this regardless of body type.
B2_API void b2Body_ApplyMassFromShapes(b2BodyId bodyId);

/// Set the automatic mass setting.
B2_API void b2Body_SetAutomaticMass(b2BodyId bodyId, bool automaticMass);

/// Get the automatic mass setting.
B2_API bool b2Body_GetAutomaticMass(b2BodyId bodyId);

/// Adjust the linear damping. Normally this is set in b2BodyDef before creation.
B2_API void b2Body_SetLinearDamping(b2BodyId bodyId, float linearDamping);
Expand Down Expand Up @@ -300,6 +315,12 @@ B2_API void b2Body_EnableSleep(b2BodyId bodyId, bool enableSleep);
/// @return is sleeping enabled for this body?
B2_API bool b2Body_IsSleepEnabled(b2BodyId bodyId);

/// Set the sleep threshold. Normally in meters per second.
B2_API void b2Body_SetSleepThreshold(b2BodyId bodyId, float sleepVelocity);

/// Get the sleep threshold. Normally in meters per second.
B2_API float b2Body_GetSleepThreshold(b2BodyId bodyId);

/// Is this body enabled?
B2_API bool b2Body_IsEnabled(b2BodyId bodyId);

Expand All @@ -309,7 +330,7 @@ B2_API void b2Body_Disable(b2BodyId bodyId);
/// Enable a body by adding it to the simulation
B2_API void b2Body_Enable(b2BodyId bodyId);

/// Set this body to have fixed rotation. This causes the mass to be reset.
/// Set this body to have fixed rotation. This causes the mass to be reset in all cases.
B2_API void b2Body_SetFixedRotation(b2BodyId bodyId, bool flag);

/// Does this body have fixed rotation?
Expand Down Expand Up @@ -492,6 +513,9 @@ B2_API int b2Shape_GetContactData(b2ShapeId shapeId, b2ContactData* contactData,
/// Get the current world AABB
B2_API b2AABB b2Shape_GetAABB(b2ShapeId shapeId);

/// Get the closest point on a shape to a target point. Target and result are in world space.
B2_API b2Vec2 b2Shape_GetClosestPoint(b2ShapeId shapeId, b2Vec2 target);

/// Chain Shape

/// Create a chain shape
Expand Down
2 changes: 1 addition & 1 deletion include/box2d/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#pragma once

#include "api.h"
#include "types.h"
#include "math_types.h"

/// All the colors! Credit to wherever I got this from, I forget.
typedef enum b2HexColor
Expand Down
6 changes: 0 additions & 6 deletions include/box2d/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@
/// The time that a body must be still before it will go to sleep. In seconds.
#define b2_timeToSleep 0.5f

/// A body cannot sleep if its linear velocity is above this tolerance. Meters per second.
#define b2_linearSleepTolerance (0.01f * b2_lengthUnitsPerMeter)

/// A body cannot sleep if its angular velocity is above this tolerance. Radians per second.
#define b2_angularSleepTolerance (2.0f / 180.0f * b2_pi)

/// Used to detect bad values. Positions greater than about 16km will have precision
/// problems, so 100km as a limit should be fine in all cases.
#define b2_huge (100000.0f * b2_lengthUnitsPerMeter)
Expand Down
24 changes: 13 additions & 11 deletions include/box2d/debug_draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,45 @@
#pragma once

#include "math_types.h"
#include "color.h"

/// This struct holds callbacks you can implement to draw a box2d world.
typedef struct b2DebugDraw
{
/// Draw a closed polygon provided in CCW order.
void (*DrawPolygon)(const b2Vec2* vertices, int vertexCount, b2Color 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)(const b2Vec2* vertices, int vertexCount, b2Color color, void* context);

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

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

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

/// Draw a capsule.
void (*DrawCapsule)(b2Vec2 p1, b2Vec2 p2, float radius, b2Color color, void* context);
void (*DrawCapsule)(b2Vec2 p1, b2Vec2 p2, float radius, b2HexColor color, void* context);

/// Draw a solid capsule.
void (*DrawSolidCapsule)(b2Vec2 p1, b2Vec2 p2, float radius, b2Color 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, b2Color 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);

/// Draw a point.
void (*DrawPoint)(b2Vec2 p, float size, b2Color 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);

b2AABB drawingBounds;
bool useDrawingBounds;

bool drawShapes;
bool drawJoints;
bool drawJointExtras;
Expand Down
4 changes: 4 additions & 0 deletions include/box2d/dynamic_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,13 @@ B2_API int32_t b2DynamicTree_Rebuild(b2DynamicTree* tree, bool fullBuild);

/// Shift the world origin. Useful for large worlds.
/// The shift formula is: position -= newOrigin
/// @param tree the tree to shift
/// @param newOrigin the new origin with respect to the old origin
B2_API void b2DynamicTree_ShiftOrigin(b2DynamicTree* tree, b2Vec2 newOrigin);

/// Get the number of bytes used by this tree
B2_API int b2DynamicTree_GetByteCount(b2DynamicTree* tree);

/// Get proxy user data
/// @return the proxy user data or 0 if the id is invalid
B2_INLINE int32_t b2DynamicTree_GetUserData(const b2DynamicTree* tree, int32_t proxyId)
Expand Down
42 changes: 42 additions & 0 deletions include/box2d/math_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <math.h>
#include <stdbool.h>

// todo these macros are not safe due to no sync point

/// Macro to get the minimum of two values
#define B2_MIN(A, B) ((A) < (B) ? (A) : (B))

Expand All @@ -27,6 +29,46 @@ static const b2Rot b2Rot_identity = {1.0f, 0.0f};
static const b2Transform b2Transform_identity = {{0.0f, 0.0f}, {1.0f, 0.0f}};
static const b2Mat22 b2Mat22_zero = {{0.0f, 0.0f}, {0.0f, 0.0f}};

B2_INLINE float b2MinFloat(float a, float b)
{
return a < b ? a : b;
}

B2_INLINE float b2MaxFloat(float a, float b)
{
return a > b ? a : b;
}

B2_INLINE float b2AbsFloat(float a)
{
return a < 0 ? -a : a;
}

B2_INLINE float b2ClampFloat(float a, float lower, float upper)
{
return a < lower ? lower : (a > upper ? upper : a);
}

B2_INLINE int b2MinInt(int a, int b)
{
return a < b ? a : b;
}

B2_INLINE int b2MaxInt(int a, int b)
{
return a > b ? a : b;
}

B2_INLINE int b2AbsInt(int a)
{
return a < 0 ? -a : a;
}

B2_INLINE int b2ClampInt(int a, int lower, int upper)
{
return a < lower ? lower : (a > upper ? upper : a);
}

/// Vector dot product
B2_INLINE float b2Dot(b2Vec2 a, b2Vec2 b)
{
Expand Down
15 changes: 14 additions & 1 deletion include/box2d/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ typedef enum b2BodyType
/// You can safely re-use body definitions. Shapes are added to a body after construction.
typedef struct b2BodyDef
{
/// The body type: static, kinematic, or dynamic.
/// The body type: static, kinematic, or dynamic.
/// Note: if a dynamic body would have zero mass, the mass is set to one.
b2BodyType type;

Expand Down Expand Up @@ -121,6 +121,9 @@ typedef struct b2BodyDef
/// Scale the gravity applied to this body.
float gravityScale;

/// Sleep velocity threshold, default is 0.05 meter per second
float sleepThreshold;

/// Use this to store application specific body data.
void* userData;

Expand All @@ -140,6 +143,10 @@ typedef struct b2BodyDef

/// Does this body start out enabled?
bool isEnabled;

/// Automatically compute mass and related properties on this body from shapes.
/// Triggers whenever a shape is add/removed/changed. Default is true.
bool automaticMass;
} b2BodyDef;

/// This holds contact filtering data.
Expand Down Expand Up @@ -211,6 +218,11 @@ typedef struct b2ShapeDef
/// and must be carefully handled due to multi-threading. Ignored for sensors.
bool enablePreSolveEvents;

/// Normally shapes on static bodies don't invoke contact creation when they are added to the world. This overrides
/// that behavior and causes contact creation. This significantly slows down static body creation which can be important
/// when there are many static bodies.
bool forceContactCreation;

} b2ShapeDef;

/// Used to create a chain of edges. This is designed to eliminate ghost collisions with some limitations.
Expand Down Expand Up @@ -286,6 +298,7 @@ typedef struct b2Counters
int32_t jointCount;
int32_t islandCount;
int32_t stackUsed;
int32_t staticTreeHeight;
int32_t treeHeight;
int32_t byteCount;
int32_t taskCount;
Expand Down
3 changes: 3 additions & 0 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ add_executable(samples
sample_robustness.cpp
sample_shapes.cpp
sample_stacking.cpp
sample_world.cpp
settings.cpp
settings.h
shader.cpp
shader.h
)

set_target_properties(samples PROPERTIES
Expand Down
Loading

0 comments on commit cc015ca

Please sign in to comment.