diff options
Diffstat (limited to 'source/blender/draw')
42 files changed, 1065 insertions, 582 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 6d3c203b076..8c54c923476 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -82,6 +82,7 @@ set(SRC intern/draw_cache_impl_volume.c intern/draw_color_management.cc intern/draw_common.c + intern/draw_curves.cc intern/draw_debug.c intern/draw_fluid.c intern/draw_hair.c @@ -98,6 +99,7 @@ set(SRC intern/draw_texture_pool.cc intern/draw_view.c intern/draw_view_data.cc + intern/draw_volume.cc intern/smaa_textures.c engines/basic/basic_engine.c engines/basic/basic_shader.c @@ -194,6 +196,7 @@ set(SRC intern/draw_color_management.h intern/draw_common.h intern/draw_common_shader_shared.h + intern/draw_curves_private.h intern/draw_debug.h intern/draw_hair_private.h intern/draw_instance_data.h diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 81edee17c76..47e8f234a01 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -353,8 +353,6 @@ static void eevee_draw_scene(void *vedata) EEVEE_renderpasses_draw_debug(vedata); - EEVEE_volumes_free_smoke_textures(); - stl->g_data->view_updated = false; DRW_view_set_active(NULL); @@ -574,7 +572,6 @@ static void eevee_render_to_image(void *vedata, } } - EEVEE_volumes_free_smoke_textures(); EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur); if (RE_engine_test_break(engine)) { diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 2e1b92de068..4f562dd9804 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -965,7 +965,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb txl->color = NULL; DRW_render_instance_buffer_finish(); - DRW_hair_update(); + DRW_curves_update(); } static void eevee_lightbake_copy_irradiance(EEVEE_LightBake *lbake, LightCache *lcache) @@ -1463,9 +1463,6 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float } eevee_lightbake_delete_resources(lbake); - - /* Free GPU smoke textures and the smoke domain list correctly: See also T73921. */ - EEVEE_volumes_free_smoke_textures(); } void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata, diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index e3342508a14..2e0937dbe49 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -440,9 +440,9 @@ void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata) DRW_render_instance_buffer_finish(); /* Need to be called after #DRW_render_instance_buffer_finish() */ - /* Also we weed to have a correct FBO bound for #DRW_hair_update. */ + /* Also we weed to have a correct FBO bound for #DRW_curves_update. */ GPU_framebuffer_bind(vedata->fbl->main_fb); - DRW_hair_update(); + DRW_curves_update(); DRW_cache_restart(); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 9f97dacf9fe..ee336326166 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -1558,7 +1558,6 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_resolve(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_volumes_free_smoke_textures(void); void EEVEE_volumes_free(void); /* eevee_effects.c */ diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 47e2b95f367..bef19c589c2 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -538,9 +538,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl DRW_render_instance_buffer_finish(); /* Need to be called after DRW_render_instance_buffer_finish() */ - /* Also we weed to have a correct FBO bound for DRW_hair_update */ + /* Also we weed to have a correct FBO bound for DRW_curves_update */ GPU_framebuffer_bind(fbl->main_fb); - DRW_hair_update(); + DRW_curves_update(); /* Sort transparents before the loop. */ DRW_pass_sort_shgroup_z(psl->transparent_pass); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 4e4a2a9eb8e..85cc7f65126 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -1487,6 +1487,10 @@ struct GPUMaterial *EEVEE_material_get( GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred); int status = GPU_material_status(mat); + /* Return null material and bypass drawing for volume shaders. */ + if ((options & VAR_MAT_VOLUME) && status != GPU_MAT_SUCCESS) { + return NULL; + } switch (status) { case GPU_MAT_SUCCESS: break; diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc index bb1a0b0abe4..05577944140 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc +++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc @@ -81,7 +81,7 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat, const bool do_fragment_attrib_load = is_background || is_volume; if (is_hair && !info.vertex_out_interfaces_.is_empty()) { - /** Hair attributes comme from sampler buffer. Transfer attributes to sampler. */ + /** Hair attributes come from sampler buffer. Transfer attributes to sampler. */ for (auto &input : info.vertex_inputs_) { info.sampler(0, ImageType::FLOAT_BUFFER, input.name, Frequency::BATCH); } @@ -97,12 +97,26 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat, } attr_load << "};\n"; attr_load << iface.name << " " << iface.instance_name << ";\n"; - /* Global vars just to make code valid. Only Orco is supported. */ - for (const ShaderCreateInfo::VertIn &in : info.vertex_inputs_) { - attr_load << in.type << " " << in.name << ";\n"; + if (!is_volume) { + /* Global vars just to make code valid. Only Orco is supported. */ + for (const ShaderCreateInfo::VertIn &in : info.vertex_inputs_) { + attr_load << in.type << " " << in.name << ";\n"; + } } info.vertex_out_interfaces_.clear(); } + if (is_volume) { + /** Volume grid attributes come from 3D textures. Transfer attributes to samplers. */ + for (auto &input : info.vertex_inputs_) { + info.sampler(0, ImageType::FLOAT_3D, input.name, Frequency::BATCH); + } + info.additional_info("draw_volume_infos"); + /* Do not add twice. */ + if (!GPU_material_flag_get(gpumat, GPU_MATFLAG_OBJECT_INFO)) { + info.additional_info("draw_object_infos"); + } + info.vertex_inputs_.clear(); + } if (!is_volume) { info.define("EEVEE_GENERATED_INTERFACE"); @@ -137,7 +151,7 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat, } frag_gen << "Closure nodetree_exec()\n"; frag_gen << "{\n"; - if (GPU_material_is_volume_shader(gpumat)) { + if (is_volume) { frag_gen << ((codegen.volume) ? codegen.volume : "return CLOSURE_DEFAULT;\n"); } else { diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 6a0c9fb36df..b8bef61f8b1 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -43,35 +43,8 @@ static struct { GPUTexture *dummy_scatter; GPUTexture *dummy_transmit; - - /* List of all fluid simulation / smoke domains rendered within this frame. */ - ListBase smoke_domains; } e_data = {NULL}; /* Engine data */ -static void eevee_create_textures_volumes(void) -{ - const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - e_data.dummy_zero = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, zero); - - const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - e_data.dummy_one = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, one); - - const float flame = 0.0f; - e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame); -} - -static GPUTexture *eevee_volume_default_texture(eGPUVolumeDefaultValue default_value) -{ - switch (default_value) { - case GPU_VOLUME_DEFAULT_0: - return e_data.dummy_zero; - case GPU_VOLUME_DEFAULT_1: - return e_data.dummy_one; - } - - return e_data.dummy_zero; -} - void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; @@ -227,11 +200,6 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) Scene *scene = draw_ctx->scene; DRWShadingGroup *grp = NULL; - /* Textures */ - if (!e_data.dummy_zero) { - eevee_create_textures_volumes(); - } - /* Quick breakdown of the Volumetric rendering: * * The rendering is separated in 4 stages: @@ -268,7 +236,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_MAT_VOLUME); - if (GPU_material_has_volume_output(mat)) { + if (mat && GPU_material_has_volume_output(mat)) { grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps); } @@ -283,11 +251,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); /* Fix principle volumetric not working with world materials. */ - ListBase gpu_grids = GPU_material_volume_grids(mat); - LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, &gpu_grids) { - DRW_shgroup_uniform_texture( - grp, gpu_grid->sampler_name, eevee_volume_default_texture(gpu_grid->default_value)); - } + grp = DRW_shgroup_volume_create_sub(NULL, NULL, grp, mat); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -299,187 +263,17 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* If no world or volume material is present just clear the buffer with this drawcall */ grp = DRW_shgroup_create(EEVEE_shaders_volumes_clear_sh_get(), psl->volumetric_world_ps); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); } } -static bool eevee_volume_object_grids_init(Object *ob, ListBase *gpu_grids, DRWShadingGroup *grp) -{ - Volume *volume = ob->data; - BKE_volume_load(volume, G.main); - - /* Test if we need to use multiple transforms. */ - DRWVolumeGrid *first_drw_grid = NULL; - bool multiple_transforms = true; - - LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) { - const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, gpu_grid->name); - DRWVolumeGrid *drw_grid = (volume_grid) ? - DRW_volume_batch_cache_get_grid(volume, volume_grid) : - NULL; - - if (drw_grid) { - if (first_drw_grid == NULL) { - first_drw_grid = drw_grid; - } - else if (drw_grid && - !equals_m4m4(drw_grid->object_to_texture, first_drw_grid->object_to_texture)) { - multiple_transforms = true; - break; - } - } - } - - /* Bail out of no grids to render. */ - if (first_drw_grid == NULL) { - return false; - } - - /* Set transform matrix for the volume as a whole. This one is also used for - * clipping so must map the entire bounding box to 0..1. */ - float bounds_to_object[4][4]; - - if (multiple_transforms) { - /* For multiple grids with different transform, we first transform from object space - * to bounds, then for each individual grid from bounds to texture. */ - const BoundBox *bb = BKE_volume_boundbox_get(ob); - float bb_size[3]; - sub_v3_v3v3(bb_size, bb->vec[6], bb->vec[0]); - size_to_mat4(bounds_to_object, bb_size); - copy_v3_v3(bounds_to_object[3], bb->vec[0]); - - invert_m4_m4(first_drw_grid->object_to_bounds, bounds_to_object); - DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", first_drw_grid->object_to_bounds); - } - else { - /* All grid transforms are equal, we can transform to texture space immediately. */ - DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", first_drw_grid->object_to_texture); - } - - /* Don't use orco transform here, only matrix. */ - DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoLoc", (float[3]){0.5f, 0.5f, 0.5f}); - DRW_shgroup_uniform_vec3_copy(grp, "volumeOrcoSize", (float[3]){0.5f, 0.5f, 0.5f}); - - /* Set density scale. */ - const float density_scale = BKE_volume_density_scale(volume, ob->obmat); - DRW_shgroup_uniform_float_copy(grp, "volumeDensityScale", density_scale); - - /* Bind volume grid textures. */ - LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) { - const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, gpu_grid->name); - DRWVolumeGrid *drw_grid = (volume_grid) ? - DRW_volume_batch_cache_get_grid(volume, volume_grid) : - NULL; - - /* Handle 3 cases here: - * - Grid exists and texture was loaded -> use texture. - * - Grid exists but has zero size or failed to load -> use zero. - * - Grid does not exist -> use default value. */ - GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture : - (volume_grid) ? e_data.dummy_zero : - eevee_volume_default_texture(gpu_grid->default_value); - - DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, grid_tex); - - if (drw_grid && multiple_transforms) { - /* Specify per-volume transform matrix that is applied after the - * transform from object to bounds. */ - mul_m4_m4m4(drw_grid->bounds_to_texture, drw_grid->object_to_texture, bounds_to_object); - DRW_shgroup_uniform_mat4(grp, gpu_grid->transform_name, drw_grid->bounds_to_texture); - } - } - - return true; -} - -static bool eevee_volume_object_mesh_init(Scene *scene, - Object *ob, - ListBase *gpu_grids, - DRWShadingGroup *grp) -{ - static const float white[3] = {1.0f, 1.0f, 1.0f}; - ModifierData *md = NULL; - - /* Smoke Simulation */ - if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && - (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) && - ((FluidModifierData *)md)->domain != NULL) { - FluidModifierData *fmd = (FluidModifierData *)md; - FluidDomainSettings *fds = fmd->domain; - - /* Don't try to show liquid domains here. */ - if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) { - return false; - } - - /* Don't show smoke before simulation starts, this could be made an option in the future. */ - /* (sebbas): Always show smoke for manta */ -#if 0 - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >= - *fds->point_cache[0]->startframe); -#endif - - if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) { - DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); - BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(fmd)); - } - - LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) { - if (STREQ(gpu_grid->name, "density")) { - DRW_shgroup_uniform_texture_ref( - grp, gpu_grid->sampler_name, fds->tex_density ? &fds->tex_density : &e_data.dummy_one); - } - else if (STREQ(gpu_grid->name, "color")) { - DRW_shgroup_uniform_texture_ref( - grp, gpu_grid->sampler_name, fds->tex_color ? &fds->tex_color : &e_data.dummy_one); - } - else if (STR_ELEM(gpu_grid->name, "flame", "temperature")) { - DRW_shgroup_uniform_texture_ref( - grp, gpu_grid->sampler_name, fds->tex_flame ? &fds->tex_flame : &e_data.dummy_flame); - } - else { - DRW_shgroup_uniform_texture( - grp, gpu_grid->sampler_name, eevee_volume_default_texture(gpu_grid->default_value)); - } - } - - /* Constant Volume color. */ - bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && - (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); - - DRW_shgroup_uniform_vec3( - grp, "volumeColor", (use_constant_color) ? fds->active_color : white, 1); - - /* Output is such that 0..1 maps to 0..1000K */ - DRW_shgroup_uniform_vec2(grp, "volumeTemperature", &fds->flame_ignition, 1); - } - else { - LISTBASE_FOREACH (GPUMaterialVolumeGrid *, gpu_grid, gpu_grids) { - DRW_shgroup_uniform_texture( - grp, gpu_grid->sampler_name, eevee_volume_default_texture(gpu_grid->default_value)); - } - } - - /* Transform for mesh volumes. */ - static const float unit_mat[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - {0.0f, 0.0f, 0.0f, 1.0f}}; - float *texco_loc, *texco_size; - BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texco_loc, &texco_size); - - DRW_shgroup_uniform_mat4(grp, "volumeObjectToTexture", unit_mat); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texco_loc, 1); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texco_size, 1); - - return true; -} - void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Scene *scene, @@ -506,15 +300,22 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, int mat_options = VAR_MAT_VOLUME | VAR_MAT_MESH; struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options); - eGPUMaterialStatus status = GPU_material_status(mat); /* If shader failed to compile or is currently compiling. */ - if (status != GPU_MAT_SUCCESS) { + if (mat == NULL) { return; } + /* TODO(fclem): Reuse main shading group to avoid shading binding cost just like for surface + * shaders. */ DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps); + grp = DRW_shgroup_volume_create_sub(scene, ob, grp, mat); + + if (grp == NULL) { + return; + } + /* TODO(fclem): remove those "unnecessary" UBOs */ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); @@ -522,22 +323,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - - ListBase gpu_grids = GPU_material_volume_grids(mat); - - if (ob->type == OB_VOLUME) { - if (!eevee_volume_object_grids_init(ob, &gpu_grids, grp)) { - return; - } - } - else { - if (!eevee_volume_object_mesh_init(scene, ob, &gpu_grids, grp)) { - return; - } - } - /* TODO: Reduce to number of slices intersecting. */ /* TODO: Preemptive culling. */ DRW_shgroup_call_procedural_triangles(grp, ob, sldata->common_data.vol_tex_size[2]); @@ -753,16 +539,6 @@ void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda } } -void EEVEE_volumes_free_smoke_textures(void) -{ - /* Free Smoke Textures after rendering */ - LISTBASE_FOREACH (LinkData *, link, &e_data.smoke_domains) { - FluidModifierData *fmd = (FluidModifierData *)link->data; - DRW_smoke_free(fmd); - } - BLI_freelistN(&e_data.smoke_domains); -} - void EEVEE_volumes_free(void) { DRW_TEXTURE_FREE_SAFE(e_data.dummy_scatter); diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 0e8e8dd9d01..ab0f4d6bec8 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -144,3 +144,13 @@ vec3 attr_load_uv(vec3 attr) return attr; } #endif + +/* Passthrough. */ +float attr_load_temperature_post(float attr) +{ + return attr; +} +vec4 attr_load_color_post(vec4 attr) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl index 9ad7a4fdbc1..79ec3807d0b 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl @@ -179,3 +179,13 @@ vec3 attr_load_uv(vec3 attr) { return vec3(0); } + +/* Passthrough. */ +float attr_load_temperature_post(float attr) +{ + return attr; +} +vec4 attr_load_color_post(vec4 attr) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl index 6c6b810422b..49c18832f72 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl @@ -157,3 +157,13 @@ vec3 attr_load_uv(vec3 attr) return attr; } #endif + +/* Passthrough. */ +float attr_load_temperature_post(float attr) +{ + return attr; +} +vec4 attr_load_color_post(vec4 attr) +{ + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index e0a79872928..914261d7f59 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -4,17 +4,13 @@ /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ -#ifdef MESH_SHADER -uniform vec3 volumeOrcoLoc; -uniform vec3 volumeOrcoSize; -uniform mat4 volumeObjectToTexture; -uniform float volumeDensityScale = 1.0; -#endif +/* Store volumetric properties into the froxel textures. */ flat in int slice; /* Warning: these are not attributes, these are global vars. */ vec3 worldPosition = vec3(0.0); +vec3 objectPosition = vec3(0.0); vec3 viewPosition = vec3(0.0); vec3 viewNormal = vec3(0.0); vec3 volumeOrco = vec3(0.0); @@ -24,9 +20,9 @@ layout(location = 1) out vec4 volumeExtinction; layout(location = 2) out vec4 volumeEmissive; layout(location = 3) out vec4 volumePhase; -/* Store volumetric properties into the froxel textures. */ +int attr_id; -#ifdef MESH_SHADER +#ifndef CLEAR GlobalData init_globals(void) { GlobalData surf; @@ -80,10 +76,8 @@ void main() viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z); worldPosition = point_view_to_world(viewPosition); #ifdef MESH_SHADER - volumeOrco = point_world_to_object(worldPosition); - /* TODO: redundant transform */ - volumeOrco = (volumeOrco - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0); - volumeOrco = (volumeObjectToTexture * vec4(volumeOrco, 1.0)).xyz; + objectPosition = point_world_to_object(worldPosition); + volumeOrco = OrcoTexCoFactors[0].xyz + objectPosition * OrcoTexCoFactors[1].xyz; if (any(lessThan(volumeOrco, vec3(0.0))) || any(greaterThan(volumeOrco, vec3(1.0)))) { /* Note: Discard is not an explicit return in Metal prior to versions 2.3. @@ -100,15 +94,13 @@ void main() volumeEmissive = vec4(0.0, 0.0, 0.0, 1.0); volumePhase = vec4(0.0, 0.0, 0.0, 0.0); #else -# ifdef MESH_SHADER g_data = init_globals(); attrib_load(); -# endif Closure cl = nodetree_exec(); # ifdef MESH_SHADER - cl.scatter *= volumeDensityScale; - cl.absorption *= volumeDensityScale; - cl.emission *= volumeDensityScale; + cl.scatter *= drw_volume.density_scale; + cl.absorption *= drw_volume.density_scale; + cl.emission *= drw_volume.density_scale; # endif volumeScattering = vec4(cl.scatter, 1.0); @@ -124,35 +116,72 @@ void main() #endif } -vec3 attr_load_orco(vec4 orco) +vec3 grid_coordinates() +{ + vec3 co = volumeOrco; +#ifdef MESH_SHADER + /* Optional per-grid transform. */ + if (drw_volume.grids_xform[attr_id][3][3] != 0.0) { + co = (drw_volume.grids_xform[attr_id] * vec4(objectPosition, 1.0)).xyz; + } +#endif + attr_id += 1; + return co; +} + +vec3 attr_load_orco(sampler3D orco) { + attr_id += 1; return volumeOrco; } -vec4 attr_load_tangent(vec4 tangent) +vec4 attr_load_tangent(sampler3D tangent) { + attr_id += 1; return vec4(0); } -vec4 attr_load_vec4(vec4 attr) +vec4 attr_load_vec4(sampler3D tex) { - return vec4(0); + return texture(tex, grid_coordinates()); } -vec3 attr_load_vec3(vec3 attr) +vec3 attr_load_vec3(sampler3D tex) { - return vec3(0); + return texture(tex, grid_coordinates()).rgb; } -vec2 attr_load_vec2(vec2 attr) +vec2 attr_load_vec2(sampler3D tex) { - return vec2(0); + return texture(tex, grid_coordinates()).rg; } -float attr_load_float(float attr) +float attr_load_float(sampler3D tex) { - return 0.0; + return texture(tex, grid_coordinates()).r; } -vec4 attr_load_color(vec4 attr) +vec4 attr_load_color(sampler3D tex) { - return vec4(0); + return texture(tex, grid_coordinates()); } -vec3 attr_load_uv(vec3 attr) +vec3 attr_load_uv(sampler3D attr) { + attr_id += 1; return vec3(0); } + +/* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on + * the engine side. But as of now, the engines are reponsible for loading the attributes. */ +float attr_load_temperature_post(float attr) +{ +#ifdef MESH_SHADER + /* Bring the into standard range without having to modify the grid values */ + attr = (attr > 0.01) ? (attr * drw_volume.temperature_mul + drw_volume.temperature_bias) : 0.0; +#endif + return attr; +} +vec4 attr_load_color_post(vec4 attr) +{ +#ifdef MESH_SHADER + /* Density is premultiplied for interpolation, divide it out here. */ + attr.rgb *= safe_rcp(attr.a); + attr.rgb *= drw_volume.color_mul.rgb; + attr.a = 1.0; +#endif + return attr; +} diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl index 26b60c992e1..527bbd18896 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl @@ -11,10 +11,8 @@ uniform sampler3D volumeScattering; /* Result of the scatter step */ uniform sampler3D volumeExtinction; #ifdef USE_VOLUME_OPTI -uniform layout(r11f_g11f_b10f) -writeonly restrict image3D finalScattering_img; -uniform layout(r11f_g11f_b10f) -writeonly restrict image3D finalTransmittance_img; +uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalScattering_img; +uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img; vec3 finalScattering; vec3 finalTransmittance; diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index abcca5525c7..5d8ba06e181 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -1474,23 +1474,6 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, } if (draw_velocity || show_gridlines) { - BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(fmd)); - } -} - -static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data) -{ - /* Free Smoke Textures after rendering */ - /* XXX This is a waste of processing and GPU bandwidth if nothing - * is updated. But the problem is since Textures are stored in the - * modifier we don't want them to take precious VRAM if the - * modifier is not used for display. We should share them for - * all viewport in a redraw at least. */ - LinkData *link; - while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) { - FluidModifierData *fmd = (FluidModifierData *)link->data; - DRW_smoke_free_velocity(fmd); - MEM_freeN(link); } } @@ -1624,8 +1607,6 @@ void OVERLAY_extra_draw(OVERLAY_Data *vedata) void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata) { DRW_draw_pass(vedata->psl->extra_ps[1]); - - OVERLAY_volume_free_smoke_textures(vedata); } void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 71b6c9424e6..4c933e08a57 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -304,7 +304,6 @@ typedef struct OVERLAY_PrivateData { DRWView *view_edit_curves_points; /** TODO: get rid of this. */ - ListBase smoke_domains; ListBase bg_movie_clips; /** Two instances for in_front option and without. */ diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh index 5d098d61dbf..698c7d1a8b7 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh @@ -55,7 +55,6 @@ GPU_SHADER_CREATE_INFO(workbench_volume_coba) GPU_SHADER_CREATE_INFO(workbench_volume_no_coba) .sampler(4, ImageType::FLOAT_3D, "shadowTexture") - .sampler(5, ImageType::UINT_2D, "transferTexture") .push_constant(Type::VEC3, "activeColor"); /** \} */ diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index f4e042933d1..f7f156e5297 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -163,7 +163,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd); wpd->volumes_do = false; - BLI_listbase_clear(&wpd->smoke_domains); /* FIXME: This reproduce old behavior when workbench was separated in 2 engines. * But this is a workaround for a missing update tagging. */ diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 566fd30096d..fb20bde2f65 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -271,6 +271,18 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, BKE_pbvh_is_drawing_set(ob->sculpt->pbvh, is_sculpt_pbvh); } + bool has_color = false; + + if (me) { + const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me); + const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me); + + has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) || + CustomData_has_layer(cd_vdata, CD_PROP_BYTE_COLOR) || + CustomData_has_layer(cd_ldata, CD_PROP_COLOR) || + CustomData_has_layer(cd_ldata, CD_PROP_BYTE_COLOR)); + } + if (color_type == V3D_SHADING_TEXTURE_COLOR) { if (ob->dt < OB_TEXTURE) { color_type = V3D_SHADING_MATERIAL_COLOR; @@ -285,14 +297,6 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, color_type = V3D_SHADING_OBJECT_COLOR; } else { - const CustomData *cd_vdata = workbench_mesh_get_vert_custom_data(me); - const CustomData *cd_ldata = workbench_mesh_get_loop_custom_data(me); - - bool has_color = (CustomData_has_layer(cd_vdata, CD_PROP_COLOR) || - CustomData_has_layer(cd_vdata, CD_MLOOPCOL) || - CustomData_has_layer(cd_ldata, CD_PROP_COLOR) || - CustomData_has_layer(cd_ldata, CD_MLOOPCOL)); - if (!has_color) { color_type = V3D_SHADING_OBJECT_COLOR; } @@ -314,7 +318,7 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, *r_texpaint_mode = true; } } - else if (is_vertpaint_mode && me && CustomData_has_layer(ldata, CD_MLOOPCOL)) { + else if (is_vertpaint_mode && me && has_color) { color_type = V3D_SHADING_VERTEX_COLOR; } } @@ -613,10 +617,8 @@ static void workbench_draw_scene(void *ved) workbench_draw_finish(vedata); } -void workbench_draw_finish(void *ved) +void workbench_draw_finish(void *UNUSED(ved)) { - WORKBENCH_Data *vedata = ved; - workbench_volume_draw_finish(vedata); /* Reset default view. */ DRW_view_set_active(NULL); } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 727b771ee08..492bce1e571 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -324,10 +324,6 @@ typedef struct WORKBENCH_PrivateData { /** Index of current material inside the material chunk. Only for material coloring mode. */ int material_index; - /* Volumes */ - /** List of smoke domain textures to free after drawing. */ - ListBase smoke_domains; - /* Depth of Field */ /** Depth of field temp buffers. */ struct GPUTexture *dof_blur_tx; @@ -533,7 +529,6 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, struct ModifierData *md, eV3DShadingColorType color_type); void workbench_volume_draw_pass(WORKBENCH_Data *vedata); -void workbench_volume_draw_finish(WORKBENCH_Data *vedata); /* workbench_engine.c */ diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 72de3fe298a..1279682e899 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -170,9 +170,9 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer DRW_render_instance_buffer_finish(); - /* Also we weed to have a correct FBO bound for #DRW_hair_update */ + /* Also we weed to have a correct FBO bound for #DRW_curves_update */ GPU_framebuffer_bind(dfbl->default_fb); - DRW_hair_update(); + DRW_curves_update(); GPU_framebuffer_bind(dfbl->default_fb); GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f); diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index c6f40c5d6bb..2c902e9b627 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -178,8 +178,6 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata, else { DRW_shgroup_call(grp, DRW_cache_cube_get(), ob); } - - BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(fmd)); } static void workbench_volume_material_color(WORKBENCH_PrivateData *wpd, @@ -334,20 +332,3 @@ void workbench_volume_draw_pass(WORKBENCH_Data *vedata) DRW_draw_pass(psl->volume_ps); } } - -void workbench_volume_draw_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_PrivateData *wpd = vedata->stl->wpd; - - /* Free Smoke Textures after rendering */ - /* XXX This is a waste of processing and GPU bandwidth if nothing - * is updated. But the problem is since Textures are stored in the - * modifier we don't want them to take precious VRAM if the - * modifier is not used for display. We should share them for - * all viewport in a redraw at least. */ - LISTBASE_FOREACH (LinkData *, link, &wpd->smoke_domains) { - FluidModifierData *fmd = (FluidModifierData *)link->data; - DRW_smoke_free(fmd); - } - BLI_freelistN(&wpd->smoke_domains); -} diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index ed94c485b32..d7e752a43f4 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -53,6 +53,8 @@ * */ +#include "DRW_render.h" + #include "MEM_guardedalloc.h" #include "draw_texture_pool.h" @@ -61,6 +63,7 @@ #include "BLI_span.hh" #include "BLI_utildefines.h" #include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" #include "GPU_framebuffer.h" #include "GPU_storage_buffer.h" diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index b084a5e5945..f2742f3bcc7 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -29,9 +29,11 @@ #include "GPU_material.h" #include "GPU_texture.h" +#include "DRW_render.h" + #include "draw_cache_impl.h" /* own include */ #include "draw_cache_inline.h" -#include "draw_hair_private.h" /* own include */ +#include "draw_curves_private.h" /* own include */ using blender::float3; using blender::IndexRange; @@ -41,7 +43,7 @@ using blender::Span; /* Curves GPUBatch Cache */ struct CurvesBatchCache { - ParticleHairCache hair; + CurvesEvalCache curves_cache; GPUBatch *edit_points; @@ -70,6 +72,28 @@ static void curves_batch_cache_init(Curves &curves) cache->is_dirty = false; } +static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache) +{ + /* TODO: more granular update tagging. */ + GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_point_buf); + GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_length_buf); + DRW_TEXTURE_FREE_SAFE(curves_cache.point_tex); + DRW_TEXTURE_FREE_SAFE(curves_cache.length_tex); + + GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_buf); + GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_strand_seg_buf); + DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex); + DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex); + + for (int i = 0; i < MAX_HAIR_SUBDIV; i++) { + GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf); + DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex); + for (int j = 0; j < MAX_THICKRES; j++) { + GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]); + } + } +} + static void curves_batch_cache_clear(Curves &curves) { CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache); @@ -77,7 +101,8 @@ static void curves_batch_cache_clear(Curves &curves) return; } - particle_batch_cache_clear_hair(&cache->hair); + curves_batch_cache_clear_data(cache->curves_cache); + GPU_BATCH_DISCARD_SAFE(cache->edit_points); } @@ -116,10 +141,9 @@ void DRW_curves_batch_cache_free(Curves *curves) MEM_SAFE_FREE(curves->batch_cache); } -static void ensure_seg_pt_count(const Curves &curves, ParticleHairCache &curves_cache) +static void ensure_seg_pt_count(const Curves &curves, CurvesEvalCache &curves_cache) { - if ((curves_cache.pos != nullptr && curves_cache.indices != nullptr) || - (curves_cache.proc_point_buf != nullptr)) { + if (curves_cache.proc_point_buf != nullptr) { return; } @@ -169,7 +193,7 @@ static void curves_batch_cache_fill_segments_proc_pos(const Curves &curves_id, } static void curves_batch_cache_ensure_procedural_pos(Curves &curves, - ParticleHairCache &cache, + CurvesEvalCache &cache, GPUMaterial *gpu_material) { if (cache.proc_point_buf == nullptr || DRW_vbo_requested(cache.proc_point_buf)) { @@ -229,7 +253,7 @@ static void curves_batch_cache_fill_strands_data(const Curves &curves_id, } static void curves_batch_cache_ensure_procedural_strand_data(Curves &curves, - ParticleHairCache &cache) + CurvesEvalCache &cache) { GPUVertBufRaw data_step, seg_step; @@ -259,7 +283,7 @@ static void curves_batch_cache_ensure_procedural_strand_data(Curves &curves, cache.proc_strand_seg_buf); } -static void curves_batch_cache_ensure_procedural_final_points(ParticleHairCache &cache, int subdiv) +static void curves_batch_cache_ensure_procedural_final_points(CurvesEvalCache &cache, int subdiv) { /* Same format as point_tex. */ GPUVertFormat format = {0}; @@ -296,7 +320,7 @@ static void curves_batch_cache_fill_segments_indices(const Curves &curves, } static void curves_batch_cache_ensure_procedural_indices(Curves &curves, - ParticleHairCache &cache, + CurvesEvalCache &cache, const int thickness_res, const int subdiv) { @@ -330,7 +354,7 @@ static void curves_batch_cache_ensure_procedural_indices(Curves &curves, } bool curves_ensure_procedural_data(Object *object, - ParticleHairCache **r_hair_cache, + CurvesEvalCache **r_hair_cache, GPUMaterial *gpu_material, const int subdiv, const int thickness_res) @@ -339,30 +363,31 @@ bool curves_ensure_procedural_data(Object *object, Curves &curves = *static_cast<Curves *>(object->data); CurvesBatchCache &cache = curves_batch_cache_get(curves); - *r_hair_cache = &cache.hair; + *r_hair_cache = &cache.curves_cache; const int steps = 3; /* TODO: don't hard-code? */ (*r_hair_cache)->final[subdiv].strands_res = 1 << (steps + subdiv); /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == nullptr) { - ensure_seg_pt_count(curves, cache.hair); - curves_batch_cache_ensure_procedural_pos(curves, cache.hair, gpu_material); + ensure_seg_pt_count(curves, cache.curves_cache); + curves_batch_cache_ensure_procedural_pos(curves, cache.curves_cache, gpu_material); need_ft_update = true; } /* Refreshed if active layer or custom data changes. */ if ((*r_hair_cache)->strand_tex == nullptr) { - curves_batch_cache_ensure_procedural_strand_data(curves, cache.hair); + curves_batch_cache_ensure_procedural_strand_data(curves, cache.curves_cache); } /* Refreshed only on subdiv count change. */ if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) { - curves_batch_cache_ensure_procedural_final_points(cache.hair, subdiv); + curves_batch_cache_ensure_procedural_final_points(cache.curves_cache, subdiv); need_ft_update = true; } if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) { - curves_batch_cache_ensure_procedural_indices(curves, cache.hair, thickness_res, subdiv); + curves_batch_cache_ensure_procedural_indices( + curves, cache.curves_cache, thickness_res, subdiv); } return need_ft_update; @@ -385,10 +410,10 @@ void DRW_curves_batch_cache_create_requested(const Object *ob) CurvesBatchCache &cache = curves_batch_cache_get(*curves); if (DRW_batch_requested(cache.edit_points, GPU_PRIM_POINTS)) { - DRW_vbo_request(cache.edit_points, &cache.hair.proc_point_buf); + DRW_vbo_request(cache.edit_points, &cache.curves_cache.proc_point_buf); } - if (DRW_vbo_requested(cache.hair.proc_point_buf)) { - curves_batch_cache_ensure_procedural_pos(*curves, cache.hair, nullptr); + if (DRW_vbo_requested(cache.curves_cache.proc_point_buf)) { + curves_batch_cache_ensure_procedural_pos(*curves, cache.curves_cache, nullptr); } } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index c4fa60ef51d..e4aec17eb69 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -518,15 +518,17 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query, domain = ATTR_DOMAIN_POINT; layer_i = CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, name); - layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_vdata, CD_MLOOPCOL, name) : - layer_i; + layer_i = layer_i == -1 ? + CustomData_get_named_layer_index(cd_vdata, CD_PROP_BYTE_COLOR, name) : + layer_i; if (layer_i == -1) { domain = ATTR_DOMAIN_CORNER; layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_PROP_COLOR, name) : layer_i; - layer_i = layer_i == -1 ? CustomData_get_named_layer_index(cd_ldata, CD_MLOOPCOL, name) : - layer_i; + layer_i = layer_i == -1 ? + CustomData_get_named_layer_index(cd_ldata, CD_PROP_BYTE_COLOR, name) : + layer_i; } /* Note: this is not the same as the layer_i below. */ @@ -610,17 +612,17 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, } if (layer == -1) { - layer = CustomData_get_named_layer(cd_vdata, CD_MLOOPCOL, name); + layer = CustomData_get_named_layer(cd_vdata, CD_PROP_BYTE_COLOR, name); if (layer != -1) { - type = CD_MLOOPCOL; + type = CD_PROP_BYTE_COLOR; domain = ATTR_DOMAIN_POINT; } } if (layer == -1) { - layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name); + layer = CustomData_get_named_layer(cd_ldata, CD_PROP_BYTE_COLOR, name); if (layer != -1) { - type = CD_MLOOPCOL; + type = CD_PROP_BYTE_COLOR; domain = ATTR_DOMAIN_CORNER; } } @@ -700,11 +702,11 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, } /* Note: attr->type will always be CD_PROP_COLOR even for - * CD_MLOOPCOL layers, see node_shader_gpu_vertex_color in + * CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in * node_shader_vertex_color.cc. */ case CD_MCOL: - case CD_MLOOPCOL: + case CD_PROP_BYTE_COLOR: case CD_PROP_COLOR: { int vcol_bit = mesh_cd_calc_gpu_layers_vcol_used(&me_query, cd_vdata, cd_ldata, name); diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index c6b56723818..0f1ab967ca5 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -164,7 +164,7 @@ static void particle_batch_cache_clear_point(ParticlePointCache *point_cache) GPU_VERTBUF_DISCARD_SAFE(point_cache->pos); } -void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) +static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) { /* TODO: more granular update tagging. */ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); @@ -822,10 +822,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); render_uv = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); } - if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) { - cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL); - active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); - render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); + if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR)) { + cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, + CD_PROP_BYTE_COLOR); + active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR); + render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR); } } @@ -891,7 +892,7 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]); char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i); + const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR, i); GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); int n = 0; @@ -1162,9 +1163,9 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV); active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); } - if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) { - num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL); - active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); + if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR)) { + num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR); + active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR); } } @@ -1195,7 +1196,8 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, for (int i = 0; i < num_col_layers; i++) { char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i); + const char *name = CustomData_get_layer_name( + &psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR, i); GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name); diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index d302140d9ac..779ac43178c 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -21,6 +21,8 @@ struct Object; struct ParticleSystem; struct RegionView3D; struct ViewLayer; +struct Scene; +struct DRWData; /* Keep in sync with globalsBlock in shaders */ BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16) @@ -54,16 +56,12 @@ struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct DRWShadingGroup *shgrp, struct GPUMaterial *gpu_material); -struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object, - struct DRWShadingGroup *shgrp, - struct GPUMaterial *gpu_material); /** * \note Only valid after #DRW_hair_update(). */ struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md); -struct GPUVertBuf *DRW_curves_pos_buffer_get(struct Object *object); void DRW_hair_duplimat_get(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, @@ -73,6 +71,37 @@ void DRW_hair_init(void); void DRW_hair_update(void); void DRW_hair_free(void); +/* draw_curves.cc */ + +/** + * \note Only valid after #DRW_curves_update(). + */ +struct GPUVertBuf *DRW_curves_pos_buffer_get(struct Object *object); + +struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object, + struct DRWShadingGroup *shgrp, + struct GPUMaterial *gpu_material); + +void DRW_curves_init(void); +void DRW_curves_update(void); +void DRW_curves_free(void); + +/* draw_volume.cc */ + +/** + * Add attributes bindings of volume grids to an existing shading group. + * No draw call is added so the caller can decide how to use the data. + * \return nullptr if there is something to draw. + */ +struct DRWShadingGroup *DRW_shgroup_volume_create_sub(struct Scene *scene, + struct Object *ob, + struct DRWShadingGroup *shgrp, + struct GPUMaterial *gpu_material); + +void DRW_volume_init(struct DRWData *drw_data); +void DRW_volume_ubos_pool_free(void *pool); +void DRW_volume_free(void); + /* draw_fluid.c */ /* Fluid simulation. */ @@ -83,7 +112,9 @@ void DRW_fluid_ensure_flags(struct FluidModifierData *fmd); void DRW_fluid_ensure_range_field(struct FluidModifierData *fmd); void DRW_smoke_free(struct FluidModifierData *fmd); -void DRW_smoke_free_velocity(struct FluidModifierData *fmd); + +void DRW_smoke_init(struct DRWData *drw_data); +void DRW_smoke_exit(struct DRWData *drw_data); /* draw_common.c */ diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc new file mode 100644 index 00000000000..88118361115 --- /dev/null +++ b/source/blender/draw/intern/draw_curves.cc @@ -0,0 +1,325 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2017 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Contains procedural GPU hair drawing methods. + */ + +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "DNA_customdata_types.h" + +#include "GPU_batch.h" +#include "GPU_capabilities.h" +#include "GPU_compute.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_vertex_buffer.h" + +#include "DRW_render.h" + +#include "draw_hair_private.h" +#include "draw_shader.h" + +#ifndef __APPLE__ +# define USE_TRANSFORM_FEEDBACK +# define USE_COMPUTE_SHADERS +#endif + +BLI_INLINE eParticleRefineShaderType drw_curves_shader_type_get() +{ +#ifdef USE_COMPUTE_SHADERS + if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) { + return PART_REFINE_SHADER_COMPUTE; + } +#endif +#ifdef USE_TRANSFORM_FEEDBACK + return PART_REFINE_SHADER_TRANSFORM_FEEDBACK; +#endif + return PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND; +} + +#ifndef USE_TRANSFORM_FEEDBACK +struct CurvesEvalCall { + struct CurvesEvalCall *next; + GPUVertBuf *vbo; + DRWShadingGroup *shgrp; + uint vert_len; +}; + +static CurvesEvalCall *g_tf_calls = nullptr; +static int g_tf_id_offset; +static int g_tf_target_width; +static int g_tf_target_height; +#endif + +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 */ + +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) +{ + /* Initialize legacy hair too, to avoid verbosity in callers. */ + DRW_hair_init(); + +#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS) + g_tf_pass = DRW_pass_create("Update Curves Pass", (DRWState)0); +#else + g_tf_pass = DRW_pass_create("Update Curves Pass", DRW_STATE_WRITE_COLOR); +#endif + + if (g_dummy_vbo == nullptr) { + /* initialize vertex format */ + GPUVertFormat format = {0}; + uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + g_dummy_vbo = GPU_vertbuf_create_with_format(&format); + + const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_vertbuf_data_alloc(g_dummy_vbo, 1); + GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert); + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(g_dummy_vbo); + + g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo); + } +} + +static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp, + CurvesEvalCache *cache, + const int subdiv) +{ + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_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 = 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; + } + } +} + +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) { + 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); +#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); +#endif + + drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv); + DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len); + } +} + +static CurvesEvalCache *drw_curves_cache_get(Object *object, + GPUMaterial *gpu_material, + int subdiv, + int thickness_res) +{ + CurvesEvalCache *cache; + bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res); + + if (update) { + if (drw_curves_shader_type_get() == PART_REFINE_SHADER_COMPUTE) { + drw_curves_cache_update_compute(cache, subdiv); + } + else { + drw_curves_cache_update_transform_feedback(cache, subdiv); + } + } + return cache; +} + +GPUVertBuf *DRW_curves_pos_buffer_get(Object *object) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + int subdiv = scene->r.hair_subdiv; + int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + + CurvesEvalCache *cache = drw_curves_cache_get(object, nullptr, subdiv, thickness_res); + + return cache->final[subdiv].proc_buf; +} + +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; + + int subdiv = scene->r.hair_subdiv; + int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + + CurvesEvalCache *curves_cache = drw_curves_cache_get( + object, gpu_material, subdiv, thickness_res); + + DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); + + /* Fix issue with certain driver not drawing anything if there is no texture bound to + * "ac", "au", "u" or "c". */ + DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); + + /* TODO: Generalize radius implementation for curves data type. */ + float hair_rad_shape = 1.0f; + float hair_rad_root = 0.005f; + float hair_rad_tip = 0.0f; + bool hair_close_tip = true; + + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex); + if (curves_cache->length_tex) { + DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex); + } + 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); + DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat); + DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); + DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); + DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); + /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass + * culling test. */ + GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1]; + DRW_shgroup_call_no_cull(shgrp, geom, object); + + return shgrp; +} + +void DRW_curves_update() +{ + /* Update legacy hair too, to avoid verbosity in callers. */ + DRW_hair_update(); + +#ifndef USE_TRANSFORM_FEEDBACK + /** + * Workaround to transform feedback not working on mac. + * On some system it crashes (see T58489) and on some other it renders garbage (see T60171). + * + * So instead of using transform feedback we render to a texture, + * read back the result to system memory and re-upload as VBO data. + * It is really not ideal performance wise, but it is the simplest + * and the most local workaround that still uses the power of the GPU. + */ + + if (g_tf_calls == nullptr) { + return; + } + + /* Search ideal buffer size. */ + uint max_size = 0; + for (CurvesEvalCall *pr_call = g_tf_calls; pr_call; pr_call = pr_call->next) { + max_size = max_ii(max_size, pr_call->vert_len); + } + + /* Create target Texture / Frame-buffer */ + /* Don't use max size as it can be really heavy and fail. + * Do chunks of maximum 2048 * 2048 hair points. */ + int width = 2048; + int height = min_ii(width, 1 + max_size / width); + GPUTexture *tex = DRW_texture_pool_query_2d( + width, height, GPU_RGBA32F, (DrawEngineType *)DRW_curves_update); + g_tf_target_height = height; + g_tf_target_width = width; + + GPUFrameBuffer *fb = nullptr; + GPU_framebuffer_ensure_config(&fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(tex), + }); + + float *data = static_cast<float *>( + MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer")); + + GPU_framebuffer_bind(fb); + while (g_tf_calls != nullptr) { + CurvesEvalCall *pr_call = g_tf_calls; + g_tf_calls = g_tf_calls->next; + + g_tf_id_offset = 0; + while (pr_call->vert_len > 0) { + int max_read_px_len = min_ii(width * height, pr_call->vert_len); + + DRW_draw_pass_subset(g_tf_pass, pr_call->shgrp, pr_call->shgrp); + /* Read back result to main memory. */ + GPU_framebuffer_read_color(fb, 0, 0, width, height, 4, 0, GPU_DATA_FLOAT, data); + /* Upload back to VBO. */ + GPU_vertbuf_use(pr_call->vbo); + GPU_vertbuf_update_sub(pr_call->vbo, + sizeof(float[4]) * g_tf_id_offset, + sizeof(float[4]) * max_read_px_len, + data); + + g_tf_id_offset += max_read_px_len; + pr_call->vert_len -= max_read_px_len; + } + + MEM_freeN(pr_call); + } + + MEM_freeN(data); + GPU_framebuffer_free(fb); +#else + /* Just render the pass when using compute shaders or transform feedback. */ + DRW_draw_pass(g_tf_pass); + if (drw_curves_shader_type_get() == PART_REFINE_SHADER_COMPUTE) { + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); + } +#endif +} + +void DRW_curves_free() +{ + DRW_hair_free(); + + GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo); + DRW_TEXTURE_FREE_SAFE(g_dummy_texture); +} diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h new file mode 100644 index 00000000000..76d5f15319d --- /dev/null +++ b/source/blender/draw/intern/draw_curves_private.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2017 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_THICKRES 2 /* see eHairType */ +#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */ + +typedef enum CurvesEvalShader { + CURVES_EVAL_CATMULL_ROM = 0, + CURVES_EVAL_BEZIER = 1, +} CurvesEvalShader; +#define CURVES_EVAL_SHADER_NUM 3 + +struct GPUVertBuf; +struct GPUIndexBuf; +struct GPUBatch; +struct GPUTexture; + +typedef struct CurvesEvalFinalCache { + /* Output of the subdivision stage: vertex buffer sized to subdiv level. */ + GPUVertBuf *proc_buf; + GPUTexture *proc_tex; + + /* Just contains a huge index buffer used to draw the final curves. */ + GPUBatch *proc_hairs[MAX_THICKRES]; + + /* Points per curve, at least 2. */ + int strands_res; +} CurvesEvalFinalCache; + +/* Curves procedural display: Evaluation is done on the GPU. */ +typedef struct CurvesEvalCache { + /* Input control points */ + GPUVertBuf *proc_point_buf; + GPUTexture *point_tex; + + /** Info of control points strands (segment count and base index) */ + GPUVertBuf *proc_strand_buf; + GPUTexture *strand_tex; + + /* Curve length data. */ + GPUVertBuf *proc_length_buf; + GPUTexture *length_tex; + + GPUVertBuf *proc_strand_seg_buf; + GPUTexture *strand_seg_tex; + + CurvesEvalFinalCache final[MAX_HAIR_SUBDIV]; + + int strands_len; + int elems_len; + int point_len; +} CurvesEvalCache; + +/** + * Ensure all textures and buffers needed for GPU accelerated drawing. + */ +bool curves_ensure_procedural_data(struct Object *object, + struct CurvesEvalCache **r_hair_cache, + struct GPUMaterial *gpu_material, + int subdiv, + int thickness_res); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_fluid.c b/source/blender/draw/intern/draw_fluid.c index 667bd24dddb..d3d4bbf505e 100644 --- a/source/blender/draw/intern/draw_fluid.c +++ b/source/blender/draw/intern/draw_fluid.c @@ -9,6 +9,7 @@ #include <string.h> +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -21,6 +22,8 @@ #include "GPU_texture.h" +#include "draw_manager.h" + #include "draw_common.h" /* Own include. */ #ifdef WITH_FLUID @@ -419,46 +422,6 @@ static bool get_smoke_velocity_field(FluidDomainSettings *fds, /** \name Public API * \{ */ -void DRW_smoke_free(FluidModifierData *fmd) -{ - if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) { - if (fmd->domain->tex_density) { - GPU_texture_free(fmd->domain->tex_density); - fmd->domain->tex_density = NULL; - } - - if (fmd->domain->tex_color) { - GPU_texture_free(fmd->domain->tex_color); - fmd->domain->tex_color = NULL; - } - - if (fmd->domain->tex_shadow) { - GPU_texture_free(fmd->domain->tex_shadow); - fmd->domain->tex_shadow = NULL; - } - - if (fmd->domain->tex_flame) { - GPU_texture_free(fmd->domain->tex_flame); - fmd->domain->tex_flame = NULL; - } - - if (fmd->domain->tex_flame_coba) { - GPU_texture_free(fmd->domain->tex_flame_coba); - fmd->domain->tex_flame_coba = NULL; - } - - if (fmd->domain->tex_coba) { - GPU_texture_free(fmd->domain->tex_coba); - fmd->domain->tex_coba = NULL; - } - - if (fmd->domain->tex_field) { - GPU_texture_free(fmd->domain->tex_field); - fmd->domain->tex_field = NULL; - } - } -} - void DRW_smoke_ensure_coba_field(FluidModifierData *fmd) { #ifndef WITH_FLUID @@ -469,6 +432,7 @@ void DRW_smoke_ensure_coba_field(FluidModifierData *fmd) if (!fds->tex_field) { fds->tex_field = create_field_texture(fds, false); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_field)); } if (!fds->tex_coba && !ELEM(fds->coba_field, FLUID_DOMAIN_FIELD_PHI, @@ -478,6 +442,7 @@ void DRW_smoke_ensure_coba_field(FluidModifierData *fmd) FLUID_DOMAIN_FIELD_FLAGS, FLUID_DOMAIN_FIELD_PRESSURE)) { fds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, fds->coba); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_coba)); } } #endif @@ -493,19 +458,24 @@ void DRW_smoke_ensure(FluidModifierData *fmd, int highres) if (!fds->tex_density) { fds->tex_density = create_density_texture(fds, highres); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_density)); } if (!fds->tex_color) { fds->tex_color = create_color_texture(fds, highres); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_color)); } if (!fds->tex_flame) { fds->tex_flame = create_flame_texture(fds, highres); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_flame)); } if (!fds->tex_flame_coba && fds->tex_flame) { fds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_flame_coba)); } if (!fds->tex_shadow) { fds->tex_shadow = create_volume_texture( fds->res, GPU_R8, GPU_DATA_FLOAT, manta_smoke_get_shadow(fds->fluid)); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_shadow)); } } #endif /* WITH_FLUID */ @@ -536,6 +506,9 @@ void DRW_smoke_ensure_velocity(FluidModifierData *fmd) "vely", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_y); fds->tex_velocity_z = GPU_texture_create_3d( "velz", UNPACK3(fds->res), 1, GPU_R16F, GPU_DATA_FLOAT, vel_z); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_velocity_x)); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_velocity_y)); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_velocity_z)); } } #endif /* WITH_FLUID */ @@ -551,6 +524,7 @@ void DRW_fluid_ensure_flags(FluidModifierData *fmd) if (!fds->tex_flags) { fds->tex_flags = create_volume_texture( fds->res, GPU_R8UI, GPU_DATA_INT, manta_smoke_get_flags(fds->fluid)); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_flags)); swizzle_texture_channel_single(fds->tex_flags); } @@ -568,42 +542,29 @@ void DRW_fluid_ensure_range_field(FluidModifierData *fmd) if (!fds->tex_range_field) { fds->tex_range_field = create_field_texture(fds, true); + BLI_addtail(&DST.vmempool->smoke_textures, BLI_genericNodeN(&fds->tex_range_field)); } } #endif /* WITH_FLUID */ } -void DRW_smoke_free_velocity(FluidModifierData *fmd) +void DRW_smoke_init(DRWData *drw_data) { - /* TODO: Unify with the other #GPU_free_smoke. */ - - if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) { - if (fmd->domain->tex_velocity_x) { - GPU_texture_free(fmd->domain->tex_velocity_x); - } - - if (fmd->domain->tex_velocity_y) { - GPU_texture_free(fmd->domain->tex_velocity_y); - } - - if (fmd->domain->tex_velocity_z) { - GPU_texture_free(fmd->domain->tex_velocity_z); - } - - if (fmd->domain->tex_flags) { - GPU_texture_free(fmd->domain->tex_flags); - } - - if (fmd->domain->tex_range_field) { - GPU_texture_free(fmd->domain->tex_range_field); - } + BLI_listbase_clear(&drw_data->smoke_textures); +} - fmd->domain->tex_velocity_x = NULL; - fmd->domain->tex_velocity_y = NULL; - fmd->domain->tex_velocity_z = NULL; - fmd->domain->tex_flags = NULL; - fmd->domain->tex_range_field = NULL; +void DRW_smoke_exit(DRWData *drw_data) +{ + /* Free Smoke Textures after rendering */ + /* XXX This is a waste of processing and GPU bandwidth if nothing + * is updated. But the problem is since Textures are stored in the + * modifier we don't want them to take precious VRAM if the + * modifier is not used for display. We should share them for + * all viewport in a redraw at least. */ + LISTBASE_FOREACH (LinkData *, link, &drw_data->smoke_textures) { + GPU_TEXTURE_FREE_SAFE(*(GPUTexture **)link->data); } + BLI_freelistN(&drw_data->smoke_textures); } /** \} */ diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index aac6f7e58c5..8351452769d 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -179,25 +179,6 @@ static ParticleHairCache *drw_hair_particle_cache_get(Object *object, return cache; } -static ParticleHairCache *drw_curves_cache_get(Object *object, - GPUMaterial *gpu_material, - int subdiv, - int thickness_res) -{ - ParticleHairCache *cache; - bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res); - - if (update) { - if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) { - drw_hair_particle_cache_update_compute(cache, subdiv); - } - else { - drw_hair_particle_cache_update_transform_feedback(cache, subdiv); - } - } - return cache; -} - GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, ModifierData *md) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -212,19 +193,6 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi return cache->final[subdiv].proc_buf; } -GPUVertBuf *DRW_curves_pos_buffer_get(Object *object) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - - int subdiv = scene->r.hair_subdiv; - int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - - ParticleHairCache *cache = drw_curves_cache_get(object, NULL, subdiv, thickness_res); - - return cache->final[subdiv].proc_buf; -} - void DRW_hair_duplimat_get(Object *object, ParticleSystem *UNUSED(psys), ModifierData *UNUSED(md), @@ -323,71 +291,6 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, return shgrp; } -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; - - int subdiv = scene->r.hair_subdiv; - int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - - ParticleHairCache *curves_cache = drw_curves_cache_get( - object, gpu_material, subdiv, thickness_res); - - DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); - - /* TODO: optimize this. Only bind the ones GPUMaterial needs. */ - for (int i = 0; i < curves_cache->num_uv_layers; i++) { - for (int n = 0; n < MAX_LAYER_NAME_CT && curves_cache->uv_layer_names[i][n][0] != '\0'; n++) { - DRW_shgroup_uniform_texture( - shgrp, curves_cache->uv_layer_names[i][n], curves_cache->uv_tex[i]); - } - } - for (int i = 0; i < curves_cache->num_col_layers; i++) { - for (int n = 0; n < MAX_LAYER_NAME_CT && curves_cache->col_layer_names[i][n][0] != '\0'; n++) { - DRW_shgroup_uniform_texture( - shgrp, curves_cache->col_layer_names[i][n], curves_cache->col_tex[i]); - } - } - - /* Fix issue with certain driver not drawing anything if there is no texture bound to - * "ac", "au", "u" or "c". */ - if (curves_cache->num_uv_layers == 0) { - DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture); - DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture); - } - if (curves_cache->num_col_layers == 0) { - DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture); - DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); - } - - /* TODO: Generalize radius implementation for curves data type. */ - float hair_rad_shape = 1.0f; - float hair_rad_root = 0.005f; - float hair_rad_tip = 0.0f; - bool hair_close_tip = true; - - DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex); - if (curves_cache->length_tex) { - DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex); - } - 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); - DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat); - DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root); - DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip); - DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip); - /* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass - * culling test. */ - GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1]; - DRW_shgroup_call_no_cull(shgrp, geom, object); - - return shgrp; -} - void DRW_hair_update(void) { #ifndef USE_TRANSFORM_FEEDBACK diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index 58e8609106b..5d84c8863f2 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -75,8 +75,6 @@ typedef struct ParticleHairCache { int point_len; } ParticleHairCache; -void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache); - /** * Ensure all textures and buffers needed for GPU accelerated drawing. */ @@ -88,15 +86,6 @@ bool particles_ensure_procedural_data(struct Object *object, int subdiv, int thickness_res); -/** - * Ensure all textures and buffers needed for GPU accelerated drawing. - */ -bool curves_ensure_procedural_data(struct Object *object, - struct ParticleHairCache **r_hair_cache, - struct GPUMaterial *gpu_material, - int subdiv, - int thickness_res); - #ifdef __cplusplus } #endif diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 88d05fcd928..adf9d4a13df 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -478,6 +478,7 @@ void DRW_viewport_data_free(DRWData *drw_data) MEM_freeN(drw_data->matrices_ubo); MEM_freeN(drw_data->obinfos_ubo); } + DRW_volume_ubos_pool_free(drw_data->volume_grids_ubos); MEM_freeN(drw_data); } @@ -1649,7 +1650,9 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DRW_globals_update(); drw_debug_init(); - DRW_hair_init(); + DRW_curves_init(); + DRW_volume_init(DST.vmempool); + DRW_smoke_init(DST.vmempool); /* No frame-buffer allowed before drawing. */ BLI_assert(GPU_framebuffer_active_get() == GPU_framebuffer_back_get()); @@ -1704,7 +1707,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, GPU_framebuffer_bind(DST.default_framebuffer); GPU_framebuffer_clear_depth_stencil(DST.default_framebuffer, 1.0f, 0xFF); - DRW_hair_update(); + DRW_curves_update(); DRW_draw_callbacks_pre_scene(); @@ -1715,6 +1718,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, GPU_flush(); } + DRW_smoke_exit(DST.vmempool); + DRW_stats_reset(); DRW_draw_callbacks_post_scene(); @@ -1999,6 +2004,8 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) GPU_framebuffer_restore(); + DRW_smoke_exit(DST.vmempool); + drw_manager_exit(&DST); /* Reset state after drawing */ @@ -2015,7 +2022,9 @@ void DRW_render_object_iter( void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) { const DRWContextState *draw_ctx = DRW_context_state_get(); - DRW_hair_init(); + DRW_curves_init(); + DRW_volume_init(DST.vmempool); + DRW_smoke_init(DST.vmempool); drw_task_graph_init(); const int object_type_exclude_viewport = draw_ctx->v3d ? @@ -2070,7 +2079,9 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, drw_manager_init(&DST, NULL, NULL); - DRW_hair_init(); + DRW_curves_init(); + DRW_volume_init(DST.vmempool); + DRW_smoke_init(DST.vmempool); ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(DST.view_data_active, draw_engine_type); @@ -2079,6 +2090,8 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, callback(data, user_data); DST.buffer_finish_called = false; + DRW_smoke_exit(DST.vmempool); + GPU_framebuffer_restore(); /* The use of custom pipeline in other thread using the same @@ -2095,11 +2108,15 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type, void DRW_cache_restart(void) { + DRW_smoke_exit(DST.vmempool); + drw_manager_init(&DST, DST.viewport, (int[2]){UNPACK2(DST.size)}); DST.buffer_finish_called = false; - DRW_hair_init(); + DRW_curves_init(); + DRW_volume_init(DST.vmempool); + DRW_smoke_init(DST.vmempool); } void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, @@ -2416,7 +2433,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, /* Init engines */ drw_engines_init(); - DRW_hair_init(); + DRW_curves_init(); + DRW_volume_init(DST.vmempool); + DRW_smoke_init(DST.vmempool); { drw_engines_cache_init(); @@ -2493,7 +2512,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DRW_state_reset(); DRW_draw_callbacks_pre_scene(); - DRW_hair_update(); + DRW_curves_update(); /* Only 1-2 passes. */ while (true) { @@ -2511,6 +2530,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } } + DRW_smoke_exit(DST.vmempool); + DRW_state_reset(); drw_engines_disable(); @@ -2586,7 +2607,9 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, /* Init engines */ drw_engines_init(); - DRW_hair_init(); + DRW_curves_init(); + DRW_volume_init(DST.vmempool); + DRW_smoke_init(DST.vmempool); { drw_engines_cache_init(); @@ -2619,10 +2642,12 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, /* Start Drawing */ DRW_state_reset(); - DRW_hair_update(); + DRW_curves_update(); drw_engines_draw_scene(); + DRW_smoke_exit(DST.vmempool); + DRW_state_reset(); /* TODO: Reading depth for operators should be done here. */ @@ -3008,7 +3033,8 @@ void DRW_engines_free(void) GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer_depth_only); DRW_shaders_free(); - DRW_hair_free(); + DRW_curves_free(); + DRW_volume_free(); DRW_shape_cache_free(); DRW_stats_free(); DRW_globals_free(); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 832897b7040..8812f112014 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -527,6 +527,10 @@ typedef struct DRWData { struct GPUUniformBuf **obinfos_ubo; struct GHash *obattrs_ubo_pool; uint ubo_len; + /** Per draw-call volume object data. */ + void *volume_grids_ubos; /* VolumeUniformBufPool */ + /** List of smoke textures to free after drawing. */ + ListBase smoke_textures; /** Texture pool to reuse temp texture across engines. */ /* TODO(@fclem): The pool could be shared even between view-ports. */ struct DRWTexturePool *texture_pool; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 39f083aaf96..b5432da0957 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -15,6 +15,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_volume.h" #include "DNA_curve_types.h" #include "DNA_mesh_types.h" @@ -555,10 +556,19 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup, static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4]) { ID *ob_data = (ob) ? ob->data : NULL; + float loc[3], size[3]; float *texcoloc = NULL; float *texcosize = NULL; if (ob_data != NULL) { switch (GS(ob_data->name)) { + case ID_VO: { + BoundBox *bbox = BKE_volume_boundbox_get(ob); + mid_v3_v3v3(loc, bbox->vec[0], bbox->vec[6]); + sub_v3_v3v3(size, bbox->vec[0], bbox->vec[6]); + texcoloc = loc; + texcosize = size; + break; + } case ID_ME: BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize); break; diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c index 53da300c106..487a09d313d 100644 --- a/source/blender/draw/intern/draw_shader.c +++ b/source/blender/draw/intern/draw_shader.c @@ -92,6 +92,30 @@ GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement, return e_data.hair_refine_sh[refinement]; } +GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, eParticleRefineShaderType sh_type) +{ + /* TODO: Implement curves evaluation types (Bezier and Catmull Rom). */ + if (e_data.hair_refine_sh[type] == NULL) { + GPUShader *sh = NULL; + switch (sh_type) { + case PART_REFINE_SHADER_COMPUTE: + sh = hair_refine_shader_compute_create(type); + break; + case PART_REFINE_SHADER_TRANSFORM_FEEDBACK: + sh = hair_refine_shader_transform_feedback_create(type); + break; + case PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND: + sh = hair_refine_shader_transform_feedback_workaround_create(type); + break; + default: + BLI_assert_msg(0, "Incorrect shader type"); + } + e_data.hair_refine_sh[type] = sh; + } + + return e_data.hair_refine_sh[type]; +} + /** \} */ void DRW_shaders_free(void) diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h index 65b9cafc1d9..650e78c9362 100644 --- a/source/blender/draw/intern/draw_shader.h +++ b/source/blender/draw/intern/draw_shader.h @@ -7,6 +7,7 @@ #pragma once +#include "draw_curves_private.h" #include "draw_hair_private.h" #ifdef __cplusplus @@ -25,6 +26,10 @@ typedef enum eParticleRefineShaderType { struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement, eParticleRefineShaderType sh_type); + +struct GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, + eParticleRefineShaderType sh_type); + void DRW_shaders_free(void); #ifdef __cplusplus diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 58875c0496a..db128fffde7 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -6,12 +6,16 @@ typedef struct ViewInfos ViewInfos; typedef struct ObjectMatrices ObjectMatrices; typedef struct ObjectInfos ObjectInfos; +typedef struct VolumeInfos VolumeInfos; #endif #define DRW_SHADER_SHARED_H #define DRW_RESOURCE_CHUNK_LEN 512 +/* Define the maximum number of grid we allow in a volume UBO. */ +#define DRW_GRID_PER_VOLUME_MAX 16 + struct ViewInfos { /* View matrices */ float4x4 persmat; @@ -63,6 +67,18 @@ struct ObjectInfos { }; BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16) +struct VolumeInfos { + /* Object to grid-space. */ + float4x4 grids_xform[DRW_GRID_PER_VOLUME_MAX]; + /* NOTE: vec4 for alignment. Only float3 needed. */ + float4 color_mul; + float density_scale; + float temperature_mul; + float temperature_bias; + float _pad; +}; +BLI_STATIC_ASSERT_ALIGN(VolumeInfos, 16) + #define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) #define ObjectInfo (drw_infos[resource_id].drw_Infos) #define ObjectColor (drw_infos[resource_id].drw_ObjectColor) diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc new file mode 100644 index 00000000000..8d9a6f486e2 --- /dev/null +++ b/source/blender/draw/intern/draw_volume.cc @@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup draw + * + * \brief Contains Volume object GPU attributes configuration. + */ + +#include "DRW_gpu_wrapper.hh" +#include "DRW_render.h" + +#include "DNA_fluid_types.h" +#include "DNA_volume_types.h" + +#include "BKE_fluid.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_volume.h" +#include "BKE_volume_render.h" + +#include "GPU_material.h" + +#include "draw_common.h" +#include "draw_manager.h" + +using namespace blender; +using namespace blender::draw; +using VolumeInfosBuf = blender::draw::UniformBuffer<VolumeInfos>; + +static struct { + GPUTexture *dummy_zero; + GPUTexture *dummy_one; + float dummy_grid_mat[4][4]; +} g_data = {}; + +struct VolumeUniformBufPool { + Vector<VolumeInfosBuf *> ubos; + uint used = 0; + + ~VolumeUniformBufPool() + { + for (VolumeInfosBuf *ubo : ubos) { + delete ubo; + } + } + + void reset() + { + used = 0; + } + + VolumeInfosBuf *alloc() + { + if (used >= ubos.size()) { + VolumeInfosBuf *buf = new VolumeInfosBuf(); + ubos.append(buf); + return buf; + } + return ubos[used++]; + } +}; + +void DRW_volume_ubos_pool_free(void *pool) +{ + delete reinterpret_cast<VolumeUniformBufPool *>(pool); +} + +static void drw_volume_globals_init() +{ + const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const float one[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + g_data.dummy_zero = GPU_texture_create_3d( + "dummy_zero", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, zero); + g_data.dummy_one = GPU_texture_create_3d( + "dummy_one", 1, 1, 1, 1, GPU_RGBA8, GPU_DATA_FLOAT, one); + GPU_texture_wrap_mode(g_data.dummy_zero, true, true); + GPU_texture_wrap_mode(g_data.dummy_one, true, true); + + memset(g_data.dummy_grid_mat, 0, sizeof(g_data.dummy_grid_mat)); +} + +void DRW_volume_free(void) +{ + GPU_TEXTURE_FREE_SAFE(g_data.dummy_zero); + GPU_TEXTURE_FREE_SAFE(g_data.dummy_one); +} + +static GPUTexture *grid_default_texture(eGPUDefaultValue default_value) +{ + switch (default_value) { + case GPU_DEFAULT_0: + return g_data.dummy_zero; + case GPU_DEFAULT_1: + return g_data.dummy_one; + } + return g_data.dummy_zero; +} + +void DRW_volume_init(DRWData *drw_data) +{ + if (drw_data->volume_grids_ubos == nullptr) { + drw_data->volume_grids_ubos = new VolumeUniformBufPool(); + } + VolumeUniformBufPool *pool = (VolumeUniformBufPool *)drw_data->volume_grids_ubos; + pool->reset(); + + if (g_data.dummy_one == nullptr) { + drw_volume_globals_init(); + } +} + +static DRWShadingGroup *drw_volume_object_grids_init(Object *ob, + ListBase *attrs, + DRWShadingGroup *grp) +{ + VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos; + VolumeInfosBuf &volume_infos = *pool->alloc(); + + Volume *volume = (Volume *)ob->data; + BKE_volume_load(volume, G.main); + + grp = DRW_shgroup_create_sub(grp); + + volume_infos.density_scale = BKE_volume_density_scale(volume, ob->obmat); + volume_infos.color_mul = float4(1.0f); + volume_infos.temperature_mul = 1.0f; + volume_infos.temperature_bias = 0.0f; + + /* Bind volume grid textures. */ + int grid_id = 0; + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) { + const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr->name); + const DRWVolumeGrid *drw_grid = (volume_grid) ? + DRW_volume_batch_cache_get_grid(volume, volume_grid) : + nullptr; + + /* Handle 3 cases here: + * - Grid exists and texture was loaded -> use texture. + * - Grid exists but has zero size or failed to load -> use zero. + * - Grid does not exist -> use default value. */ + const GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture : + (volume_grid) ? g_data.dummy_zero : + grid_default_texture(attr->default_value); + DRW_shgroup_uniform_texture(grp, attr->input_name, grid_tex); + + copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), drw_grid->object_to_texture); + } + + volume_infos.push_update(); + + DRW_shgroup_uniform_block(grp, "drw_volume", volume_infos); + + return grp; +} + +static DRWShadingGroup *drw_volume_object_mesh_init(Scene *scene, + Object *ob, + ListBase *attrs, + DRWShadingGroup *grp) +{ + VolumeUniformBufPool *pool = (VolumeUniformBufPool *)DST.vmempool->volume_grids_ubos; + VolumeInfosBuf &volume_infos = *pool->alloc(); + + ModifierData *md = nullptr; + + volume_infos.density_scale = 1.0f; + volume_infos.color_mul = float4(1.0f); + volume_infos.temperature_mul = 1.0f; + volume_infos.temperature_bias = 0.0f; + + /* Smoke Simulation */ + if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) && + (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) && + ((FluidModifierData *)md)->domain != nullptr) { + FluidModifierData *fmd = (FluidModifierData *)md; + FluidDomainSettings *fds = fmd->domain; + + /* Don't try to show liquid domains here. */ + if (!fds->fluid || !(fds->type == FLUID_DOMAIN_TYPE_GAS)) { + return nullptr; + } + + if (fds->fluid && (fds->type == FLUID_DOMAIN_TYPE_GAS)) { + DRW_smoke_ensure(fmd, fds->flags & FLUID_DOMAIN_USE_NOISE); + } + + grp = DRW_shgroup_create_sub(grp); + + int grid_id = 0; + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) { + if (STREQ(attr->name, "density")) { + DRW_shgroup_uniform_texture_ref( + grp, attr->input_name, fds->tex_density ? &fds->tex_density : &g_data.dummy_one); + } + else if (STREQ(attr->name, "color")) { + DRW_shgroup_uniform_texture_ref( + grp, attr->input_name, fds->tex_color ? &fds->tex_color : &g_data.dummy_one); + } + else if (STR_ELEM(attr->name, "flame", "temperature")) { + DRW_shgroup_uniform_texture_ref( + grp, attr->input_name, fds->tex_flame ? &fds->tex_flame : &g_data.dummy_zero); + } + else { + DRW_shgroup_uniform_texture( + grp, attr->input_name, grid_default_texture(attr->default_value)); + } + copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), g_data.dummy_grid_mat); + } + + bool use_constant_color = ((fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && + (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); + if (use_constant_color) { + volume_infos.color_mul = float4(UNPACK3(fds->active_color), 1.0f); + } + + /* Output is such that 0..1 maps to 0..1000K */ + volume_infos.temperature_mul = fds->flame_max_temp - fds->flame_ignition; + volume_infos.temperature_bias = fds->flame_ignition; + } + else { + grp = DRW_shgroup_create_sub(grp); + + int grid_id = 0; + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) { + DRW_shgroup_uniform_texture( + grp, attr->input_name, grid_default_texture(attr->default_value)); + copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), g_data.dummy_grid_mat); + } + } + + volume_infos.push_update(); + + DRW_shgroup_uniform_block(grp, "drw_volume", volume_infos); + + return grp; +} + +static DRWShadingGroup *drw_volume_world_grids_init(ListBase *attrs, DRWShadingGroup *grp) +{ + /* Bind default volume grid textures. */ + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) { + DRW_shgroup_uniform_texture(grp, attr->input_name, grid_default_texture(attr->default_value)); + } + return grp; +} + +DRWShadingGroup *DRW_shgroup_volume_create_sub(Scene *scene, + Object *ob, + DRWShadingGroup *shgrp, + GPUMaterial *gpu_material) +{ + ListBase attrs = GPU_material_attributes(gpu_material); + + if (ob == nullptr) { + return drw_volume_world_grids_init(&attrs, shgrp); + } + if (ob->type == OB_VOLUME) { + return drw_volume_object_grids_init(ob, &attrs, shgrp); + } + return drw_volume_object_mesh_init(scene, ob, &attrs, shgrp); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index d52226a4c90..4cb68cad66c 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -173,7 +173,7 @@ static void extract_vcol_init(const MeshRenderData *mr, } BMIter iter; - const bool is_byte = ref.layer->type == CD_MLOOPCOL; + const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR; const bool is_point = ref.domain == ATTR_DOMAIN_POINT; BMFace *f; @@ -318,7 +318,7 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, BMIter iter; BMFace *f; int cd_ofs = cdata->layers[layer_i].offset; - const bool is_byte = ref.layer->type == CD_MLOOPCOL; + const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { BMLoop *l_iter = f->l_first; diff --git a/source/blender/draw/intern/shaders/common_attribute_lib.glsl b/source/blender/draw/intern/shaders/common_attribute_lib.glsl index 99db2929a13..30239a84c0c 100644 --- a/source/blender/draw/intern/shaders/common_attribute_lib.glsl +++ b/source/blender/draw/intern/shaders/common_attribute_lib.glsl @@ -19,3 +19,15 @@ vec4 attr_load_vec4(samplerBuffer attr); vec3 attr_load_vec3(samplerBuffer attr); vec2 attr_load_vec2(samplerBuffer attr); float attr_load_float(samplerBuffer attr); + +vec3 attr_load_orco(sampler3D orco); +vec4 attr_load_tangent(sampler3D tangent); +vec3 attr_load_uv(sampler3D attr); +vec4 attr_load_color(sampler3D tex); +vec4 attr_load_vec4(sampler3D tex); +vec3 attr_load_vec3(sampler3D tex); +vec2 attr_load_vec2(sampler3D tex); +float attr_load_float(sampler3D tex); + +float attr_load_temperature_post(float attr); +vec4 attr_load_color_post(vec4 attr); diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh index 392b016fc3b..c74a043ec97 100644 --- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh +++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh @@ -6,3 +6,7 @@ GPU_SHADER_CREATE_INFO(draw_object_infos) .typedef_source("draw_shader_shared.h") .define("OBINFO_LIB") .uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH); + +GPU_SHADER_CREATE_INFO(draw_volume_infos) + .typedef_source("draw_shader_shared.h") + .uniform_buf(2, "VolumeInfos", "drw_volume", Frequency::BATCH); |