BLO: support overaligned types in SDNA
This fixes #121695. `float4x4` matrices are generally expected to be 16 byte aligned. Currently, there is no mechanism (afaik) that allows allocating these overaligned types when loading files from disk. This patch adds an array with alignment information for each type in `SDNA`. Currently, the alignment is just `__STDCPP_DEFAULT_NEW_ALIGNMENT__` for all types and is manually set for the `mat4x4f` DNA type. The .blend file format is not changed at all. The alignment information is purely runtime data. In the future it would probably be good to generalize this a bit more instead of hardcoding the alignment for `mat4x4f`, but would make it unnecessarily complex for now because this is intended for the release branch. Pull Request: https://projects.blender.org/blender/blender/pulls/123271
This commit is contained in:
@@ -2155,6 +2155,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
layerDefault_propquaternion},
|
||||
};
|
||||
|
||||
static_assert(sizeof(mat4x4f) == sizeof(blender::float4x4));
|
||||
|
||||
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
|
||||
/* 0-4 */ "CDMVert",
|
||||
"CDMSticky",
|
||||
|
||||
@@ -1825,7 +1825,8 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
|
||||
}
|
||||
else {
|
||||
/* SDNA_CMP_EQUAL */
|
||||
temp = MEM_mallocN(bh->len, blockname);
|
||||
const int alignment = DNA_struct_alignment(fd->filesdna, bh->SDNAnr);
|
||||
temp = MEM_mallocN_aligned(bh->len, alignment, blockname);
|
||||
#ifdef USE_BHEAD_READ_ON_DEMAND
|
||||
if (BHEADN_FROM_BHEAD(bh)->has_data) {
|
||||
memcpy(temp, (bh + 1), bh->len);
|
||||
|
||||
@@ -190,6 +190,11 @@ int DNA_struct_member_size(const struct SDNA *sdna, short type, short name);
|
||||
*/
|
||||
int DNA_elem_type_size(eSDNA_Type elem_nr);
|
||||
|
||||
/**
|
||||
* Get the alignment that should be used when allocating memory for this type.
|
||||
*/
|
||||
int DNA_struct_alignment(const struct SDNA *sdna, int struct_nr);
|
||||
|
||||
/**
|
||||
* Rename a struct
|
||||
*/
|
||||
|
||||
@@ -80,6 +80,13 @@ typedef struct SDNA {
|
||||
/** A version of #SDNA.structs_map that uses #SDNA.alias.types for its keys. */
|
||||
struct GHash *structs_map;
|
||||
} alias;
|
||||
|
||||
/**
|
||||
* Alignment used when allocating pointers to this type. The actual minimum alignment of the
|
||||
* type may be lower in some cases. For example, the pointer alignment of a single char is at
|
||||
* least 8 bytes, but the alignment of the type itself is 1.
|
||||
*/
|
||||
int *types_alignment;
|
||||
} SDNA;
|
||||
|
||||
#
|
||||
|
||||
@@ -50,6 +50,11 @@ typedef struct vec4f {
|
||||
float x, y, z, w;
|
||||
} vec4f;
|
||||
|
||||
/**
|
||||
* This type generally shouldn't be used. It only exists for cases where a DNA type that
|
||||
* corresponds to `blender:float4x4` is required. Note that `float4x4` is 16 byte aligned, but we
|
||||
* can't enforce that this struct yet.
|
||||
*/
|
||||
typedef struct mat4x4f {
|
||||
float value[4][4];
|
||||
} mat4x4f;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "MEM_guardedalloc.h" /* for MEM_freeN MEM_mallocN MEM_callocN */
|
||||
|
||||
#include "BLI_endian_switch.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
@@ -132,6 +133,7 @@ void DNA_sdna_free(SDNA *sdna)
|
||||
MEM_freeN((void *)sdna->names_array_len);
|
||||
MEM_freeN((void *)sdna->types);
|
||||
MEM_freeN(sdna->structs);
|
||||
MEM_freeN(sdna->types_alignment);
|
||||
|
||||
#ifdef WITH_DNA_GHASH
|
||||
if (sdna->structs_map) {
|
||||
@@ -522,6 +524,19 @@ static bool init_structDNA(SDNA *sdna, bool do_endian_swap, const char **r_error
|
||||
sdna->names_array_len = names_array_len;
|
||||
}
|
||||
|
||||
sdna->types_alignment = static_cast<int *>(
|
||||
MEM_malloc_arrayN(sdna->types_len, sizeof(int), __func__));
|
||||
for (int i = 0; i < sdna->types_len; i++) {
|
||||
sdna->types_alignment[i] = int(__STDCPP_DEFAULT_NEW_ALIGNMENT__);
|
||||
}
|
||||
{
|
||||
uint dummy_index = 0;
|
||||
/* TODO: This should be generalized at some point. We should be able to specify overaligned
|
||||
* types directly in the DNA struct definitions. */
|
||||
sdna->types_alignment[DNA_struct_find_without_alias_ex(sdna, "mat4x4f", &dummy_index)] =
|
||||
alignof(blender::float4x4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1265,7 +1280,9 @@ void *DNA_struct_reconstruct(const DNA_ReconstructInfo *reconstruct_info,
|
||||
const SDNA_Struct *new_struct = newsdna->structs[new_struct_nr];
|
||||
const int new_block_size = newsdna->types_size[new_struct->type];
|
||||
|
||||
char *new_blocks = static_cast<char *>(MEM_callocN(blocks * new_block_size, "reconstruct"));
|
||||
const int alignment = DNA_struct_alignment(newsdna, new_struct_nr);
|
||||
char *new_blocks = static_cast<char *>(
|
||||
MEM_calloc_arrayN_aligned(new_block_size, blocks, alignment, "reconstruct"));
|
||||
reconstruct_structs(reconstruct_info,
|
||||
blocks,
|
||||
old_struct_nr,
|
||||
@@ -1697,6 +1714,11 @@ int DNA_elem_type_size(const eSDNA_Type elem_nr)
|
||||
return 8;
|
||||
}
|
||||
|
||||
int DNA_struct_alignment(const SDNA *sdna, const int struct_nr)
|
||||
{
|
||||
return sdna->types_alignment[struct_nr];
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Version Patch DNA
|
||||
* \{ */
|
||||
|
||||
Reference in New Issue
Block a user