Skip to content

Commit

Permalink
Tables: Fixed unaligned accesses when using TableSetBgColor(ImGuiTabl…
Browse files Browse the repository at this point in the history
…eBgTarget_CellBg). (ocornut#3872)

ImSpanAllocator: Support for alignment.
  • Loading branch information
ocornut committed Mar 4, 2021
1 parent 1ddaff8 commit d8c88bd
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 11 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Other Changes:
- Window: Shrink close button hit-testing region when it covers an abnormally high portion of the window visible
area (e.g. when window is collapsed + moved in a corner) to facilitate moving the window away. (#3825)
- Window, Nav: Fixed crash when calling SetWindowFocus(NULL) as the time a new window appears. (#3865) [@nem0]
- Tables: Fixed unaligned accesses when using TableSetBgColor(ImGuiTableBgTarget_CellBg). (#3872)
- Added GetAllocatorFunctions() to facilitate sharing allocators accross DLL boundaries. (#3836)
- ImFontAtlas: Added 'bool TexPixelsUseColors' output to help backend decide of underlying texture format. (#3369)
This can currently only ever be set by the Freetype renderer.
Expand Down
19 changes: 11 additions & 8 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ namespace ImStb
#define IM_NEWLINE "\n"
#endif
#define IM_TABSIZE (4)
#define IM_MEMALIGN(_OFF,_ALIGN) (((_OFF) + (_ALIGN - 1)) & ~(_ALIGN - 1)) // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds
Expand Down Expand Up @@ -545,20 +546,22 @@ struct ImSpan

// Helper: ImSpanAllocator<>
// Facilitate storing multiple chunks into a single large block (the "arena")
// - Usage: call Reserve() N times, allocate GetArenaSizeInBytes() worth, pass it to SetArenaBasePtr(), call GetSpan() N times to retrieve the aligned ranges.
template<int CHUNKS>
struct ImSpanAllocator
{
char* BasePtr;
int TotalSize;
int CurrSpan;
int CurrOff;
int CurrIdx;
int Offsets[CHUNKS];
int Sizes[CHUNKS];

ImSpanAllocator() { memset(this, 0, sizeof(*this)); }
inline void ReserveBytes(int n, size_t sz) { IM_ASSERT(n == CurrSpan && n < CHUNKS); IM_UNUSED(n); Offsets[CurrSpan++] = TotalSize; TotalSize += (int)sz; }
inline int GetArenaSizeInBytes() { return TotalSize; }
inline void Reserve(int n, size_t sz, int a=4) { IM_ASSERT(n == CurrIdx && n < CHUNKS); CurrOff = IM_MEMALIGN(CurrOff, a); Offsets[n] = CurrOff; Sizes[n] = (int)sz; CurrIdx++; CurrOff += (int)sz; }
inline int GetArenaSizeInBytes() { return CurrOff; }
inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; }
inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrSpan == CHUNKS); return (void*)(BasePtr + Offsets[n]); }
inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrSpan == CHUNKS); return (n + 1 < CHUNKS) ? BasePtr + Offsets[n + 1] : (void*)(BasePtr + TotalSize); }
inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n]); }
inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); }
template<typename T>
inline void GetSpan(int n, ImSpan<T>* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); }
};
Expand Down Expand Up @@ -592,7 +595,7 @@ struct IMGUI_API ImPool
// Helper: ImChunkStream<>
// Build and iterate a contiguous stream of variable-sized structures.
// This is used by Settings to store persistent data while reducing allocation count.
// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for)
// We store the chunk size first, and align the final size on 4 bytes boundaries.
// The tedious/zealous amount of casting is to avoid -Wcast-align warnings.
template<typename T>
struct IMGUI_API ImChunkStream
Expand All @@ -602,7 +605,7 @@ struct IMGUI_API ImChunkStream
void clear() { Buf.clear(); }
bool empty() const { return Buf.Size == 0; }
int size() const { return Buf.Size; }
T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); }
T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = IM_MEMALIGN(HDR_SZ + sz, 4u); int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); }
T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); }
T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; }
int chunk_size(const T* p) { return ((const int*)p)[-1]; }
Expand Down
6 changes: 3 additions & 3 deletions imgui_tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,9 @@ void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count)
{
// Allocate single buffer for our arrays
ImSpanAllocator<3> span_allocator;
span_allocator.ReserveBytes(0, columns_count * sizeof(ImGuiTableColumn));
span_allocator.ReserveBytes(1, columns_count * sizeof(ImGuiTableColumnIdx));
span_allocator.ReserveBytes(2, columns_count * sizeof(ImGuiTableCellData));
span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn));
span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx));
span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4);
table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes());
memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes());
span_allocator.SetArenaBasePtr(table->RawData);
Expand Down

0 comments on commit d8c88bd

Please sign in to comment.