diff options
Diffstat (limited to 'source/blender/draw/intern/draw_curves.cc')
-rw-r--r-- | source/blender/draw/intern/draw_curves.cc | 218 |
1 files changed, 183 insertions, 35 deletions
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc index 2edf596ac63..d90c63b680e 100644 --- a/source/blender/draw/intern/draw_curves.cc +++ b/source/blender/draw/intern/draw_curves.cc @@ -10,6 +10,7 @@ #include "BLI_string_utils.h" #include "BLI_utildefines.h" +#include "DNA_curves_types.h" #include "DNA_customdata_types.h" #include "GPU_batch.h" @@ -20,9 +21,13 @@ #include "GPU_texture.h" #include "GPU_vertex_buffer.h" +#include "DRW_gpu_wrapper.hh" #include "DRW_render.h" +#include "draw_cache_impl.h" +#include "draw_curves_private.h" #include "draw_hair_private.h" +#include "draw_manager.h" #include "draw_shader.h" #ifndef __APPLE__ @@ -61,16 +66,43 @@ static GPUVertBuf *g_dummy_vbo = nullptr; static GPUTexture *g_dummy_texture = nullptr; static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */ +using CurvesInfosBuf = blender::draw::UniformBuffer<CurvesInfos>; + +struct CurvesUniformBufPool { + blender::Vector<std::unique_ptr<CurvesInfosBuf>> ubos; + int used = 0; + + void reset() + { + used = 0; + } + + CurvesInfosBuf &alloc() + { + if (used >= ubos.size()) { + ubos.append(std::make_unique<CurvesInfosBuf>()); + return *ubos.last().get(); + } + return *ubos[used++].get(); + } +}; + static GPUShader *curves_eval_shader_get(CurvesEvalShader type) { return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get()); } -void DRW_curves_init(void) +void DRW_curves_init(DRWData *drw_data) { /* Initialize legacy hair too, to avoid verbosity in callers. */ DRW_hair_init(); + if (drw_data->curves_ubos == nullptr) { + drw_data->curves_ubos = MEM_new<CurvesUniformBufPool>("CurvesUniformBufPool"); + } + CurvesUniformBufPool *pool = drw_data->curves_ubos; + pool->reset(); + #if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS) g_tf_pass = DRW_pass_create("Update Curves Pass", (DRWState)0); #else @@ -94,63 +126,120 @@ void DRW_curves_init(void) } } +void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool) +{ + MEM_delete(pool); +} + static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp, CurvesEvalCache *cache, + GPUTexture *tex, const int subdiv) { - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex); + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", tex); DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex); DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1); } +static void drw_curves_cache_update_compute(CurvesEvalCache *cache, + const int subdiv, + const int strands_len, + GPUVertBuf *buffer, + GPUTexture *tex) +{ + GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM); + DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass); + drw_curves_cache_shgrp_attach_resources(shgrp, cache, tex, subdiv); + DRW_shgroup_vertex_buffer(shgrp, "posTime", buffer); + + const int max_strands_per_call = GPU_max_work_group_count(0); + int strands_start = 0; + while (strands_start < strands_len) { + int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call); + DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp); + DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start); + DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1); + strands_start += batch_strands_len; + } +} + static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv) { const int strands_len = cache->strands_len; const int final_points_len = cache->final[subdiv].strands_res * strands_len; - if (final_points_len > 0) { - GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM); - DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass); - drw_curves_cache_shgrp_attach_resources(shgrp, cache, subdiv); - DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf); - - const int max_strands_per_call = GPU_max_work_group_count(0); - int strands_start = 0; - while (strands_start < strands_len) { - int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call); - DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp); - DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start); - DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1); - strands_start += batch_strands_len; + if (final_points_len == 0) { + return; + } + + drw_curves_cache_update_compute( + cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->point_tex); + + const DRW_Attributes &attrs = cache->final[subdiv].attr_used; + for (int i = 0; i < attrs.num_requests; i++) { + /* Only refine point attributes. */ + if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) { + continue; } + + drw_curves_cache_update_compute(cache, + subdiv, + strands_len, + cache->final[subdiv].attributes_buf[i], + cache->proc_attributes_tex[i]); } } -static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv) +static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, + GPUVertBuf *vbo, + GPUTexture *tex, + const int subdiv, + const int final_points_len) { - const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; - if (final_points_len > 0) { - GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM); + GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM); #ifdef USE_TRANSFORM_FEEDBACK - DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create( - tf_shader, g_tf_pass, cache->final[subdiv].proc_buf); + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, vbo); #else - DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); - - CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__); - pr_call->next = g_tf_calls; - pr_call->vbo = cache->final[subdiv].proc_buf; - pr_call->shgrp = tf_shgrp; - pr_call->vert_len = final_points_len; - g_tf_calls = pr_call; - DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); - DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); - DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); + DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass); + + CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__); + pr_call->next = g_tf_calls; + pr_call->vbo = vbo; + pr_call->shgrp = tf_shgrp; + pr_call->vert_len = final_points_len; + g_tf_calls = pr_call; + DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1); + DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1); + DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1); #endif - drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv); - DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len); + drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, tex, subdiv); + DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len); +} + +static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv) +{ + const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len; + if (final_points_len == 0) { + return; + } + + drw_curves_cache_update_transform_feedback( + cache, cache->final[subdiv].proc_buf, cache->point_tex, subdiv, final_points_len); + + const DRW_Attributes &attrs = cache->final[subdiv].attr_used; + for (int i = 0; i < attrs.num_requests; i++) { + /* Only refine point attributes. */ + if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) { + continue; + } + + drw_curves_cache_update_transform_feedback(cache, + cache->final[subdiv].attributes_buf[i], + cache->proc_attributes_tex[i], + subdiv, + final_points_len); } } @@ -186,12 +275,34 @@ GPUVertBuf *DRW_curves_pos_buffer_get(Object *object) return cache->final[subdiv].proc_buf; } +static int attribute_index_in_material(GPUMaterial *gpu_material, const char *name) +{ + if (!gpu_material) { + return -1; + } + + int index = 0; + + ListBase gpu_attrs = GPU_material_attributes(gpu_material); + LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) { + if (STREQ(gpu_attr->name, name)) { + return index; + } + + index++; + } + + return -1; +} + DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, DRWShadingGroup *shgrp_parent, GPUMaterial *gpu_material) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; + CurvesUniformBufPool *pool = DST.vmempool->curves_ubos; + CurvesInfosBuf &curves_infos = pool->alloc(); int subdiv = scene->r.hair_subdiv; int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; @@ -218,6 +329,43 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object, if (curves_cache->length_tex) { DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex); } + + const DRW_Attributes &attrs = curves_cache->final[subdiv].attr_used; + for (int i = 0; i < attrs.num_requests; i++) { + const DRW_AttributeRequest &request = attrs.requests[i]; + + char sampler_name[32]; + drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name); + + if (request.domain == ATTR_DOMAIN_CURVE) { + if (!curves_cache->proc_attributes_tex[i]) { + continue; + } + + DRW_shgroup_uniform_texture(shgrp, sampler_name, curves_cache->proc_attributes_tex[i]); + } + else { + if (!curves_cache->final[subdiv].attributes_tex[i]) { + continue; + } + DRW_shgroup_uniform_texture( + shgrp, sampler_name, curves_cache->final[subdiv].attributes_tex[i]); + } + + /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so + * we need to find the right index for this attribute as uniforms defining the scope of the + * attributes are based on attribute loading order, which is itself based on the material's + * attributes. */ + const int index = attribute_index_in_material(gpu_material, request.attribute_name); + if (index != -1) { + curves_infos.is_point_attribute[index] = request.domain == ATTR_DOMAIN_POINT; + } + } + + curves_infos.push_update(); + + DRW_shgroup_uniform_block(shgrp, "drw_curves", curves_infos); + DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1); DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res); DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape); |