From eed45d2a239a2a18a2420ba15dfb55e0f8dc5630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Mon, 27 Dec 2021 16:34:47 +0100 Subject: OpenSubDiv: add support for an OpenGL evaluator This evaluator is used in order to evaluate subdivision at render time, allowing for faster renders of meshes with a subdivision surface modifier placed at the last position in the modifier list. When evaluating the subsurf modifier, we detect whether we can delegate evaluation to the draw code. If so, the subdivision is first evaluated on the GPU using our own custom evaluator (only the coarse data needs to be initially sent to the GPU), then, buffers for the final `MeshBufferCache` are filled on the GPU using a set of compute shaders. However, some buffers are still filled on the CPU side, if doing so on the GPU is impractical (e.g. the line adjacency buffer used for x-ray, whose logic is hardly GPU compatible). This is done at the mesh buffer extraction level so that the result can be readily used in the various OpenGL engines, without having to write custom geometry or tesselation shaders. We use our own subdivision evaluation shaders, instead of OpenSubDiv's vanilla one, in order to control the data layout, and interpolation. For example, we store vertex colors as compressed 16-bit integers, while OpenSubDiv's default evaluator only work for float types. In order to still access the modified geometry on the CPU side, for use in modifiers or transform operators, a dedicated wrapper type is added `MESH_WRAPPER_TYPE_SUBD`. Subdivision will be lazily evaluated via `BKE_object_get_evaluated_mesh` which will create such a wrapper if possible. If the final subdivision surface is not needed on the CPU side, `BKE_object_get_evaluated_mesh_no_subsurf` should be used. Enabling or disabling GPU subdivision can be done through the user preferences (under Viewport -> Subdivision). See patch description for benchmarks. Reviewed By: campbellbarton, jbakker, fclem, brecht, #eevee_viewport Differential Revision: https://developer.blender.org/D12406 --- source/blender/blenkernel/BKE_subdiv_eval.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/BKE_subdiv_eval.h') diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index 0b61e62c89c..177d5f386a8 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -31,15 +31,25 @@ extern "C" { struct Mesh; struct Subdiv; +struct OpenSubdiv_EvaluatorCache; + +typedef enum eSubdivEvaluatorType { + SUBDIV_EVALUATOR_TYPE_CPU, + SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, +} eSubdivEvaluatorType; /* Returns true if evaluator is ready for use. */ -bool BKE_subdiv_eval_begin(struct Subdiv *subdiv); +bool BKE_subdiv_eval_begin(struct Subdiv *subdiv, + eSubdivEvaluatorType evaluator_type, + struct OpenSubdiv_EvaluatorCache *evaluator_cache); /* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse * mesh. */ bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh, - const float (*coarse_vertex_cos)[3]); + const float (*coarse_vertex_cos)[3], + eSubdivEvaluatorType evaluator_type, + struct OpenSubdiv_EvaluatorCache *evaluator_cache); bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh, const float (*coarse_vertex_cos)[3]); -- cgit v1.2.3 From 3d3bc748849834ef74563deb603ab43859cffeeb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 7 Jan 2022 11:38:08 +1100 Subject: Cleanup: remove redundant const qualifiers for POD types MSVC used to warn about const mismatch for arguments passed by value. Remove these as newer versions of MSVC no longer show this warning. --- source/blender/blenkernel/BKE_subdiv_eval.h | 88 +++++++++++++---------------- 1 file changed, 40 insertions(+), 48 deletions(-) (limited to 'source/blender/blenkernel/BKE_subdiv_eval.h') diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index 177d5f386a8..052d25693c4 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -65,33 +65,25 @@ void BKE_subdiv_eval_init_displacement(struct Subdiv *subdiv); /* Evaluate point at a limit surface, with optional derivatives and normal. */ void BKE_subdiv_eval_limit_point( - struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]); + struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]); void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv, - const int ptex_face_index, - const float u, - const float v, + int ptex_face_index, + float u, + float v, float r_P[3], float r_dPdu[3], float r_dPdv[3]); -void BKE_subdiv_eval_limit_point_and_normal(struct Subdiv *subdiv, - const int ptex_face_index, - const float u, - const float v, - float r_P[3], - float r_N[3]); -void BKE_subdiv_eval_limit_point_and_short_normal(struct Subdiv *subdiv, - const int ptex_face_index, - const float u, - const float v, - float r_P[3], - short r_N[3]); +void BKE_subdiv_eval_limit_point_and_normal( + struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]); +void BKE_subdiv_eval_limit_point_and_short_normal( + struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], short r_N[3]); /* Evaluate face-varying layer (such as UV). */ void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv, - const int face_varying_channel, - const int ptex_face_index, - const float u, - const float v, + int face_varying_channel, + int ptex_face_index, + float u, + float v, float r_face_varying[2]); /* NOTE: Expects derivatives to be correct. @@ -101,16 +93,16 @@ void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv, * Would be nice to have displacement evaluation function which does not require * knowing derivatives ahead of a time. */ void BKE_subdiv_eval_displacement(struct Subdiv *subdiv, - const int ptex_face_index, - const float u, - const float v, + int ptex_face_index, + float u, + float v, const float dPdu[3], const float dPdv[3], float r_D[3]); /* Evaluate point on a limit surface with displacement applied to it. */ void BKE_subdiv_eval_final_point( - struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]); + struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]); /* Patch queries at given resolution. * @@ -119,41 +111,41 @@ void BKE_subdiv_eval_final_point( * goes as u in rows, v in columns. */ void BKE_subdiv_eval_limit_patch_resolution_point(struct Subdiv *subdiv, - const int ptex_face_index, - const int resolution, + int ptex_face_index, + int resolution, void *buffer, - const int offset, - const int stride); + int offset, + int stride); void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(struct Subdiv *subdiv, - const int ptex_face_index, - const int resolution, + int ptex_face_index, + int resolution, void *point_buffer, - const int point_offset, - const int point_stride, + int point_offset, + int point_stride, void *du_buffer, - const int du_offset, - const int du_stride, + int du_offset, + int du_stride, void *dv_buffer, - const int dv_offset, - const int dv_stride); + int dv_offset, + int dv_stride); void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(struct Subdiv *subdiv, - const int ptex_face_index, - const int resolution, + int ptex_face_index, + int resolution, void *point_buffer, - const int point_offset, - const int point_stride, + int point_offset, + int point_stride, void *normal_buffer, - const int normal_offset, - const int normal_stride); + int normal_offset, + int normal_stride); void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(struct Subdiv *subdiv, - const int ptex_face_index, - const int resolution, + int ptex_face_index, + int resolution, void *point_buffer, - const int point_offset, - const int point_stride, + int point_offset, + int point_stride, void *normal_buffer, - const int normal_offset, - const int normal_stride); + int normal_offset, + int normal_stride); #ifdef __cplusplus } -- cgit v1.2.3 From cfa53e0fbeed7178c7876413e2010fd3347d7f72 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 13 Jan 2022 14:37:58 -0600 Subject: Refactor: Move normals out of MVert, lazy calculation As described in T91186, this commit moves mesh vertex normals into a contiguous array of float vectors in a custom data layer, how face normals are currently stored. The main interface is documented in `BKE_mesh.h`. Vertex and face normals are now calculated on-demand and cached, retrieved with an "ensure" function. Since the logical state of a mesh is now "has normals when necessary", they can be retrieved from a `const` mesh. The goal is to use on-demand calculation for all derived data, but leave room for eager calculation for performance purposes (modifier evaluation is threaded, but viewport data generation is not). **Benefits** This moves us closer to a SoA approach rather than the current AoS paradigm. Accessing a contiguous `float3` is much more efficient than retrieving data from a larger struct. The memory requirements for accessing only normals or vertex locations are smaller, and at the cost of more memory usage for just normals, they now don't have to be converted between float and short, which also simplifies code In the future, the remaining items can be removed from `MVert`, leaving only `float3`, which has similar benefits (see T93602). Removing the combination of derived and original data makes it conceptually simpler to only calculate normals when necessary. This is especially important now that we have more opportunities for temporary meshes in geometry nodes. **Performance** In addition to the theoretical future performance improvements by making `MVert == float3`, I've done some basic performance testing on this patch directly. The data is fairly rough, but it gives an idea about where things stand generally. - Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms), showing that accessing just `MVert` is now more efficient. - Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight change that at least shows there is no regression. - Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small but observable speedup. - Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms), shows that using normals in geometry nodes is faster. - Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms), shows that calculating normals is slightly faster now. - File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB), Normals are not saved in files, which can help with large meshes. As for memory usage, it may be slightly more in some cases, but I didn't observe any difference in the production files I tested. **Tests** Some modifiers and cycles test results need to be updated with this commit, for two reasons: - The subdivision surface modifier is not responsible for calculating normals anymore. In master, the modifier creates different normals than the result of the `Mesh` normal calculation, so this is a bug fix. - There are small differences in the results of some modifiers that use normals because they are not converted to and from `short` anymore. **Future improvements** - Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier already retrieves normals if they are needed anyway. - Copy normals as part of a better CoW system for attributes. - Make more areas use lazy instead of eager normal calculation. - Remove `BKE_mesh_normals_tag_dirty` in more places since that is now the default state of a new mesh. - Possibly apply a similar change to derived face corner normals. Differential Revision: https://developer.blender.org/D12770 --- source/blender/blenkernel/BKE_subdiv_eval.h | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'source/blender/blenkernel/BKE_subdiv_eval.h') diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index 052d25693c4..eeb80898148 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -75,8 +75,6 @@ void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv, float r_dPdv[3]); void BKE_subdiv_eval_limit_point_and_normal( struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]); -void BKE_subdiv_eval_limit_point_and_short_normal( - struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], short r_N[3]); /* Evaluate face-varying layer (such as UV). */ void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv, @@ -137,15 +135,6 @@ void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(struct Subdiv *subd void *normal_buffer, int normal_offset, int normal_stride); -void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(struct Subdiv *subdiv, - int ptex_face_index, - int resolution, - void *point_buffer, - int point_offset, - int point_stride, - void *normal_buffer, - int normal_offset, - int normal_stride); #ifdef __cplusplus } -- cgit v1.2.3 From b7a27efd781b909536ad6f6ade6b7a9d5f746eb9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 14 Jan 2022 14:04:24 -0600 Subject: Cleanup: Remove unused subdiv functions I noticed these when doing final cleanup on rBcfa53e0fbeed. One use was removed in that commit, the others were unused going further back a few years. Differential Revision: https://developer.blender.org/D13834 --- source/blender/blenkernel/BKE_subdiv_eval.h | 34 ----------------------------- 1 file changed, 34 deletions(-) (limited to 'source/blender/blenkernel/BKE_subdiv_eval.h') diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index eeb80898148..2eb64ae795d 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -102,40 +102,6 @@ void BKE_subdiv_eval_displacement(struct Subdiv *subdiv, void BKE_subdiv_eval_final_point( struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]); -/* Patch queries at given resolution. - * - * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid - * of given resolution, producing resolution^2 evaluation points. The order - * goes as u in rows, v in columns. */ - -void BKE_subdiv_eval_limit_patch_resolution_point(struct Subdiv *subdiv, - int ptex_face_index, - int resolution, - void *buffer, - int offset, - int stride); -void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(struct Subdiv *subdiv, - int ptex_face_index, - int resolution, - void *point_buffer, - int point_offset, - int point_stride, - void *du_buffer, - int du_offset, - int du_stride, - void *dv_buffer, - int dv_offset, - int dv_stride); -void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(struct Subdiv *subdiv, - int ptex_face_index, - int resolution, - void *point_buffer, - int point_offset, - int point_stride, - void *normal_buffer, - int normal_offset, - int normal_stride); - #ifdef __cplusplus } #endif -- cgit v1.2.3 From 4b1f243e4d76dc9b3e92a8c2bf43414bcda4b2c3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 24 Jan 2022 21:16:06 +1100 Subject: Cleanup: sort struct forward declarations --- source/blender/blenkernel/BKE_subdiv_eval.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/BKE_subdiv_eval.h') diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index 2eb64ae795d..23bcdcce276 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -30,8 +30,8 @@ extern "C" { #endif struct Mesh; -struct Subdiv; struct OpenSubdiv_EvaluatorCache; +struct Subdiv; typedef enum eSubdivEvaluatorType { SUBDIV_EVALUATOR_TYPE_CPU, -- cgit v1.2.3