Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKévin Dietrich <kevin.dietrich@mailoo.org>2022-05-22 10:19:55 +0300
committerKévin Dietrich <kevin.dietrich@mailoo.org>2022-05-22 10:19:55 +0300
commit9d9f2f1a0356d2049ea2ce4820c61fdebbdf50ca (patch)
tree402d7a7e1bda5a9516e43e09f5e9b8ba8a6205ff /source/blender
parent45ed325443a3a3afb57da25ad01d636a94bf6cee (diff)
GPU subdiv: smoothly interpolate orco layer
This uses the recently introduced evaluator's vertex data to smoothly interpolate original coordinates instead of using linear interpolation. The orcos are interpolated at the same time as positions and as such, the specific subdivision routine for the orco extractor has been removed. The patch evaluation shader uses a definition to enable code specific to orco evaluation. Since the orco layer may not have been requested on first render, and since orco data is now stored in the OpenSubDiv evaluator, the evaluator needs to be recreated if an orco layer is suddenly available. For this, a callback to check if the evaluator has the data was added. This is added to the evaluator as the `Subdiv` cache stored in the modifier is invalidated less often than the Mesh batch cache and so leads to fewer evaluator recreations. Differential Revision: https://developer.blender.org/D14999
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc8
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc55
-rw-r--r--source/blender/draw/intern/draw_subdivision.h4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc67
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc18
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl56
7 files changed, 133 insertions, 77 deletions
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index ec544d8e786..3d44d3d1b3f 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -793,7 +793,12 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/* The order in which extractors are added to the list matters somewhat, as some buffers are
* reused when building others. */
EXTRACT_ADD_REQUESTED(ibo, tris);
- EXTRACT_ADD_REQUESTED(vbo, pos_nor);
+
+ /* Orcos are extracted at the same time as positions. */
+ if (DRW_vbo_requested(mbuflist->vbo.pos_nor) || DRW_vbo_requested(mbuflist->vbo.orco)) {
+ extractors.append(&extract_pos_nor);
+ }
+
EXTRACT_ADD_REQUESTED(vbo, lnor);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
@@ -843,7 +848,6 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
- EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, vcol);
EXTRACT_ADD_REQUESTED(vbo, weights);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index cfdf059ca37..dc40e15a450 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -69,6 +69,7 @@ enum {
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_ORCO,
SHADER_COMP_CUSTOM_DATA_INTERP_1D,
SHADER_COMP_CUSTOM_DATA_INTERP_2D,
SHADER_COMP_CUSTOM_DATA_INTERP_3D,
@@ -107,7 +108,8 @@ static const char *get_shader_code(int shader_type)
}
case SHADER_PATCH_EVALUATION:
case SHADER_PATCH_EVALUATION_FVAR:
- case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ case SHADER_PATCH_EVALUATION_FACE_DOTS:
+ case SHADER_PATCH_EVALUATION_ORCO: {
return datatoc_common_subdiv_patch_evaluation_comp_glsl;
}
case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
@@ -163,6 +165,9 @@ static const char *get_shader_name(int shader_type)
case SHADER_PATCH_EVALUATION_FACE_DOTS: {
return "subdiv patch evaluation face dots";
}
+ case SHADER_PATCH_EVALUATION_ORCO: {
+ return "subdiv patch evaluation orco";
+ }
case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
return "subdiv custom data interp 1D";
}
@@ -206,6 +211,12 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define FDOTS_EVALUATION\n";
}
+ else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define ORCO_EVALUATION\n";
+ }
else {
defines =
"#define OSD_PATCH_BASIS_GLSL\n"
@@ -236,7 +247,8 @@ static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
if (ELEM(shader_type,
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
- SHADER_PATCH_EVALUATION_FACE_DOTS)) {
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_ORCO)) {
return get_patch_evaluation_shader(shader_type);
}
if (g_subdiv_shaders[shader_type] == nullptr) {
@@ -710,6 +722,23 @@ static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
return subdiv_cache;
}
+static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, Mesh *mesh)
+{
+ const bool has_orco = CustomData_has_layer(&mesh->vdata, CD_ORCO);
+ if (has_orco && subdiv->evaluator && !subdiv->evaluator->hasVertexData(subdiv->evaluator)) {
+ /* If we suddenly have/need original coordinates, recreate the evaluator if the extra
+ * source was not created yet. The refiner also has to be recreated as refinement for source
+ * and vertex data is done only once. */
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ subdiv->evaluator = nullptr;
+
+ if (subdiv->topology_refiner != nullptr) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ subdiv->topology_refiner = nullptr;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1230,7 +1259,9 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
}
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *orco)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
@@ -1245,6 +1276,14 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_subdiv_vertex_format());
evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+ GPUVertBuf *src_extra_buffer = nullptr;
+ if (orco) {
+ OpenSubdiv_Buffer src_extra_buffer_interface;
+ src_extra_buffer = create_buffer_and_interface(&src_extra_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcVertexDataBuffer(evaluator, &src_extra_buffer_interface);
+ }
+
OpenSubdiv_Buffer patch_arrays_buffer_interface;
GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
get_patch_array_format());
@@ -1260,7 +1299,8 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
- GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION);
+ GPUShader *shader = get_patch_evaluation_shader(orco ? SHADER_PATCH_EVALUATION_ORCO :
+ SHADER_PATCH_EVALUATION);
GPU_shader_bind(shader);
int binding_point = 0;
@@ -1273,6 +1313,10 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ if (orco) {
+ GPU_vertbuf_bind_as_ssbo(src_extra_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(orco, binding_point++);
+ }
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1289,6 +1333,7 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_discard(patch_param_buffer);
GPU_vertbuf_discard(patch_arrays_buffer);
GPU_vertbuf_discard(src_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(src_extra_buffer);
}
void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
@@ -1935,6 +1980,8 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
return false;
}
+ draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval);
+
if (!BKE_subdiv_eval_begin_from_mesh(
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
/* This could happen in two situations:
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 2d24d07e037..7bddd000ecb 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -235,7 +235,9 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor);
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, struct GPUVertBuf *pos_nor);
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *orco);
void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
struct GPUVertBuf *src_data,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index 14f61dcd739..fb4b95885fc 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -236,7 +236,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdi
draw_subdiv_get_pos_nor_format(),
subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
- draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor);
+ draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor, nullptr);
}
/* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
index b45a73a27c0..94674a54f12 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
@@ -7,8 +7,6 @@
#include "extract_mesh.h"
-#include "draw_subdivision.h"
-
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -79,77 +77,12 @@ static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_orco_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buffer,
- void *UNUSED(data))
-{
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
- * attributes. This is a substantial waste of video-ram and should be done another way.
- * Unfortunately, at the time of writing, I did not found any other "non disruptive"
- * alternative. */
- GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
-
- GPUVertBuf *coarse_vbo = GPU_vertbuf_calloc();
- /* Dynamic as we upload and interpolate layers one at a time. */
- GPU_vertbuf_init_with_format_ex(coarse_vbo, &format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(coarse_vbo, mr->loop_len);
-
- float(*coarse_vbo_data)[4] = static_cast<float(*)[4]>(GPU_vertbuf_get_data(coarse_vbo));
-
- CustomData *cd_vdata = &mr->me->vdata;
- const float(*orco)[3] = static_cast<const float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
-
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const MLoop *mloop = mr->mloop;
- const MPoly *mp = mr->mpoly;
-
- int ml_index = 0;
- for (int i = 0; i < mr->poly_len; i++, mp++) {
- const MLoop *ml = &mloop[mp->loopstart];
-
- for (int j = 0; j < mp->totloop; j++, ml++, ml_index++) {
- float *loop_orco = coarse_vbo_data[ml_index];
- copy_v3_v3(loop_orco, orco[ml->v]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- }
- }
- }
- else {
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter;
- BMLoop *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- const int l_index = BM_elem_index_get(l_iter);
- float *loop_orco = coarse_vbo_data[l_index];
- copy_v3_v3(loop_orco, orco[BM_elem_index_get(l_iter->v)]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
-
- draw_subdiv_interp_custom_data(subdiv_cache, coarse_vbo, dst_buffer, 4, 0, false);
-
- GPU_vertbuf_discard(coarse_vbo);
-}
-
constexpr MeshExtract create_extractor_orco()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_orco_init;
extractor.iter_poly_bm = extract_orco_iter_poly_bm;
extractor.iter_poly_mesh = extract_orco_iter_poly_mesh;
- extractor.init_subdiv = extract_orco_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_Orco_Data);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index c8c91d45542..f80b33e28f2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -201,7 +201,7 @@ static GPUVertFormat *get_custom_normals_format()
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -216,7 +216,21 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
- draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
+ GPUVertBuf *orco_vbo = cache->final.buff.vbo.orco;
+
+ if (orco_vbo) {
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
+ * attributes. This is a substantial waste of video-ram and should be done another way.
+ * Unfortunately, at the time of writing, I did not found any other "non disruptive"
+ * alternative. */
+ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(orco_vbo, &format, subdiv_cache->num_subdiv_loops);
+ }
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, orco_vbo);
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
index 65cf4ebb90f..bf1f0f95787 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -89,6 +89,16 @@ layout(std430, binding = 8) writeonly buffer outputVertexData
{
PosNorLoop output_verts[];
};
+# if defined(ORCO_EVALUATION)
+layout(std430, binding = 9) buffer src_extra_buffer
+{
+ float srcExtraVertexBuffer[];
+};
+layout(std430, binding = 10) writeonly buffer outputOrcoData
+{
+ vec4 output_orcos[];
+};
+# endif
#endif
vec2 read_vec2(int index)
@@ -108,6 +118,17 @@ vec3 read_vec3(int index)
return result;
}
+#if defined(ORCO_EVALUATION)
+vec3 read_vec3_extra(int index)
+{
+ vec3 result;
+ result.x = srcExtraVertexBuffer[index * 3];
+ result.y = srcExtraVertexBuffer[index * 3 + 1];
+ result.z = srcExtraVertexBuffer[index * 3 + 2];
+ return result;
+}
+#endif
+
OsdPatchArray GetPatchArray(int arrayIndex)
{
return patchArrayBuffer[arrayIndex];
@@ -290,6 +311,31 @@ void evaluate_patches_limits(
dv += src_vertex * wDv[cv];
}
}
+
+# if defined(ORCO_EVALUATION)
+/* Evaluate the patches limits from the extra source vertex buffer. */
+void evaluate_patches_limits_extra(int patch_index, float u, float v, inout vec3 dst)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec3 src_vertex = read_vec3_extra(index);
+
+ dst += src_vertex * wP[cv];
+ }
+}
+# endif
#endif
/* ------------------------------------------------------------------------------
@@ -407,6 +453,16 @@ void main()
set_vertex_pos(vertex_data, pos);
set_vertex_nor(vertex_data, nor, flag);
output_verts[loop_index] = vertex_data;
+
+# if defined(ORCO_EVALUATION)
+ pos = vec3(0.0);
+ evaluate_patches_limits_extra(patch_co.patch_index, uv.x, uv.y, pos);
+
+ /* Set w = 0.0 to indicate that this is not a generic attribute.
+ * See comments in `extract_mesh_vbo_orco.cc`. */
+ vec4 orco_data = vec4(pos, 0.0);
+ output_orcos[loop_index] = orco_data;
+# endif
}
}
#endif