BMesh: add mesh debug information printing

- Add BM_mesh_debug_print & BM_mesh_debug_info.
- Report flags in Mesh.cd_flag in BKE_mesh_debug_print
- Move custom data printing into customdata.cc (noted as a TODO).

Note that the term "runtime" has been removed from
`BKE_mesh_runtime_debug_print` since these are useful for debugging any
kind of mesh data.
This commit is contained in:
Campbell Barton 2022-01-19 15:09:48 +11:00
parent 71879d665d
commit eb63646605
12 changed files with 287 additions and 125 deletions

View File

@ -747,6 +747,14 @@ void CustomData_blend_write(struct BlendWriter *writer,
struct ID *id);
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
#ifndef NDEBUG
struct DynStr;
/** Use to inspect mesh data when debugging. */
void CustomData_debug_info_from_layers(const struct CustomData *data,
const char *indent,
struct DynStr *dynstr);
#endif /* NDEBUG */
#ifdef __cplusplus
}
#endif

View File

@ -23,6 +23,7 @@
*/
#include "BKE_mesh_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
struct BLI_Stack;
@ -1038,6 +1039,13 @@ void BKE_mesh_batch_cache_free(struct Mesh *me);
extern void (*BKE_mesh_batch_cache_dirty_tag_cb)(struct Mesh *me, eMeshBatchDirtyMode mode);
extern void (*BKE_mesh_batch_cache_free_cb)(struct Mesh *me);
/* mesh_debug.c */
#ifndef NDEBUG
char *BKE_mesh_debug_info(const struct Mesh *me)
ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
#endif
/* Inlines */
/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,

View File

@ -116,10 +116,6 @@ void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed,
struct KeyBlock *kb);
#ifndef NDEBUG
char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval);
void BKE_mesh_runtime_debug_print(struct Mesh *me_eval);
/* XXX Should go in customdata file? */
void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data);
bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval);
#endif /* NDEBUG */

View File

@ -197,6 +197,7 @@ set(SRC
intern/mesh.cc
intern/mesh_boolean_convert.cc
intern/mesh_convert.cc
intern/mesh_debug.cc
intern/mesh_evaluate.cc
intern/mesh_fair.cc
intern/mesh_iterators.c

View File

@ -44,6 +44,10 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#ifndef NDEBUG
# include "BLI_dynstr.h"
#endif
#include "BLT_translation.h"
#include "BKE_anonymous_attribute.h"
@ -5188,3 +5192,33 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
CustomData_update_typemap(data);
}
#ifndef NDEBUG
void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
{
for (int type = 0; type < CD_NUMTYPES; type++) {
if (CustomData_has_layer(data, type)) {
/* NOTE: doesn't account for multiple layers. */
const char *name = CustomData_layertype_name(type);
const int size = CustomData_sizeof(type);
const void *pt = CustomData_get_layer(data, type);
const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
const char *structname;
int structnum;
CustomData_file_write_info(type, &structname, &structnum);
BLI_dynstr_appendf(
dynstr,
"%sdict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
indent,
name,
structname,
type,
(const void *)pt,
size,
pt_size);
}
}
}
#endif /* NDEBUG */

View File

@ -0,0 +1,115 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Evaluated mesh info printing function, to help track down differences output.
*
* Output from these functions can be evaluated as Python literals.
* See `bmesh_debug.c` for the equivalent #BMesh functionality.
*/
#ifndef NDEBUG
# include <stdio.h>
# include "MEM_guardedalloc.h"
# include "DNA_mesh_types.h"
# include "DNA_meshdata_types.h"
# include "DNA_object_types.h"
# include "BLI_utildefines.h"
# include "BKE_customdata.h"
# include "BKE_mesh.h"
# include "BLI_dynstr.h"
static void mesh_debug_info_from_cd_flag(const Mesh *me, DynStr *dynstr)
{
BLI_dynstr_append(dynstr, "'cd_flag': {");
if (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
BLI_dynstr_append(dynstr, "'VERT_BWEIGHT', ");
}
if (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
BLI_dynstr_append(dynstr, "'EDGE_BWEIGHT', ");
}
if (me->cd_flag & ME_CDFLAG_EDGE_CREASE) {
BLI_dynstr_append(dynstr, "'EDGE_CREASE', ");
}
BLI_dynstr_append(dynstr, "},\n");
}
char *BKE_mesh_debug_info(const Mesh *me)
{
DynStr *dynstr = BLI_dynstr_new();
char *ret;
const char *indent4 = " ";
const char *indent8 = " ";
BLI_dynstr_append(dynstr, "{\n");
BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me);
BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me->totvert);
BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me->totedge);
BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me->totface);
BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly);
BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only);
BLI_dynstr_appendf(dynstr, " 'runtime.is_original': %d,\n", me->runtime.is_original);
BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'edge_layers': (\n");
CustomData_debug_info_from_layers(&me->edata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'loop_layers': (\n");
CustomData_debug_info_from_layers(&me->ldata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'poly_layers': (\n");
CustomData_debug_info_from_layers(&me->pdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'tessface_layers': (\n");
CustomData_debug_info_from_layers(&me->fdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, indent4);
mesh_debug_info_from_cd_flag(me, dynstr);
BLI_dynstr_append(dynstr, "}\n");
ret = BLI_dynstr_get_cstring(dynstr);
BLI_dynstr_free(dynstr);
return ret;
}
void BKE_mesh_debug_print(const Mesh *me)
{
char *str = BKE_mesh_debug_info(me);
puts(str);
fflush(stdout);
MEM_freeN(str);
}
#endif /* NDEBUG */

View File

@ -298,129 +298,10 @@ void BKE_mesh_batch_cache_free(Mesh *me)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Runtime Debug Helpers
/** \name Mesh Runtime Validation
* \{ */
/* Evaluated mesh info printing function, to help track down differences output. */
#ifndef NDEBUG
# include "BLI_dynstr.h"
static void mesh_runtime_debug_info_layers(DynStr *dynstr, CustomData *cd)
{
int type;
for (type = 0; type < CD_NUMTYPES; type++) {
if (CustomData_has_layer(cd, type)) {
/* NOTE: doesn't account for multiple layers. */
const char *name = CustomData_layertype_name(type);
const int size = CustomData_sizeof(type);
const void *pt = CustomData_get_layer(cd, type);
const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
const char *structname;
int structnum;
CustomData_file_write_info(type, &structname, &structnum);
BLI_dynstr_appendf(
dynstr,
" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
name,
structname,
type,
(const void *)pt,
size,
pt_size);
}
}
}
char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
{
DynStr *dynstr = BLI_dynstr_new();
char *ret;
BLI_dynstr_append(dynstr, "{\n");
BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
# if 0
const char *tstr;
switch (me_eval->type) {
case DM_TYPE_CDDM:
tstr = "DM_TYPE_CDDM";
break;
case DM_TYPE_CCGDM:
tstr = "DM_TYPE_CCGDM";
break;
default:
tstr = "UNKNOWN";
break;
}
BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
# endif
BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, "}\n");
ret = BLI_dynstr_get_cstring(dynstr);
BLI_dynstr_free(dynstr);
return ret;
}
void BKE_mesh_runtime_debug_print(Mesh *me_eval)
{
char *str = BKE_mesh_runtime_debug_info(me_eval);
puts(str);
fflush(stdout);
MEM_freeN(str);
}
void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
{
int i;
const CustomDataLayer *layer;
printf("{\n");
for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
const char *name = CustomData_layertype_name(layer->type);
const int size = CustomData_sizeof(layer->type);
const char *structname;
int structnum;
CustomData_file_write_info(layer->type, &structname, &structnum);
printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
name,
structname,
layer->type,
(const void *)layer->data,
size,
(int)(MEM_allocN_len(layer->data) / size));
}
printf("}\n");
}
bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
{

View File

@ -100,6 +100,8 @@ set(SRC
intern/bmesh_mesh.h
intern/bmesh_mesh_convert.c
intern/bmesh_mesh_convert.h
intern/bmesh_mesh_debug.c
intern/bmesh_mesh_debug.h
intern/bmesh_mesh_duplicate.c
intern/bmesh_mesh_duplicate.h
intern/bmesh_mesh_normals.c

View File

@ -214,6 +214,7 @@ extern "C" {
#include "intern/bmesh_marking.h"
#include "intern/bmesh_mesh.h"
#include "intern/bmesh_mesh_convert.h"
#include "intern/bmesh_mesh_debug.h"
#include "intern/bmesh_mesh_duplicate.h"
#include "intern/bmesh_mesh_normals.h"
#include "intern/bmesh_mesh_partial_update.h"

View File

@ -0,0 +1,86 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Evaluated mesh info printing function, to help track down differences output.
*
* Output from these functions can be evaluated as Python literals.
* See `mesh_debug.cc` for the equivalent #Mesh functionality.
*/
#ifndef NDEBUG
# include <stdio.h>
# include "MEM_guardedalloc.h"
# include "BLI_utildefines.h"
# include "BKE_customdata.h"
# include "bmesh.h"
# include "bmesh_mesh_debug.h"
# include "BLI_dynstr.h"
char *BM_mesh_debug_info(BMesh *bm)
{
DynStr *dynstr = BLI_dynstr_new();
char *ret;
const char *indent8 = " ";
BLI_dynstr_append(dynstr, "{\n");
BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)bm);
BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", bm->totvert);
BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", bm->totedge);
BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", bm->totface);
BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
CustomData_debug_info_from_layers(&bm->vdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'edge_layers': (\n");
CustomData_debug_info_from_layers(&bm->edata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'loop_layers': (\n");
CustomData_debug_info_from_layers(&bm->ldata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, " 'poly_layers': (\n");
CustomData_debug_info_from_layers(&bm->pdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
BLI_dynstr_append(dynstr, "}\n");
ret = BLI_dynstr_get_cstring(dynstr);
BLI_dynstr_free(dynstr);
return ret;
}
void BM_mesh_debug_print(BMesh *bm)
{
char *str = BM_mesh_debug_info(bm);
puts(str);
fflush(stdout);
MEM_freeN(str);
}
#endif /* NDEBUG */

View File

@ -0,0 +1,30 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup bmesh
*/
#include "BLI_compiler_attrs.h"
#include "bmesh.h"
#ifndef NDEBUG
char *BM_mesh_debug_info(BMesh *bm) ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BM_mesh_debug_print(BMesh *bm) ATTR_NONNULL(1);
#endif /* NDEBUG */

View File

@ -729,7 +729,7 @@ void rna_Object_me_eval_info(
}
if (me_eval) {
ret = BKE_mesh_runtime_debug_info(me_eval);
ret = BKE_mesh_debug_info(me_eval);
if (ret) {
strcpy(result, ret);
MEM_freeN(ret);