diff options
Diffstat (limited to 'source/blender/draw/intern/draw_cache_impl_particles.c')
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_particles.c | 119 |
1 files changed, 63 insertions, 56 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index dee7a8cec37..8facea4333f 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -11,6 +11,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_alloca.h" #include "BLI_ghash.h" #include "BLI_math_vector.h" #include "BLI_string.h" @@ -31,6 +32,8 @@ #include "ED_particle.h" #include "GPU_batch.h" +#include "GPU_capabilities.h" +#include "GPU_context.h" #include "GPU_material.h" #include "DEG_depsgraph_query.h" @@ -170,25 +173,21 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) /* TODO: more granular update tagging. */ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_length_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); - DRW_TEXTURE_FREE_SAFE(hair_cache->length_tex); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_seg_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex); for (int i = 0; i < MAX_MTFACE; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]); DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]); } - for (int i = 0; i < MAX_MCOL; i++) { + for (int i = 0; i < hair_cache->num_col_layers; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]); DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]); } + for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); for (int j = 0; j < MAX_THICKRES; j++) { GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); } @@ -218,9 +217,24 @@ static void particle_batch_cache_clear(ParticleSystem *psys) GPU_VERTBUF_DISCARD_SAFE(cache->edit_tip_pos); } +static void particle_batch_cache_free_hair(ParticleHairCache *hair) +{ + MEM_SAFE_FREE(hair->proc_col_buf); + MEM_SAFE_FREE(hair->col_tex); + MEM_SAFE_FREE(hair->col_layer_names); +} + void DRW_particle_batch_cache_free(ParticleSystem *psys) { particle_batch_cache_clear(psys); + + ParticleBatchCache *cache = psys->batch_cache; + + if (cache) { + particle_batch_cache_free_hair(&cache->hair); + particle_batch_cache_free_hair(&cache->edit_hair); + } + MEM_SAFE_FREE(psys->batch_cache); } @@ -296,7 +310,8 @@ static void particle_calculate_parent_uvs(ParticleSystem *psys, } } if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { - MFace *mface = &psmd->mesh_final->mface[num]; + MFace *mfaces = CustomData_get_layer(&psmd->mesh_final->fdata, CD_MFACE); + MFace *mface = &mfaces[num]; for (int j = 0; j < num_uv_layers; j++) { psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]); } @@ -325,7 +340,8 @@ static void particle_calculate_parent_mcol(ParticleSystem *psys, } } if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { - MFace *mface = &psmd->mesh_final->mface[num]; + MFace *mfaces = CustomData_get_layer(&psmd->mesh_final->fdata, CD_MFACE); + MFace *mface = &mfaces[num]; for (int j = 0; j < num_col_layers; j++) { /* CustomDataLayer CD_MCOL has 4 structs per face. */ psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]); @@ -351,7 +367,8 @@ static void particle_interpolate_children_uvs(ParticleSystem *psys, ChildParticle *particle = &psys->child[child_index]; int num = particle->num; if (num != DMCACHE_NOTFOUND) { - MFace *mface = &psmd->mesh_final->mface[num]; + MFace *mfaces = CustomData_get_layer(&psmd->mesh_final->fdata, CD_MFACE); + MFace *mface = &mfaces[num]; for (int j = 0; j < num_uv_layers; j++) { psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]); } @@ -375,7 +392,8 @@ static void particle_interpolate_children_mcol(ParticleSystem *psys, ChildParticle *particle = &psys->child[child_index]; int num = particle->num; if (num != DMCACHE_NOTFOUND) { - MFace *mface = &psmd->mesh_final->mface[num]; + MFace *mfaces = CustomData_get_layer(&psmd->mesh_final->fdata, CD_MFACE); + MFace *mface = &mfaces[num]; for (int j = 0; j < num_col_layers; j++) { /* CustomDataLayer CD_MCOL has 4 structs per face. */ psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]); @@ -787,22 +805,19 @@ static int particle_batch_cache_fill_strands_data(ParticleSystem *psys, static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv) { - /* Same format as point_tex. */ + /* Same format as proc_point_buf. */ GPUVertFormat format = {0}; GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format(&format); + /* Transform feedback buffer only needs to be resident in device memory. */ + GPUUsageType type = GPU_transform_feedback_support() ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_STATIC; + cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format_ex( + &format, type | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); /* Create a destination buffer for the transform feedback. Sized appropriately */ /* Those are points! not line segments. */ GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf, cache->final[subdiv].strands_res * cache->strands_len); - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->final[subdiv].proc_buf); - - cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("part_proc", - cache->final[subdiv].proc_buf); } static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit, @@ -833,10 +848,10 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit GPUVertBufRaw data_step, seg_step; GPUVertBufRaw uv_step[MAX_MTFACE]; - GPUVertBufRaw col_step[MAX_MCOL]; + GPUVertBufRaw *col_step = BLI_array_alloca(col_step, cache->num_col_layers); const MTFace *mtfaces[MAX_MTFACE] = {NULL}; - const MCol *mcols[MAX_MCOL] = {NULL}; + const MCol **mcols = BLI_array_alloca(mcols, cache->num_col_layers); float(**parent_uvs)[2] = NULL; MCol **parent_mcol = NULL; @@ -854,20 +869,22 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit &format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names)); - memset(cache->col_layer_names, 0, sizeof(cache->col_layer_names)); /* Strand Data */ - cache->proc_strand_buf = GPU_vertbuf_create_with_format(&format_data); + cache->proc_strand_buf = GPU_vertbuf_create_with_format_ex( + &format_data, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache->proc_strand_buf, cache->strands_len); GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step); - cache->proc_strand_seg_buf = GPU_vertbuf_create_with_format(&format_seg); + cache->proc_strand_seg_buf = GPU_vertbuf_create_with_format_ex( + &format_seg, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache->proc_strand_seg_buf, cache->strands_len); GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step); /* UV layers */ for (int i = 0; i < cache->num_uv_layers; i++) { - cache->proc_uv_buf[i] = GPU_vertbuf_create_with_format(&format_uv); + cache->proc_uv_buf[i] = GPU_vertbuf_create_with_format_ex( + &format_uv, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache->proc_uv_buf[i], cache->strands_len); GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]); @@ -885,9 +902,20 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit BLI_strncpy(cache->uv_layer_names[i][n++], "a", MAX_LAYER_NAME_LEN); } } + + MEM_SAFE_FREE(cache->proc_col_buf); + MEM_SAFE_FREE(cache->col_tex); + MEM_SAFE_FREE(cache->col_layer_names); + + cache->proc_col_buf = MEM_calloc_arrayN(cache->num_col_layers, sizeof(void *), "proc_col_buf"); + cache->col_tex = MEM_calloc_arrayN(cache->num_col_layers, sizeof(void *), "col_tex"); + cache->col_layer_names = MEM_calloc_arrayN( + cache->num_col_layers, sizeof(*cache->col_layer_names), "col_layer_names"); + /* Vertex colors */ for (int i = 0; i < cache->num_col_layers; i++) { - cache->proc_col_buf[i] = GPU_vertbuf_create_with_format(&format_col); + cache->proc_col_buf[i] = GPU_vertbuf_create_with_format_ex( + &format_col, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache->proc_col_buf[i], cache->strands_len); GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]); @@ -995,14 +1023,6 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit MEM_freeN(parent_mcol); } - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_strand_buf); - cache->strand_tex = GPU_texture_create_from_vertbuf("part_strand", cache->proc_strand_buf); - - GPU_vertbuf_use(cache->proc_strand_seg_buf); - cache->strand_seg_tex = GPU_texture_create_from_vertbuf("part_strand_seg", - cache->proc_strand_seg_buf); - for (int i = 0; i < cache->num_uv_layers; i++) { GPU_vertbuf_use(cache->proc_uv_buf[i]); cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]); @@ -1033,8 +1053,9 @@ static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, static GPUVertFormat format = {0}; GPU_vertformat_clear(&format); - /* initialize vertex format */ - GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + /* NOTE: initialize vertex format. Using GPU_COMP_U32 to satisfy Metal's 4-byte minimum + * stride requirement. */ + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U32, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(vbo, 1); @@ -1067,7 +1088,7 @@ static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, - GPUMaterial *gpu_material) + GPUMaterial *UNUSED(gpu_material)) { if (cache->proc_point_buf == NULL) { /* initialize vertex format */ @@ -1075,7 +1096,8 @@ static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, uint pos_id = GPU_vertformat_attr_add( &pos_format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - cache->proc_point_buf = GPU_vertbuf_create_with_format(&pos_format); + cache->proc_point_buf = GPU_vertbuf_create_with_format_ex( + &pos_format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len); GPUVertBufRaw pos_step; @@ -1085,7 +1107,8 @@ static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, uint length_id = GPU_vertformat_attr_add( &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - cache->proc_length_buf = GPU_vertbuf_create_with_format(&length_format); + cache->proc_length_buf = GPU_vertbuf_create_with_format_ex( + &length_format, GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); GPU_vertbuf_data_alloc(cache->proc_length_buf, cache->strands_len); GPUVertBufRaw length_step; @@ -1107,22 +1130,6 @@ static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, psys->childcache, child_count, &pos_step, &length_step); } } - - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_point_buf); - cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf); - } - - /* Checking hair length separately, only allocating gpu memory when needed. */ - if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex == NULL) { - ListBase gpu_attrs = GPU_material_attributes(gpu_material); - LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { - if (attr->type == CD_HAIRLENGTH) { - GPU_vertbuf_use(cache->proc_length_buf); - cache->length_tex = GPU_texture_create_from_vertbuf("hair_length", cache->proc_length_buf); - break; - } - } } } @@ -1680,7 +1687,7 @@ bool particles_ensure_procedural_data(Object *object, /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == NULL || - (gpu_material && (*r_hair_cache)->length_tex == NULL)) { + (gpu_material && (*r_hair_cache)->proc_length_buf == NULL)) { ensure_seg_pt_count(source.edit, source.psys, &cache->hair); particle_batch_cache_ensure_procedural_pos( source.edit, source.psys, &cache->hair, gpu_material); @@ -1688,7 +1695,7 @@ bool particles_ensure_procedural_data(Object *object, } /* Refreshed if active layer or custom data changes. */ - if ((*r_hair_cache)->strand_tex == NULL) { + if ((*r_hair_cache)->proc_strand_buf == NULL) { particle_batch_cache_ensure_procedural_strand_data( source.edit, source.psys, source.md, &cache->hair); } |