feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -47,6 +47,83 @@ public:
using const_iterator = const T *;
using iterator = T *;
/// An iterator that traverses the array in reverse order
class rev_it
{
public:
/// Constructor
rev_it() = default;
explicit rev_it(T *inValue) : mValue(inValue) { }
/// Copying
rev_it(const rev_it &) = default;
rev_it & operator = (const rev_it &) = default;
/// Comparison
bool operator == (const rev_it &inRHS) const { return mValue == inRHS.mValue; }
bool operator != (const rev_it &inRHS) const { return mValue != inRHS.mValue; }
/// Arithmetics
rev_it & operator ++ () { --mValue; return *this; }
rev_it operator ++ (int) { return rev_it(mValue--); }
rev_it & operator -- () { ++mValue; return *this; }
rev_it operator -- (int) { return rev_it(mValue++); }
rev_it operator + (int inValue) { return rev_it(mValue - inValue); }
rev_it operator - (int inValue) { return rev_it(mValue + inValue); }
rev_it & operator += (int inValue) { mValue -= inValue; return *this; }
rev_it & operator -= (int inValue) { mValue += inValue; return *this; }
/// Access
T & operator * () const { return *mValue; }
T & operator -> () const { return *mValue; }
private:
T * mValue;
};
/// A const iterator that traverses the array in reverse order
class crev_it
{
public:
/// Constructor
crev_it() = default;
explicit crev_it(const T *inValue) : mValue(inValue) { }
/// Copying
crev_it(const crev_it &) = default;
explicit crev_it(const rev_it &inValue) : mValue(inValue.mValue) { }
crev_it & operator = (const crev_it &) = default;
crev_it & operator = (const rev_it &inRHS) { mValue = inRHS.mValue; return *this; }
/// Comparison
bool operator == (const crev_it &inRHS) const { return mValue == inRHS.mValue; }
bool operator != (const crev_it &inRHS) const { return mValue != inRHS.mValue; }
/// Arithmetics
crev_it & operator ++ () { --mValue; return *this; }
crev_it operator ++ (int) { return crev_it(mValue--); }
crev_it & operator -- () { ++mValue; return *this; }
crev_it operator -- (int) { return crev_it(mValue++); }
crev_it operator + (int inValue) { return crev_it(mValue - inValue); }
crev_it operator - (int inValue) { return crev_it(mValue + inValue); }
crev_it & operator += (int inValue) { mValue -= inValue; return *this; }
crev_it & operator -= (int inValue) { mValue += inValue; return *this; }
/// Access
const T & operator * () const { return *mValue; }
const T & operator -> () const { return *mValue; }
private:
const T * mValue;
};
using reverse_iterator = rev_it;
using const_reverse_iterator = crev_it;
private:
/// Move elements from one location to another
inline void move(pointer inDestination, pointer inSource, size_type inCount)
@ -388,7 +465,7 @@ public:
}
/// Remove one element from the array
void erase(const_iterator inIter)
iterator erase(const_iterator inIter)
{
size_type p = size_type(inIter - begin());
JPH_ASSERT(p < mSize);
@ -396,10 +473,11 @@ public:
if (p + 1 < mSize)
move(mElements + p, mElements + p + 1, mSize - p - 1);
--mSize;
return const_cast<iterator>(inIter);
}
/// Remove multiple element from the array
void erase(const_iterator inBegin, const_iterator inEnd)
iterator erase(const_iterator inBegin, const_iterator inEnd)
{
size_type p = size_type(inBegin - begin());
size_type n = size_type(inEnd - inBegin);
@ -408,6 +486,7 @@ public:
if (p + n < mSize)
move(mElements + p, mElements + p + n, mSize - p - n);
mSize -= n;
return const_cast<iterator>(inBegin);
}
/// Iterators
@ -421,14 +500,34 @@ public:
return mElements + mSize;
}
inline crev_it rbegin() const
{
return crev_it(mElements + mSize - 1);
}
inline crev_it rend() const
{
return crev_it(mElements - 1);
}
inline const_iterator cbegin() const
{
return mElements;
return begin();
}
inline const_iterator cend() const
{
return mElements + mSize;
return end();
}
inline crev_it crbegin() const
{
return rbegin();
}
inline crev_it crend() const
{
return rend();
}
inline iterator begin()
@ -441,6 +540,16 @@ public:
return mElements + mSize;
}
inline rev_it rbegin()
{
return rev_it(mElements + mSize - 1);
}
inline rev_it rend()
{
return rev_it(mElements - 1);
}
inline const T * data() const
{
return mElements;

View file

@ -12,7 +12,7 @@ class Color;
using ColorArg = Color;
/// Class that holds an RGBA color with 8-bits per component
class [[nodiscard]] JPH_EXPORT_GCC_BUG_WORKAROUND Color
class JPH_EXPORT_GCC_BUG_WORKAROUND [[nodiscard]] Color
{
public:
/// Constructors

View file

@ -6,8 +6,8 @@
// Jolt library version
#define JPH_VERSION_MAJOR 5
#define JPH_VERSION_MINOR 2
#define JPH_VERSION_PATCH 1
#define JPH_VERSION_MINOR 3
#define JPH_VERSION_PATCH 0
// Determine which features the library was compiled with
#ifdef JPH_DOUBLE_PRECISION
@ -83,8 +83,8 @@
#define JPH_PLATFORM_ANDROID
#elif defined(__linux__)
#define JPH_PLATFORM_LINUX
#elif defined(__FreeBSD__)
#define JPH_PLATFORM_FREEBSD
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define JPH_PLATFORM_BSD
#elif defined(__APPLE__)
#include <TargetConditionals.h>
#if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
@ -195,7 +195,11 @@
#elif defined(JPH_PLATFORM_WASM)
// WebAssembly CPU architecture
#define JPH_CPU_WASM
#define JPH_CPU_ADDRESS_BITS 32
#if defined(__wasm64__)
#define JPH_CPU_ADDRESS_BITS 64
#else
#define JPH_CPU_ADDRESS_BITS 32
#endif
#define JPH_VECTOR_ALIGNMENT 16
#define JPH_DVECTOR_ALIGNMENT 32
#ifdef __wasm_simd128__
@ -360,6 +364,7 @@
JPH_MSVC_SUPPRESS_WARNING(4514) /* 'X' : unreferenced inline function has been removed */ \
JPH_MSVC_SUPPRESS_WARNING(4710) /* 'X' : function not inlined */ \
JPH_MSVC_SUPPRESS_WARNING(4711) /* function 'X' selected for automatic inline expansion */ \
JPH_MSVC_SUPPRESS_WARNING(4714) /* function 'X' marked as __forceinline not inlined */ \
JPH_MSVC_SUPPRESS_WARNING(4820) /* 'X': 'Y' bytes padding added after data member 'Z' */ \
JPH_MSVC_SUPPRESS_WARNING(4100) /* 'X' : unreferenced formal parameter */ \
JPH_MSVC_SUPPRESS_WARNING(4626) /* 'X' : assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted */ \
@ -388,9 +393,9 @@
// Configuration for a popular game console.
// This file is not distributed because it would violate an NDA.
// Creating one should only be a couple of minutes of work if you have the documentation for the platform
// (you only need to define JPH_BREAKPOINT, JPH_PLATFORM_BLUE_GET_TICKS, JPH_PLATFORM_BLUE_MUTEX*, JPH_PLATFORM_BLUE_RWLOCK* and include the right header).
// (you only need to define JPH_BREAKPOINT, JPH_PLATFORM_BLUE_GET_TICKS, JPH_PLATFORM_BLUE_MUTEX*, JPH_PLATFORM_BLUE_RWLOCK*, JPH_PLATFORM_BLUE_SEMAPHORE* and include the right header).
#include <Jolt/Core/PlatformBlue.h>
#elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS) || defined(JPH_PLATFORM_FREEBSD)
#elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS) || defined(JPH_PLATFORM_BSD)
#if defined(JPH_CPU_X86)
#define JPH_BREAKPOINT __asm volatile ("int $0x3")
#elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_E2K) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH)
@ -426,7 +431,8 @@
JPH_MSVC_SUPPRESS_WARNING(4514) \
JPH_MSVC_SUPPRESS_WARNING(5262) \
JPH_MSVC_SUPPRESS_WARNING(5264) \
JPH_MSVC_SUPPRESS_WARNING(4738)
JPH_MSVC_SUPPRESS_WARNING(4738) \
JPH_MSVC_SUPPRESS_WARNING(5045)
#define JPH_SUPPRESS_WARNINGS_STD_END \
JPH_SUPPRESS_WARNING_POP

View file

@ -16,11 +16,12 @@ JPH_NAMESPACE_BEGIN
class FPExceptionsEnable { };
class FPExceptionDisableInvalid { };
class FPExceptionDisableDivByZero { };
class FPExceptionDisableOverflow { };
#elif defined(JPH_USE_SSE)
/// Enable floating point divide by zero exception and exceptions on invalid numbers
class FPExceptionsEnable : public FPControlWord<0, _MM_MASK_DIV_ZERO | _MM_MASK_INVALID> { };
/// Enable floating point divide by zero exception, overflow exceptions and exceptions on invalid numbers
class FPExceptionsEnable : public FPControlWord<0, _MM_MASK_DIV_ZERO | _MM_MASK_INVALID | _MM_MASK_OVERFLOW> { };
/// Disable invalid floating point value exceptions
class FPExceptionDisableInvalid : public FPControlWord<_MM_MASK_INVALID, _MM_MASK_INVALID> { };
@ -28,10 +29,13 @@ class FPExceptionDisableInvalid : public FPControlWord<_MM_MASK_INVALID, _MM_MAS
/// Disable division by zero floating point exceptions
class FPExceptionDisableDivByZero : public FPControlWord<_MM_MASK_DIV_ZERO, _MM_MASK_DIV_ZERO> { };
/// Disable floating point overflow exceptions
class FPExceptionDisableOverflow : public FPControlWord<_MM_MASK_OVERFLOW, _MM_MASK_OVERFLOW> { };
#elif defined(JPH_CPU_ARM) && defined(JPH_COMPILER_MSVC)
/// Enable floating point divide by zero exception and exceptions on invalid numbers
class FPExceptionsEnable : public FPControlWord<0, _EM_INVALID | _EM_ZERODIVIDE> { };
/// Enable floating point divide by zero exception, overflow exceptions and exceptions on invalid numbers
class FPExceptionsEnable : public FPControlWord<0, _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW> { };
/// Disable invalid floating point value exceptions
class FPExceptionDisableInvalid : public FPControlWord<_EM_INVALID, _EM_INVALID> { };
@ -39,6 +43,9 @@ class FPExceptionDisableInvalid : public FPControlWord<_EM_INVALID, _EM_INVALID>
/// Disable division by zero floating point exceptions
class FPExceptionDisableDivByZero : public FPControlWord<_EM_ZERODIVIDE, _EM_ZERODIVIDE> { };
/// Disable floating point overflow exceptions
class FPExceptionDisableOverflow : public FPControlWord<_EM_OVERFLOW, _EM_OVERFLOW> { };
#elif defined(JPH_CPU_ARM)
/// Invalid operation exception bit
@ -47,8 +54,11 @@ static constexpr uint64 FP_IOE = 1 << 8;
/// Enable divide by zero exception bit
static constexpr uint64 FP_DZE = 1 << 9;
/// Enable floating point divide by zero exception and exceptions on invalid numbers
class FPExceptionsEnable : public FPControlWord<FP_IOE | FP_DZE, FP_IOE | FP_DZE> { };
/// Enable floating point overflow bit
static constexpr uint64 FP_OFE = 1 << 10;
/// Enable floating point divide by zero exception, overflow exceptions and exceptions on invalid numbers
class FPExceptionsEnable : public FPControlWord<FP_IOE | FP_DZE | FP_OFE, FP_IOE | FP_DZE | FP_OFE> { };
/// Disable invalid floating point value exceptions
class FPExceptionDisableInvalid : public FPControlWord<0, FP_IOE> { };
@ -56,6 +66,9 @@ class FPExceptionDisableInvalid : public FPControlWord<0, FP_IOE> { };
/// Disable division by zero floating point exceptions
class FPExceptionDisableDivByZero : public FPControlWord<0, FP_DZE> { };
/// Disable floating point overflow exceptions
class FPExceptionDisableOverflow : public FPControlWord<0, FP_OFE> { };
#elif defined(JPH_CPU_RISCV)
#error "RISC-V only implements manually checking if exceptions occurred by reading the fcsr register. It doesn't generate exceptions. JPH_FLOATING_POINT_EXCEPTIONS_ENABLED must be disabled."
@ -76,6 +89,7 @@ class FPExceptionDisableDivByZero : public FPControlWord<0, FP_DZE> { };
class FPExceptionsEnable { };
class FPExceptionDisableInvalid { };
class FPExceptionDisableDivByZero { };
class FPExceptionDisableOverflow { };
#endif

View file

@ -26,10 +26,10 @@ private:
class IteratorBase
{
public:
/// Properties
/// Properties
using difference_type = typename Table::difference_type;
using value_type = typename Table::value_type;
using iterator_category = std::forward_iterator_tag;
using value_type = typename Table::value_type;
using iterator_category = std::forward_iterator_tag;
/// Copy constructor
IteratorBase(const IteratorBase &inRHS) = default;
@ -179,17 +179,9 @@ private:
mSize = inRHS.mSize;
}
/// Grow the table to the next power of 2
void GrowTable()
/// Grow the table to a new size
void GrowTable(size_type inNewMaxSize)
{
// Calculate new size
size_type new_max_size = max<size_type>(mMaxSize << 1, 16);
if (new_max_size < mMaxSize)
{
JPH_ASSERT(false, "Overflow in hash table size, can't grow!");
return;
}
// Move the old table to a temporary structure
size_type old_max_size = mMaxSize;
KeyValue *old_data = mData;
@ -201,7 +193,7 @@ private:
mLoadLeft = 0;
// Allocate new table
AllocateTable(new_max_size);
AllocateTable(inNewMaxSize);
// Reset all control bytes
memset(mControl, cBucketEmpty, mMaxSize + 15);
@ -252,7 +244,16 @@ protected:
if (num_deleted * cMaxDeletedElementsDenominator > mMaxSize * cMaxDeletedElementsNumerator)
rehash(0);
else
GrowTable();
{
// Grow by a power of 2
size_type new_max_size = max<size_type>(mMaxSize << 1, 16);
if (new_max_size < mMaxSize)
{
JPH_ASSERT(false, "Overflow in hash table size, can't grow!");
return false;
}
GrowTable(new_max_size);
}
}
// Split hash into index and control value
@ -363,9 +364,9 @@ public:
using Base = IteratorBase<HashTable, iterator>;
public:
/// Properties
using reference = typename Base::value_type &;
using pointer = typename Base::value_type *;
/// Properties
using reference = typename Base::value_type &;
using pointer = typename Base::value_type *;
/// Constructors
explicit iterator(HashTable *inTable) : Base(inTable) { }
@ -400,9 +401,9 @@ public:
using Base = IteratorBase<const HashTable, const_iterator>;
public:
/// Properties
using reference = const typename Base::value_type &;
using pointer = const typename Base::value_type *;
/// Properties
using reference = const typename Base::value_type &;
using pointer = const typename Base::value_type *;
/// Constructors
explicit const_iterator(const HashTable *inTable) : Base(inTable) { }
@ -489,11 +490,7 @@ public:
if (max_size <= mMaxSize)
return;
// Allocate buffers
AllocateTable(max_size);
// Reset all control bytes
memset(mControl, cBucketEmpty, mMaxSize + 15);
GrowTable(max_size);
}
/// Destroy the entire hash table
@ -523,6 +520,27 @@ public:
}
}
/// Destroy the entire hash table but keeps the memory allocated
void ClearAndKeepMemory()
{
// Destruct elements
if constexpr (!std::is_trivially_destructible<KeyValue>())
if (!empty())
for (size_type i = 0; i < mMaxSize; ++i)
if (mControl[i] & cBucketUsed)
mData[i].~KeyValue();
mSize = 0;
// If there are elements that are not marked cBucketEmpty, we reset them
size_type max_load = sGetMaxLoad(mMaxSize);
if (mLoadLeft != max_load)
{
// Reset all control bytes
memset(mControl, cBucketEmpty, mMaxSize + 15);
mLoadLeft = max_load;
}
}
/// Iterator to first element
iterator begin()
{

View file

@ -222,8 +222,331 @@ void Profiler::DumpChart(const char *inTag, const Threads &inThreads, const KeyT
<html>
<head>
<title>Profile Chart</title>
<link rel="stylesheet" href="WebIncludes/profile_chart.css">
<script type="text/javascript" src="WebIncludes/profile_chart.js"></script>
<style>
html, body {
padding: 0px;
border: 0px;
margin: 0px;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
position: absolute;
top: 10px;
left: 10px;
padding: 0px;
border: 0px;
margin: 0px;
}
#tooltip {
font: Courier New;
position: absolute;
background-color: white;
border: 1px;
border-style: solid;
border-color: black;
pointer-events: none;
padding: 5px;
font: 14px Arial;
visibility: hidden;
height: auto;
}
.stat {
color: blue;
text-align: right;
}
</style>
<script type="text/javascript">
var canvas;
var ctx;
var tooltip;
var min_scale;
var scale;
var offset_x = 0;
var offset_y = 0;
var size_y;
var dragging = false;
var previous_x = 0;
var previous_y = 0;
var bar_height = 15;
var line_height = bar_height + 2;
var thread_separation = 6;
var thread_font_size = 12;
var thread_font = thread_font_size + "px Arial";
var bar_font_size = 10;
var bar_font = bar_font_size + "px Arial";
var end_cycle = 0;
function drawChart()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.lineWidth = 1;
var y = offset_y;
for (var t = 0; t < threads.length; t++)
{
// Check if thread has samples
var thread = threads[t];
if (thread.start.length == 0)
continue;
// Draw thread name
y += thread_font_size;
ctx.font = thread_font;
ctx.fillStyle = "#000000";
ctx.fillText(thread.thread_name, 0, y);
y += thread_separation;
// Draw outlines for each bar of samples
ctx.fillStyle = "#c0c0c0";
for (var d = 0; d <= thread.max_depth; d++)
ctx.fillRect(0, y + d * line_height, canvas.width, bar_height);
// Draw samples
ctx.font = bar_font;
for (var s = 0; s < thread.start.length; s++)
{
// Cull bar
var rx = scale * (offset_x + thread.start[s]);
if (rx > canvas.width) // right of canvas
break;
var rw = scale * thread.cycles[s];
if (rw < 0.5) // less than half pixel, skip
continue;
if (rx + rw < 0) // left of canvas
continue;
// Draw bar
var ry = y + line_height * thread.depth[s];
ctx.fillStyle = thread.color[s];
ctx.fillRect(rx, ry, rw, bar_height);
ctx.strokeStyle = thread.darkened_color[s];
ctx.strokeRect(rx, ry, rw, bar_height);
// Get index in aggregated list
var a = thread.aggregator[s];
// Draw text
if (rw > aggregated.name_width[a])
{
ctx.fillStyle = "#000000";
ctx.fillText(aggregated.name[a], rx + (rw - aggregated.name_width[a]) / 2, ry + bar_height - 4);
}
}
// Next line
y += line_height * (1 + thread.max_depth) + thread_separation;
}
// Update size
size_y = y - offset_y;
}
function drawTooltip(mouse_x, mouse_y)
{
var y = offset_y;
for (var t = 0; t < threads.length; t++)
{
// Check if thread has samples
var thread = threads[t];
if (thread.start.length == 0)
continue;
// Thead name
y += thread_font_size + thread_separation;
// Draw samples
for (var s = 0; s < thread.start.length; s++)
{
// Cull bar
var rx = scale * (offset_x + thread.start[s]);
if (rx > mouse_x)
break;
var rw = scale * thread.cycles[s];
if (rx + rw < mouse_x)
continue;
var ry = y + line_height * thread.depth[s];
if (mouse_y >= ry && mouse_y < ry + bar_height)
{
// Get index into aggregated list
var a = thread.aggregator[s];
// Found bar, fill in tooltip
tooltip.style.left = (canvas.offsetLeft + mouse_x) + "px";
tooltip.style.top = (canvas.offsetTop + mouse_y) + "px";
tooltip.style.visibility = "visible";
tooltip.innerHTML = aggregated.name[a] + "<br>"
+ "<table>"
+ "<tr><td>Time:</td><td class=\"stat\">" + (1000000 * thread.cycles[s] / cycles_per_second).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>Start:</td><td class=\"stat\">" + (1000000 * thread.start[s] / cycles_per_second).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>End:</td><td class=\"stat\">" + (1000000 * (thread.start[s] + thread.cycles[s]) / cycles_per_second).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>Avg. Time:</td><td class=\"stat\">" + (1000000 * aggregated.cycles_per_frame[a] / cycles_per_second / aggregated.calls[a]).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>Min Time:</td><td class=\"stat\">" + (1000000 * aggregated.min_cycles[a] / cycles_per_second).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>Max Time:</td><td class=\"stat\">" + (1000000 * aggregated.max_cycles[a] / cycles_per_second).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>Time / Frame:</td><td class=\"stat\">" + (1000000 * aggregated.cycles_per_frame[a] / cycles_per_second).toFixed(2) + " &micro;s</td></tr>"
+ "<tr><td>Calls:</td><td class=\"stat\">" + aggregated.calls[a] + "</td></tr>"
+ "</table>";
return;
}
}
// Next line
y += line_height * (1 + thread.max_depth) + thread_separation;
}
// No bar found, hide tooltip
tooltip.style.visibility = "hidden";
}
function onMouseDown(evt)
{
dragging = true;
previous_x = evt.clientX, previous_y = evt.clientY;
tooltip.style.visibility = "hidden";
}
function onMouseUp(evt)
{
dragging = false;
}
function clampMotion()
{
// Clamp horizontally
var min_offset_x = canvas.width / scale - end_cycle;
if (offset_x < min_offset_x)
offset_x = min_offset_x;
if (offset_x > 0)
offset_x = 0;
// Clamp vertically
var min_offset_y = canvas.height - size_y;
if (offset_y < min_offset_y)
offset_y = min_offset_y;
if (offset_y > 0)
offset_y = 0;
// Clamp scale
if (scale < min_scale)
scale = min_scale;
var max_scale = 1000 * min_scale;
if (scale > max_scale)
scale = max_scale;
}
function onMouseMove(evt)
{
if (dragging)
{
// Calculate new offset
offset_x += (evt.clientX - previous_x) / scale;
offset_y += evt.clientY - previous_y;
clampMotion();
drawChart();
}
else
drawTooltip(evt.clientX - canvas.offsetLeft, evt.clientY - canvas.offsetTop);
previous_x = evt.clientX, previous_y = evt.clientY;
}
function onScroll(evt)
{
tooltip.style.visibility = "hidden";
var old_scale = scale;
if (evt.deltaY > 0)
scale /= 1.1;
else
scale *= 1.1;
clampMotion();
// Ensure that event under mouse stays under mouse
var x = previous_x - canvas.offsetLeft;
offset_x += x / scale - x / old_scale;
clampMotion();
drawChart();
}
function darkenColor(color)
{
var i = parseInt(color.slice(1), 16);
var r = i >> 16;
var g = (i >> 8) & 0xff;
var b = i & 0xff;
r = Math.round(0.8 * r);
g = Math.round(0.8 * g);
b = Math.round(0.8 * b);
i = (r << 16) + (g << 8) + b;
return "#" + i.toString(16);
}
function startChart()
{
// Fetch elements
canvas = document.getElementById('canvas');
ctx = canvas.getContext("2d");
tooltip = document.getElementById('tooltip');
// Resize canvas to fill screen
canvas.width = document.body.offsetWidth - 20;
canvas.height = document.body.offsetHeight - 20;
// Register mouse handlers
canvas.onmousedown = onMouseDown;
canvas.onmouseup = onMouseUp;
canvas.onmouseout = onMouseUp;
canvas.onmousemove = onMouseMove;
canvas.onwheel = onScroll;
for (var t = 0; t < threads.length; t++)
{
var thread = threads[t];
// Calculate darkened colors
thread.darkened_color = new Array(thread.color.length);
for (var s = 0; s < thread.color.length; s++)
thread.darkened_color[s] = darkenColor(thread.color[s]);
// Calculate max depth and end cycle
thread.max_depth = 0;
for (var s = 0; s < thread.start.length; s++)
{
thread.max_depth = Math.max(thread.max_depth, thread.depth[s]);
end_cycle = Math.max(end_cycle, thread.start[s] + thread.cycles[s]);
}
}
// Calculate width of name strings
ctx.font = bar_font;
aggregated.name_width = new Array(aggregated.name.length);
for (var a = 0; a < aggregated.name.length; a++)
aggregated.name_width[a] = ctx.measureText(aggregated.name[a]).width;
// Store scale properties
min_scale = canvas.width / end_cycle;
scale = min_scale;
drawChart();
}
</script>
</head>
<body onload="startChart();">
<script type="text/javascript">

View file

@ -43,7 +43,8 @@ public:
/// Constructor used when rebinding to another type. This expects the allocator to use the original memory pool from the first allocator,
/// but in our case we cannot use the local buffer of the original allocator as it has different size and alignment rules.
/// To solve this we make this allocator fall back to the heap immediately.
template <class T2> STLLocalAllocator(const STLLocalAllocator<T2, N> &) : mNumElementsUsed(N) { }
template <class T2>
explicit STLLocalAllocator(const STLLocalAllocator<T2, N> &) : mNumElementsUsed(N) { }
/// Check if inPointer is in the local buffer
inline bool is_local(const_pointer inPointer) const

View file

@ -17,7 +17,6 @@
#else
#include <windows.h>
#endif
JPH_SUPPRESS_WARNING_POP
#endif
@ -27,6 +26,31 @@ Semaphore::Semaphore()
{
#ifdef JPH_PLATFORM_WINDOWS
mSemaphore = CreateSemaphore(nullptr, 0, INT_MAX, nullptr);
if (mSemaphore == nullptr)
{
Trace("Failed to create semaphore");
std::abort();
}
#elif defined(JPH_USE_PTHREADS)
int ret = sem_init(&mSemaphore, 0, 0);
if (ret == -1)
{
Trace("Failed to create semaphore");
std::abort();
}
#elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
mSemaphore = dispatch_semaphore_create(0);
if (mSemaphore == nullptr)
{
Trace("Failed to create semaphore");
std::abort();
}
#elif defined(JPH_PLATFORM_BLUE)
if (!JPH_PLATFORM_BLUE_SEMAPHORE_INIT(mSemaphore))
{
Trace("Failed to create semaphore");
std::abort();
}
#endif
}
@ -34,6 +58,12 @@ Semaphore::~Semaphore()
{
#ifdef JPH_PLATFORM_WINDOWS
CloseHandle(mSemaphore);
#elif defined(JPH_USE_PTHREADS)
sem_destroy(&mSemaphore);
#elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
dispatch_release(mSemaphore);
#elif defined(JPH_PLATFORM_BLUE)
JPH_PLATFORM_BLUE_SEMAPHORE_DESTROY(mSemaphore);
#endif
}
@ -41,13 +71,23 @@ void Semaphore::Release(uint inNumber)
{
JPH_ASSERT(inNumber > 0);
#ifdef JPH_PLATFORM_WINDOWS
int old_value = mCount.fetch_add(inNumber);
#if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
int old_value = mCount.fetch_add(inNumber, std::memory_order_release);
if (old_value < 0)
{
int new_value = old_value + (int)inNumber;
int num_to_release = min(new_value, 0) - old_value;
#ifdef JPH_PLATFORM_WINDOWS
::ReleaseSemaphore(mSemaphore, num_to_release, nullptr);
#elif defined(JPH_USE_PTHREADS)
for (int i = 0; i < num_to_release; ++i)
sem_post(&mSemaphore);
#elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
for (int i = 0; i < num_to_release; ++i)
dispatch_semaphore_signal(mSemaphore);
#elif defined(JPH_PLATFORM_BLUE)
JPH_PLATFORM_BLUE_SEMAPHORE_SIGNAL(mSemaphore, num_to_release);
#endif
}
#else
std::lock_guard lock(mLock);
@ -63,19 +103,31 @@ void Semaphore::Acquire(uint inNumber)
{
JPH_ASSERT(inNumber > 0);
#ifdef JPH_PLATFORM_WINDOWS
int old_value = mCount.fetch_sub(inNumber);
#if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
int old_value = mCount.fetch_sub(inNumber, std::memory_order_acquire);
int new_value = old_value - (int)inNumber;
if (new_value < 0)
{
int num_to_acquire = min(old_value, 0) - new_value;
#ifdef JPH_PLATFORM_WINDOWS
for (int i = 0; i < num_to_acquire; ++i)
WaitForSingleObject(mSemaphore, INFINITE);
#elif defined(JPH_USE_PTHREADS)
for (int i = 0; i < num_to_acquire; ++i)
sem_wait(&mSemaphore);
#elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
for (int i = 0; i < num_to_acquire; ++i)
dispatch_semaphore_wait(mSemaphore, DISPATCH_TIME_FOREVER);
#elif defined(JPH_PLATFORM_BLUE)
JPH_PLATFORM_BLUE_SEMAPHORE_WAIT(mSemaphore, num_to_acquire);
#endif
}
#else
std::unique_lock lock(mLock);
mWaitVariable.wait(lock, [this, inNumber]() {
return mCount.load(std::memory_order_relaxed) >= int(inNumber);
});
mCount.fetch_sub(inNumber, std::memory_order_relaxed);
mWaitVariable.wait(lock, [this]() { return mCount >= 0; });
#endif
}

View file

@ -4,47 +4,64 @@
#pragma once
#include <Jolt/Core/Atomics.h>
// Determine which platform specific construct we'll use
JPH_SUPPRESS_WARNINGS_STD_BEGIN
#include <atomic>
#include <mutex>
#include <condition_variable>
#ifdef JPH_PLATFORM_WINDOWS
// We include windows.h in the cpp file, the semaphore itself is a void pointer
#elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_BSD) || defined(JPH_PLATFORM_WASM)
#include <semaphore.h>
#define JPH_USE_PTHREADS
#elif defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS)
#include <dispatch/dispatch.h>
#define JPH_USE_GRAND_CENTRAL_DISPATCH
#elif defined(JPH_PLATFORM_BLUE)
// Jolt/Core/PlatformBlue.h should have defined everything that is needed below
#else
#include <mutex>
#include <condition_variable>
#endif
JPH_SUPPRESS_WARNINGS_STD_END
JPH_NAMESPACE_BEGIN
// Things we're using from STL
using std::atomic;
using std::mutex;
using std::condition_variable;
/// Implements a semaphore
/// When we switch to C++20 we can use counting_semaphore to unify this
class JPH_EXPORT Semaphore
{
public:
/// Constructor
Semaphore();
~Semaphore();
Semaphore();
~Semaphore();
/// Release the semaphore, signaling the thread waiting on the barrier that there may be work
void Release(uint inNumber = 1);
void Release(uint inNumber = 1);
/// Acquire the semaphore inNumber times
void Acquire(uint inNumber = 1);
void Acquire(uint inNumber = 1);
/// Get the current value of the semaphore
inline int GetValue() const { return mCount.load(std::memory_order_relaxed); }
inline int GetValue() const { return mCount.load(std::memory_order_relaxed); }
private:
#if defined(JPH_PLATFORM_WINDOWS) || defined(JPH_USE_PTHREADS) || defined(JPH_USE_GRAND_CENTRAL_DISPATCH) || defined(JPH_PLATFORM_BLUE)
#ifdef JPH_PLATFORM_WINDOWS
// On windows we use a semaphore object since it is more efficient than a lock and a condition variable
alignas(JPH_CACHE_LINE_SIZE) atomic<int> mCount { 0 }; ///< We increment mCount for every release, to acquire we decrement the count. If the count is negative we know that we are waiting on the actual semaphore.
void * mSemaphore; ///< The semaphore is an expensive construct so we only acquire/release it if we know that we need to wait/have waiting threads
using SemaphoreType = void *;
#elif defined(JPH_USE_PTHREADS)
using SemaphoreType = sem_t;
#elif defined(JPH_USE_GRAND_CENTRAL_DISPATCH)
using SemaphoreType = dispatch_semaphore_t;
#elif defined(JPH_PLATFORM_BLUE)
using SemaphoreType = JPH_PLATFORM_BLUE_SEMAPHORE;
#endif
alignas(JPH_CACHE_LINE_SIZE) atomic<int> mCount { 0 }; ///< We increment mCount for every release, to acquire we decrement the count. If the count is negative we know that we are waiting on the actual semaphore.
SemaphoreType mSemaphore { }; ///< The semaphore is an expensive construct so we only acquire/release it if we know that we need to wait/have waiting threads
#else
// Other platforms: Emulate a semaphore using a mutex, condition variable and count
mutex mLock;
condition_variable mWaitVariable;
atomic<int> mCount { 0 };
std::mutex mLock;
std::condition_variable mWaitVariable;
atomic<int> mCount { 0 };
#endif
};

View file

@ -18,7 +18,8 @@ public:
/// Read a string of bytes from the binary stream
virtual void ReadBytes(void *outData, size_t inNumBytes) = 0;
/// Returns true when an attempt has been made to read past the end of the file
/// Returns true when an attempt has been made to read past the end of the file.
/// Note that this follows the convention of std::basic_ios::eof which only returns true when an attempt is made to read past the end, not when the read pointer is at the end.
virtual bool IsEOF() const = 0;
/// Returns true if there was an IO failure

View file

@ -34,7 +34,7 @@ public:
JPH_OVERRIDE_NEW_DELETE
/// Constructs the allocator with a maximum allocatable size of inSize
explicit TempAllocatorImpl(uint inSize) :
explicit TempAllocatorImpl(size_t inSize) :
mBase(static_cast<uint8 *>(AlignedAllocate(inSize, JPH_RVECTOR_ALIGNMENT))),
mSize(inSize)
{
@ -56,10 +56,10 @@ public:
}
else
{
uint new_top = mTop + AlignUp(inSize, JPH_RVECTOR_ALIGNMENT);
size_t new_top = mTop + AlignUp(inSize, JPH_RVECTOR_ALIGNMENT);
if (new_top > mSize)
{
Trace("TempAllocator: Out of memory");
Trace("TempAllocator: Out of memory trying to allocate %u bytes", inSize);
std::abort();
}
void *address = mBase + mTop;
@ -93,13 +93,13 @@ public:
}
/// Get the total size of the fixed buffer
uint GetSize() const
size_t GetSize() const
{
return mSize;
}
/// Get current usage in bytes of the buffer
uint GetUsage() const
size_t GetUsage() const
{
return mTop;
}
@ -118,8 +118,8 @@ public:
private:
uint8 * mBase; ///< Base address of the memory block
uint mSize; ///< Size of the memory block
uint mTop = 0; ///< End of currently allocated area
size_t mSize; ///< Size of the memory block
size_t mTop = 0; ///< End of currently allocated area
};
/// Implementation of the TempAllocator that just falls back to malloc/free