Tables: Fixed unaligned accesses when using TableSetBgColor(ImGuiTableBgTarget_CellBg). (#3872)

ImSpanAllocator: Support for alignment.
This commit is contained in:
ocornut 2021-03-04 09:52:00 +01:00
parent 1ddaff83d8
commit d8c88bd943
3 changed files with 15 additions and 11 deletions

View File

@ -51,6 +51,7 @@ Other Changes:
- Window: Shrink close button hit-testing region when it covers an abnormally high portion of the window visible - 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) 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] - 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) - Added GetAllocatorFunctions() to facilitate sharing allocators accross DLL boundaries. (#3836)
- ImFontAtlas: Added 'bool TexPixelsUseColors' output to help backend decide of underlying texture format. (#3369) - 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. This can currently only ever be set by the Freetype renderer.

View File

@ -214,6 +214,7 @@ namespace ImStb
#define IM_NEWLINE "\n" #define IM_NEWLINE "\n"
#endif #endif
#define IM_TABSIZE (4) #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_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_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 #define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds
@ -545,20 +546,22 @@ struct ImSpan
// Helper: ImSpanAllocator<> // Helper: ImSpanAllocator<>
// Facilitate storing multiple chunks into a single large block (the "arena") // 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> template<int CHUNKS>
struct ImSpanAllocator struct ImSpanAllocator
{ {
char* BasePtr; char* BasePtr;
int TotalSize; int CurrOff;
int CurrSpan; int CurrIdx;
int Offsets[CHUNKS]; int Offsets[CHUNKS];
int Sizes[CHUNKS];
ImSpanAllocator() { memset(this, 0, sizeof(*this)); } 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 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 TotalSize; } inline int GetArenaSizeInBytes() { return CurrOff; }
inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; } 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* 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 && CurrSpan == CHUNKS); return (n + 1 < CHUNKS) ? BasePtr + Offsets[n + 1] : (void*)(BasePtr + TotalSize); } inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); }
template<typename T> template<typename T>
inline void GetSpan(int n, ImSpan<T>* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } inline void GetSpan(int n, ImSpan<T>* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); }
}; };
@ -592,7 +595,7 @@ struct IMGUI_API ImPool
// Helper: ImChunkStream<> // Helper: ImChunkStream<>
// Build and iterate a contiguous stream of variable-sized structures. // Build and iterate a contiguous stream of variable-sized structures.
// This is used by Settings to store persistent data while reducing allocation count. // 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. // The tedious/zealous amount of casting is to avoid -Wcast-align warnings.
template<typename T> template<typename T>
struct IMGUI_API ImChunkStream struct IMGUI_API ImChunkStream
@ -602,7 +605,7 @@ struct IMGUI_API ImChunkStream
void clear() { Buf.clear(); } void clear() { Buf.clear(); }
bool empty() const { return Buf.Size == 0; } bool empty() const { return Buf.Size == 0; }
int size() const { return Buf.Size; } 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* 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; } 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]; } int chunk_size(const T* p) { return ((const int*)p)[-1]; }

View File

@ -538,9 +538,9 @@ void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count)
{ {
// Allocate single buffer for our arrays // Allocate single buffer for our arrays
ImSpanAllocator<3> span_allocator; ImSpanAllocator<3> span_allocator;
span_allocator.ReserveBytes(0, columns_count * sizeof(ImGuiTableColumn)); span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn));
span_allocator.ReserveBytes(1, columns_count * sizeof(ImGuiTableColumnIdx)); span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx));
span_allocator.ReserveBytes(2, columns_count * sizeof(ImGuiTableCellData)); span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4);
table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes());
memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes());
span_allocator.SetArenaBasePtr(table->RawData); span_allocator.SetArenaBasePtr(table->RawData);