[Bf-blender-cvs] [0ea70ab8e54] soc-2020-io-performance: Add faster fprintf writer, remove unused headers

Ankit Meel noreply at git.blender.org
Thu Jun 11 17:46:38 CEST 2020


Commit: 0ea70ab8e54cf284af12badb4341bd7f31b7fccd
Author: Ankit Meel
Date:   Tue Jun 9 00:20:07 2020 +0530
Branches: soc-2020-io-performance
https://developer.blender.org/rB0ea70ab8e54cf284af12badb4341bd7f31b7fccd

Add faster fprintf writer, remove unused headers

Changes here:

Reverted temporarily to std::vector to keep working, instead of
waiting for D7931 to get committed in master.

Adds an forced inline function for calculation of face/ polygon normals
by averaging vertex normals. I will look for an existing method.
This way, the allocated memory in `data_to_export->mvert[i].no` is
actually used.
Also, `BLI::Vector<uint> face_normal_index` is not needed anymore since
we loop over the same polygon list while writing normals, so
their indices will be the same.

Adds a writer method option, `fprintf`, which is faster than `fstream`.
With fstream, 478 MB of an ico-sphere with 8 subsurf takes 22 seconds.
with fprintf, the same takes 13 seconds.
With fstream, a 44 MB of cube with 8 subsurf take 2.3 seconds.
with fprintf, the same takes 1.4 seconds.

Adds timing info of the full export directly in console.

Removed unused and repeated headers from `wavefront_obj.cc`.

Differential Revision: https://developer.blender.org/D7959

===================================================================

M	source/blender/io/wavefront_obj/IO_wavefront_obj.h
M	source/blender/io/wavefront_obj/intern/wavefront_obj.cc
M	source/blender/io/wavefront_obj/intern/wavefront_obj.hh
M	source/blender/io/wavefront_obj/intern/wavefront_obj_exporter.cc
M	source/blender/io/wavefront_obj/intern/wavefront_obj_file_handler.cc
M	source/blender/io/wavefront_obj/intern/wavefront_obj_file_handler.hh

===================================================================

diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index b2f03c6714a..6af50635565 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -22,7 +22,7 @@
 #define __IO_WAVEFRONT_OBJ_H__
 
 #include "BKE_context.h"
-#include <stdio.h>
+#include <stdio.h> /* For FILENAME_MAX. */
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/source/blender/io/wavefront_obj/intern/wavefront_obj.cc b/source/blender/io/wavefront_obj/intern/wavefront_obj.cc
index 25f56582e68..c26bd020535 100644
--- a/source/blender/io/wavefront_obj/intern/wavefront_obj.cc
+++ b/source/blender/io/wavefront_obj/intern/wavefront_obj.cc
@@ -22,6 +22,7 @@
  */
 
 #include "IO_wavefront_obj.h"
+#include <chrono>
 
 #include "wavefront_obj.hh"
 #include "wavefront_obj_exporter.hh"
@@ -32,7 +33,12 @@
  */
 void OBJ_export(bContext *C, const OBJExportParams *export_params)
 {
+  std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
   io::obj::exporter_main(C, export_params);
+  std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+  std::cout << "-------- \n Time difference = "
+            << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[us]"
+            << std::endl;
 }
 /**
  * Called from io_obj.c. Currently not implemented.
diff --git a/source/blender/io/wavefront_obj/intern/wavefront_obj.hh b/source/blender/io/wavefront_obj/intern/wavefront_obj.hh
index c9be522c189..0ad0279b6c4 100644
--- a/source/blender/io/wavefront_obj/intern/wavefront_obj.hh
+++ b/source/blender/io/wavefront_obj/intern/wavefront_obj.hh
@@ -21,10 +21,15 @@
 #ifndef __WAVEFRONT_OBJ_HH__
 #define __WAVEFRONT_OBJ_HH__
 
+#include <stdio.h>
+
 #include "BKE_context.h"
+#include "BKE_object.h"
 
 #include "BLI_array.hh"
 #include "BLI_vector.hh"
+
+#include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 
 namespace io {
@@ -41,12 +46,7 @@ struct Polygon {
    * Vertex indices of this polygon. v1, v2 .. above.
    * The index corresponds to the pre-defined vertex list.
    */
-  BLI::Vector<uint> vertex_index;
-  /**
-   * Face normal indices of this polygon. vn1, vn2 .. above.
-   * The index corresponds to the pre-defined face normal list.
-   */
-  BLI::Vector<uint> face_normal_index;
+  std::vector<uint> vertex_index;
 };
 
 /**
@@ -56,6 +56,7 @@ struct Polygon {
 struct OBJ_data_to_export {
   bContext *C;
   Depsgraph *depsgraph;
+  Object *ob_eval;
 
   /** Vertices in a mesh to export. */
   MVert *mvert;
@@ -63,9 +64,10 @@ struct OBJ_data_to_export {
   uint tot_vertices;
 
   /** Polygons in a mesh to export. */
-  BLI::Vector<Polygon> polygon_list;
+  /* TODO (ankitm): Replace vector with BLI::Vector. See D7931 */
+  std::vector<Polygon> polygon_list;
   /** Number of polygons in a mesh to export. */
-  uint tot_faces;
+  uint tot_poly;
 };
 }  // namespace obj
 }  // namespace io
diff --git a/source/blender/io/wavefront_obj/intern/wavefront_obj_exporter.cc b/source/blender/io/wavefront_obj/intern/wavefront_obj_exporter.cc
index b985d44bed1..588c8d9d280 100644
--- a/source/blender/io/wavefront_obj/intern/wavefront_obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/intern/wavefront_obj_exporter.cc
@@ -24,24 +24,18 @@
 #include "MEM_guardedalloc.h"
 
 #include <stdio.h>
+#include <vector>
 
-#include "BKE_context.h"
 #include "BKE_mesh.h"
 #include "BKE_mesh_runtime.h"
-#include "BKE_object.h"
 #include "BKE_scene.h"
 
-#include "BLI_iterator.h"
-#include "BLI_linklist.h"
 #include "BLI_math.h"
 #include "BLI_vector.hh"
 
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_query.h"
 
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
 #include "IO_wavefront_obj.h"
 
 #include "wavefront_obj.hh"
@@ -73,39 +67,39 @@ static void get_transformed_mesh_vertices(Mesh *me_eval,
 /**
  * Store the mesh vertex normals in data_to_export, in world coordinates.
  */
-static void get_transformed_vertex_normals(Mesh *me_eval, OBJ_data_to_export *data_to_export)
+static void get_transformed_vertex_normals(Mesh *me_eval,
+                                           Object *ob_eval,
+                                           OBJ_data_to_export *data_to_export)
 {
+  BKE_mesh_ensure_normals(me_eval);
   float transformed_normal[3];
-  const MLoop *mloop;
-  const MPoly *mpoly = me_eval->mpoly;
-  const MVert *mvert = me_eval->mvert;
-
-  for (uint i = 0; i < me_eval->totpoly; i++, mpoly++) {
-    mloop = &me_eval->mloop[mpoly->loopstart];
-    BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, transformed_normal);
+  for (uint i = 0; i < me_eval->totvert; i++) {
+    normal_short_to_float_v3(transformed_normal, me_eval->mvert[i].no);
+    mul_mat3_m4_v3(ob_eval->obmat, transformed_normal);
     normal_float_to_short_v3(data_to_export->mvert[i].no, transformed_normal);
   }
 }
 
 /**
- * Store a polygon's vertex indices and normal indices, indexing into the pre-defined
- * vertex coordinates and vertex normals list.
+ * Store a polygon's vertex indices, indexing into the pre-defined
+ * vertex coordinates list.
  */
 static void get_polygon_vert_indices(Mesh *me_eval, OBJ_data_to_export *data_to_export)
 {
   const MLoop *mloop;
   const MPoly *mpoly = me_eval->mpoly;
 
-  data_to_export->tot_faces = me_eval->totpoly;
-  data_to_export->polygon_list.increase_size_unchecked(me_eval->totpoly);
+  data_to_export->tot_poly = me_eval->totpoly;
+  data_to_export->polygon_list.resize(me_eval->totpoly);
 
   for (uint i = 0; i < me_eval->totpoly; i++, mpoly++) {
     mloop = &me_eval->mloop[mpoly->loopstart];
     data_to_export->polygon_list[i].total_vertices_per_poly = mpoly->totloop;
 
+    data_to_export->polygon_list[i].vertex_index.resize(mpoly->totloop);
+
     for (int j = 0; j < mpoly->totloop; j++) {
-      data_to_export->polygon_list[i].vertex_index.append((mloop + j)->v + 1);
-      data_to_export->polygon_list[i].face_normal_index.append(i + 1);
+      data_to_export->polygon_list[i].vertex_index[j] = (mloop + j)->v + 1;
     }
   }
 }
@@ -115,11 +109,11 @@ static void get_geometry_per_object(const OBJExportParams *export_params,
 {
   Depsgraph *depsgraph = data_to_export->depsgraph;
   Object *ob = CTX_data_active_object(data_to_export->C);
-  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+  Object *ob_eval = data_to_export->ob_eval = DEG_get_evaluated_object(depsgraph, ob);
   Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
 
   get_transformed_mesh_vertices(me_eval, ob_eval, data_to_export);
-  get_transformed_vertex_normals(me_eval, data_to_export);
+  get_transformed_vertex_normals(me_eval, ob_eval, data_to_export);
   get_polygon_vert_indices(me_eval, data_to_export);
 }
 
@@ -135,7 +129,9 @@ void exporter_main(bContext *C, const OBJExportParams *export_params)
 
   get_geometry_per_object(export_params, &data_to_export);
 
+  /* Comment out either one of the following. */
   write_obj_data(filepath, &data_to_export);
+  //  write_obj_data_in_fprintf(filepath, &data_to_export);
   MEM_freeN(data_to_export.mvert);
 }
 }  // namespace obj
diff --git a/source/blender/io/wavefront_obj/intern/wavefront_obj_file_handler.cc b/source/blender/io/wavefront_obj/intern/wavefront_obj_file_handler.cc
index 54cac5a266b..6d4b3be8e32 100644
--- a/source/blender/io/wavefront_obj/intern/wavefront_obj_file_handler.cc
+++ b/source/blender/io/wavefront_obj/intern/wavefront_obj_file_handler.cc
@@ -24,45 +24,117 @@
 #include <fstream>
 #include <iostream>
 
+#include "DNA_object_types.h"
+
 #include "wavefront_obj.hh"
 #include "wavefront_obj_file_handler.hh"
 
 namespace io {
 namespace obj {
 
+/**
+ * Calculate a face normal's axis component by averaging over its vertex normals.
+ */
+MALWAYS_INLINE short face_normal_axis_component(const Polygon &poly_to_write,
+                                                int axis,
+                                                MVert *vertex_list)
+{
+  float sum = 0;
+  for (int i = 0; i < poly_to_write.total_vertices_per_poly; i++) {
+    sum += vertex_list[poly_to_write.vertex_index[i] - 1].no[axis];
+  }
+  return short(sum / poly_to_write.total_vertices_per_poly);
+}
+
 /**
  * Low level writer to the OBJ file at filepath.
- * data_to_export is filled in obj_exporter.cc.
  */
 void write_obj_data(const char *filepath, OBJ_data_to_export *data_to_export)
 {
-  std::ofstream outfile(filepath, std::ios::binary);
+  std::ofstream outfile(filepath, std::ios::binary | std::ios::trunc);
+  if (outfile.is_open() == false) {
+    printf("Error opening file.");
+    return;
+  }
+
   outfile << "# Blender 2.90 \n";
 
+  /** Write object name, as seen in outliner. First two characters are ID code, so skipped. */
+  outfile << "o " << data_to_export->ob_eval->id.name + 2 << "\n";
+
   /** Write v x y z for all vertices. */
   for (int i = 0; i < data_to_export->tot_vertices; i++) {
     MVert *vertex = &data_to_export->mvert[i];
     outfile << "v ";
-    outfile << vertex[i].co[0] << " " << vertex[i].co[1] << " " << vertex[i].co[2] << "\n";
+    outfile << vertex->co[0] << " " << vertex->co[1] << " " << vertex->co[2] << "\n";
   }
 
   /** Write vn nx ny nz for all face normals. */
-  for (int i = 0; i < data_to_export->tot_faces; i++) {
-    MVert *vertex = &data_to_export->mvert[i];
-    outfile << "vn ";
-    outfile << vertex[i].no[0] << " " << vertex[i].no[1] << " " << vertex[i].no[2] << "\n";
+  for (int i = 0; i < data_to_export->tot_poly; i++) {
+    MVert *vertex_list = data_to_export->mvert;
+    const Polygon &polygon = data_to_export->polygon_list[i];
+    outfile << "vn " << face_normal_axis_component(polygon, 0, vertex_list) << " "
+            << face_normal_axis_component(polygon, 1, vertex_list) << " "
+            << face_normal_axis_component(polygon, 2, vertex_list) << "\n";
   }
 
-  /** Write f v1/vt1/vn1 .. total_vertices_per_poly , for all polygons. */
-  for (int i = 0; i < data_to_export->tot_faces; i++) {
+  /**
+   * Write f v1/vt1/vn1 .. total_vertices_per_poly , for all polygons.
+   * i-th vn is always i + 1, guaranteed by face normal loop above.
+   * Both loop over the same polygon list.
+   */
+  for (int i = 0; i < d

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list