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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/CMakeLists.txt16
-rw-r--r--source/blender/draw/DRW_select_buffer.h8
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c14
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h4
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders_extra.cc4
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.cc152
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.hh88
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_defines.hh8
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_engine.cc35
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc33
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.hh36
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.cc65
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.hh51
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_pipeline.cc29
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_pipeline.hh27
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.cc19
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.hh6
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh102
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.cc25
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.hh3
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.cc420
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.hh178
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.cc38
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh12
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.cc12
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl25
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl166
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl14
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl11
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl11
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl13
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl101
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl58
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh8
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh55
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c12
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c8
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/extra_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/volume_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh2
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl2
-rw-r--r--source/blender/draw/engines/select/shaders/infos/select_id_info.hh2
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c6
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c22
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh111
-rw-r--r--source/blender/draw/intern/DRW_render.h13
-rw-r--r--source/blender/draw/intern/draw_attributes.cc112
-rw-r--r--source/blender/draw/intern/draw_attributes.h60
-rw-r--r--source/blender/draw/intern/draw_cache.c3
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h15
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc8
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc299
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c157
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c54
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc59
-rw-r--r--source/blender/draw/intern/draw_common.h6
-rw-r--r--source/blender/draw/intern/draw_curves.cc220
-rw-r--r--source/blender/draw/intern/draw_curves_private.h29
-rw-r--r--source/blender/draw/intern/draw_hair.cc (renamed from source/blender/draw/intern/draw_hair.c)41
-rw-r--r--source/blender/draw/intern/draw_manager.c17
-rw-r--r--source/blender/draw/intern/draw_manager.h6
-rw-r--r--source/blender/draw/intern/draw_manager_data.c40
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c6
-rw-r--r--source/blender/draw/intern/draw_shader.cc (renamed from source/blender/draw/intern/draw_shader.c)32
-rw-r--r--source/blender/draw/intern/draw_shader.h2
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h14
-rw-r--r--source/blender/draw/intern/draw_subdivision.h8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc7
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc71
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc20
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc5
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc3
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl4
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl56
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh4
95 files changed, 2869 insertions, 625 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 1ff7585165b..3381dbadbab 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SRC
intern/mesh_extractors/extract_mesh_vbo_uv.cc
intern/mesh_extractors/extract_mesh_vbo_vcol.cc
intern/mesh_extractors/extract_mesh_vbo_weights.cc
+ intern/draw_attributes.cc
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_curves.cc
intern/draw_cache_impl_displist.c
@@ -85,7 +86,7 @@ set(SRC
intern/draw_curves.cc
intern/draw_debug.c
intern/draw_fluid.c
- intern/draw_hair.c
+ intern/draw_hair.cc
intern/draw_instance_data.c
intern/draw_manager.c
intern/draw_manager_data.c
@@ -95,7 +96,7 @@ set(SRC
intern/draw_manager_text.c
intern/draw_manager_texture.c
intern/draw_select_buffer.c
- intern/draw_shader.c
+ intern/draw_shader.cc
intern/draw_texture_pool.cc
intern/draw_view.c
intern/draw_view_data.cc
@@ -133,6 +134,7 @@ set(SRC
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
+ engines/eevee_next/eevee_camera.cc
engines/eevee_next/eevee_engine.cc
engines/eevee_next/eevee_instance.cc
engines/eevee_next/eevee_material.cc
@@ -140,6 +142,7 @@ set(SRC
engines/eevee_next/eevee_shader.cc
engines/eevee_next/eevee_sync.cc
engines/eevee_next/eevee_view.cc
+ engines/eevee_next/eevee_velocity.cc
engines/eevee_next/eevee_world.cc
engines/workbench/workbench_data.c
engines/workbench/workbench_effect_antialiasing.c
@@ -196,6 +199,7 @@ set(SRC
DRW_select_buffer.h
intern/DRW_gpu_wrapper.hh
intern/DRW_render.h
+ intern/draw_attributes.h
intern/draw_cache.h
intern/draw_cache_extract.h
intern/draw_cache_impl.h
@@ -352,6 +356,7 @@ set(GLSL_SRC
engines/eevee/shaders/world_vert.glsl
engines/eevee_next/shaders/eevee_attributes_lib.glsl
+ engines/eevee_next/shaders/eevee_camera_lib.glsl
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
@@ -362,6 +367,11 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
engines/eevee_next/shaders/eevee_surf_lib.glsl
engines/eevee_next/shaders/eevee_surf_world_frag.glsl
+ engines/eevee_next/shaders/eevee_velocity_lib.glsl
+ engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl
+
+ engines/eevee_next/eevee_defines.hh
+ engines/eevee_next/eevee_shader_shared.hh
engines/workbench/shaders/workbench_cavity_lib.glsl
engines/workbench/shaders/workbench_common_lib.glsl
@@ -422,8 +432,8 @@ set(GLSL_SRC
intern/shaders/common_subdiv_vbo_lnor_comp.glsl
intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
- intern/draw_shader_shared.h
intern/draw_common_shader_shared.h
+ intern/draw_shader_shared.h
engines/gpencil/shaders/gpencil_frag.glsl
engines/gpencil/shaders/gpencil_vert.glsl
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index 324ebebfbe6..5bc7aee92ba 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -9,6 +9,10 @@
#include "BLI_sys_types.h" /* for bool and uint */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ARegion;
struct Base;
struct Depsgraph;
@@ -133,3 +137,7 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
uint id_max,
uint *dist);
void DRW_select_buffer_context_create(struct Base **bases, uint bases_len, short select_mode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index b17efe4b68d..33063e14c03 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -68,7 +68,7 @@ BLI_INLINE int eevee_cryptomatte_layers_count(const ViewLayer *view_layer)
}
/* The number of render result passes are needed to store a single cryptomatte layer. Per
- * renderpass 2 cryptomatte samples can be stored. */
+ * render-pass 2 cryptomatte samples can be stored. */
BLI_INLINE int eevee_cryptomatte_passes_per_layer(const ViewLayer *view_layer)
{
const int num_cryptomatte_levels = view_layer->cryptomatte_levels;
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 4f562dd9804..7f722ff1764 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -95,7 +95,7 @@ typedef struct EEVEE_LightBake {
/** Target layer to store the data to. */
int layer;
/** Sample count for the convolution. */
- float samples_ct, invsamples_ct;
+ float samples_count, invsamples_count;
/** Sampling bias during convolution step. */
float lod_factor;
/** Max cube-map LOD to sample when convolving. */
@@ -282,14 +282,14 @@ static void irradiance_pool_size_get(int visibility_size, int total_samples, int
(visibility_size / IRRADIANCE_SAMPLE_SIZE_Y);
/* The irradiance itself take one layer, hence the +1 */
- int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
+ int layer_count = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
- int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1));
+ int texel_count = (int)ceilf((float)total_samples / (float)(layer_count - 1));
r_size[0] = visibility_size *
- max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ max_ii(1, min_ii(texel_count, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
r_size[1] = visibility_size *
- max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
- r_size[2] = layer_ct;
+ max_ii(1, (texel_count / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[2] = layer_count;
}
static bool EEVEE_lightcache_validate(const LightCache *light_cache,
@@ -1118,7 +1118,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
/* TODO: do this once for the whole bake when we have independent DRWManagers.
- * Warning: Some of the things above require this. */
+ * WARNING: Some of the things above require this. */
eevee_lightbake_cache_create(vedata, lbake);
/* Compute sample position */
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index 43d0b050cc8..a4bd789438d 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -112,7 +112,7 @@ void EEVEE_lookdev_init(EEVEE_Data *vedata)
if (sphere_size != effects->sphere_size || rect->xmax != effects->anchor[0] ||
rect->ymin != effects->anchor[1]) {
- /* Make sphere resolution adaptive to viewport_scale, dpi and lookdev_sphere_size */
+ /* Make sphere resolution adaptive to viewport_scale, DPI and #U.lookdev_sphere_size. */
float res_scale = clamp_f(
(U.lookdev_sphere_size / 400.0f) * viewport_scale * U.dpi_fac, 0.1f, 1.0f);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index b03a4fa70b4..0a7c8e185c4 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -301,7 +301,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *maxz_copydepth_ps;
struct DRWPass *maxz_copydepth_layer_ps;
- /* Renderpass Accumulation. */
+ /* Render-pass Accumulation. */
struct DRWPass *material_accum_ps;
struct DRWPass *background_accum_ps;
struct DRWPass *cryptomatte_ps;
@@ -1069,7 +1069,7 @@ typedef struct EEVEE_PrivateData {
GPUTexture *renderpass_col_input;
GPUTexture *renderpass_light_input;
GPUTexture *renderpass_transmittance_input;
- /* Renderpass ubo reference used by material pass. */
+ /* Render-pass UBO reference used by material pass. */
struct GPUUniformBuf *renderpass_ubo;
/** For rendering shadows. */
struct DRWView *cube_views[6];
diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
index 05577944140..216a15de2b9 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
+++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
@@ -118,6 +118,10 @@ void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
info.vertex_inputs_.clear();
}
+ if (is_hair) {
+ info.additional_info("draw_curves_infos");
+ }
+
if (!is_volume) {
info.define("EEVEE_GENERATED_INTERFACE");
info.vertex_out(*stage_interface);
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 5295a05b965..2926f8c5a89 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -65,6 +65,22 @@ vec3 attr_load_orco(samplerBuffer cd_buf)
}
# endif
+/* Per attribute scope follows loading order. */
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = hairStrandID;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported. */
@@ -73,22 +89,22 @@ vec4 attr_load_tangent(samplerBuffer cd_buf)
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
#else
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 81f73979723..8e1bafe8d92 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -201,4 +201,4 @@ vec3 coordinate_incoming(vec3 P)
#else
return cameraVec(P);
#endif
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 04f38978076..a8e95e13b12 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -72,6 +72,22 @@ vec3 attr_load_orco(samplerBuffer cd_buf)
}
# endif
+/* Per attribute scope follows loading order. */
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = hairStrandID;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
return vec4(hairTangent, 1.0);
@@ -79,22 +95,22 @@ vec4 attr_load_tangent(samplerBuffer cd_buf)
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, hairStrandID).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
#else
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index d6eeedd8640..a81d37f4e6f 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -8,7 +8,7 @@
flat in int slice;
-/* Warning: these are not attributes, these are global vars. */
+/* WARNING: these are not attributes, these are global vars. */
vec3 worldPosition = vec3(0.0);
vec3 objectPosition = vec3(0.0);
vec3 viewPosition = vec3(0.0);
@@ -80,8 +80,8 @@ void main()
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.
- * adding return after discard ensures consistent behaviour and avoids GPU
+ /* NOTE: Discard is not an explicit return in Metal prior to versions 2.3.
+ * adding return after discard ensures consistent behavior and avoids GPU
* side-effects where control flow continues with undefined values. */
discard;
return;
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 527bbd18896..3ce54b3122a 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -70,7 +70,7 @@ void main()
vec3 Tr = exp(-s_extinction * s_len);
/* integrate along the current step segment */
- /* Note: Original calculation carries precision issues when compiling for AMD GPUs
+ /* NOTE: Original calculation carries precision issues when compiling for AMD GPUs
* and running Metal. This version of the equation retains precision well for all
* macOS HW configurations. */
Lscat = (Lscat * (1.0f - Tr)) / max(vec3(1e-8), s_extinction);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index ce863bdf660..186f438b03b 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -76,4 +76,4 @@ vec3 coordinate_reflect(vec3 P, vec3 N)
vec3 coordinate_incoming(vec3 P)
{
return vec3(0.0);
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.cc b/source/blender/draw/engines/eevee_next/eevee_camera.cc
new file mode 100644
index 00000000000..e6d2e2db764
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.cc
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ */
+
+#include <array>
+
+#include "DRW_render.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_camera.h"
+#include "DEG_depsgraph_query.h"
+#include "RE_pipeline.h"
+
+#include "eevee_camera.hh"
+#include "eevee_instance.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+void Camera::init()
+{
+ const Object *camera_eval = inst_.camera_eval_object;
+ synced_ = false;
+ data_.swap();
+
+ CameraData &data = data_.current();
+
+ if (camera_eval) {
+ const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
+ switch (cam->type) {
+ default:
+ case CAM_PERSP:
+ data.type = CAMERA_PERSP;
+ break;
+ case CAM_ORTHO:
+ data.type = CAMERA_ORTHO;
+ break;
+#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
+ case CAM_PANO: {
+ switch (cam->panorama_type) {
+ default:
+ case CAM_PANO_EQUIRECTANGULAR:
+ data.type = CAMERA_PANO_EQUIRECT;
+ break;
+ case CAM_PANO_FISHEYE_EQUIDISTANT:
+ data.type = CAMERA_PANO_EQUIDISTANT;
+ break;
+ case CAM_PANO_FISHEYE_EQUISOLID:
+ data.type = CAMERA_PANO_EQUISOLID;
+ break;
+ case CAM_PANO_MIRRORBALL:
+ data.type = CAMERA_PANO_MIRROR;
+ break;
+ }
+ }
+#endif
+ }
+ }
+ else if (inst_.drw_view) {
+ data.type = DRW_view_is_persp_get(inst_.drw_view) ? CAMERA_PERSP : CAMERA_ORTHO;
+ }
+ else {
+ /* Light-probe baking. */
+ data.type = CAMERA_PERSP;
+ }
+}
+
+void Camera::sync()
+{
+ const Object *camera_eval = inst_.camera_eval_object;
+ CameraData &data = data_.current();
+
+ data.filter_size = inst_.scene->r.gauss;
+
+ if (inst_.drw_view) {
+ DRW_view_viewmat_get(inst_.drw_view, data.viewmat.ptr(), false);
+ DRW_view_viewmat_get(inst_.drw_view, data.viewinv.ptr(), true);
+ DRW_view_winmat_get(inst_.drw_view, data.winmat.ptr(), false);
+ DRW_view_winmat_get(inst_.drw_view, data.wininv.ptr(), true);
+ DRW_view_persmat_get(inst_.drw_view, data.persmat.ptr(), false);
+ DRW_view_persmat_get(inst_.drw_view, data.persinv.ptr(), true);
+ DRW_view_camtexco_get(inst_.drw_view, data.uv_scale);
+ }
+ else if (inst_.render) {
+ /* TODO(@fclem): Over-scan. */
+ // RE_GetCameraWindowWithOverscan(inst_.render->re, g_data->overscan, data.winmat);
+ RE_GetCameraWindow(inst_.render->re, camera_eval, data.winmat.ptr());
+ RE_GetCameraModelMatrix(inst_.render->re, camera_eval, data.viewinv.ptr());
+ invert_m4_m4(data.viewmat.ptr(), data.viewinv.ptr());
+ invert_m4_m4(data.wininv.ptr(), data.winmat.ptr());
+ mul_m4_m4m4(data.persmat.ptr(), data.winmat.ptr(), data.viewmat.ptr());
+ invert_m4_m4(data.persinv.ptr(), data.persmat.ptr());
+ data.uv_scale = float2(1.0f);
+ data.uv_bias = float2(0.0f);
+ }
+ else {
+ data.viewmat = float4x4::identity();
+ data.viewinv = float4x4::identity();
+ perspective_m4(data.winmat.ptr(), -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f);
+ data.wininv = data.winmat.inverted();
+ data.persmat = data.winmat * data.viewmat;
+ data.persinv = data.persmat.inverted();
+ }
+
+ if (camera_eval) {
+ const ::Camera *cam = reinterpret_cast<const ::Camera *>(camera_eval->data);
+ data.clip_near = cam->clip_start;
+ data.clip_far = cam->clip_end;
+#if 0 /* TODO(fclem): Make fisheye properties inside blender. */
+ data.fisheye_fov = cam->fisheye_fov;
+ data.fisheye_lens = cam->fisheye_lens;
+ data.equirect_bias.x = -cam->longitude_min + M_PI_2;
+ data.equirect_bias.y = -cam->latitude_min + M_PI_2;
+ data.equirect_scale.x = cam->longitude_min - cam->longitude_max;
+ data.equirect_scale.y = cam->latitude_min - cam->latitude_max;
+ /* Combine with uv_scale/bias to avoid doing extra computation. */
+ data.equirect_bias += data.uv_bias * data.equirect_scale;
+ data.equirect_scale *= data.uv_scale;
+
+ data.equirect_scale_inv = 1.0f / data.equirect_scale;
+#endif
+ }
+ else if (inst_.drw_view) {
+ data.clip_near = DRW_view_near_distance_get(inst_.drw_view);
+ data.clip_far = DRW_view_far_distance_get(inst_.drw_view);
+ data.fisheye_fov = data.fisheye_lens = -1.0f;
+ data.equirect_bias = float2(0.0f);
+ data.equirect_scale = float2(0.0f);
+ }
+
+ data_.current().push_update();
+
+ synced_ = true;
+
+ /* Detect changes in parameters. */
+ if (data_.current() != data_.previous()) {
+ // inst_.sampling.reset();
+ }
+}
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh
index 3db343703e0..dfec738b1f3 100644
--- a/source/blender/draw/engines/eevee_next/eevee_camera.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh
@@ -1,11 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2021 Blender Foundation.
- */
+ * Copyright 2021 Blender Foundation. */
+
+#pragma once
/** \file
* \ingroup eevee
*/
+#include "eevee_shader_shared.hh"
+
namespace blender::eevee {
class Instance;
@@ -43,4 +46,85 @@ static const float cubeface_mat[6][4][4] = {
{0.0f, 0.0f, 0.0f, 1.0f}},
};
+inline void cubeface_winmat_get(float4x4 &winmat, float near, float far)
+{
+ /* Simple 90° FOV projection. */
+ perspective_m4(winmat.ptr(), -near, near, -near, near, near, far);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name CameraData operators
+ * \{ */
+
+inline bool operator==(const CameraData &a, const CameraData &b)
+{
+ return compare_m4m4(a.persmat.ptr(), b.persmat.ptr(), FLT_MIN) && (a.uv_scale == b.uv_scale) &&
+ (a.uv_bias == b.uv_bias) && (a.equirect_scale == b.equirect_scale) &&
+ (a.equirect_bias == b.equirect_bias) && (a.fisheye_fov == b.fisheye_fov) &&
+ (a.fisheye_lens == b.fisheye_lens) && (a.filter_size == b.filter_size) &&
+ (a.type == b.type);
+}
+
+inline bool operator!=(const CameraData &a, const CameraData &b)
+{
+ return !(a == b);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+/**
+ * Point of view in the scene. Can be init from viewport or camera object.
+ */
+class Camera {
+ private:
+ Instance &inst_;
+
+ /** Double buffered to detect changes and have history for re-projection. */
+ SwapChain<CameraDataBuf, 2> data_;
+ /** Detects wrong usage. */
+ bool synced_ = false;
+
+ public:
+ Camera(Instance &inst) : inst_(inst){};
+ ~Camera(){};
+
+ void init();
+ void sync();
+
+ /**
+ * Getters
+ **/
+ const CameraData &data_get() const
+ {
+ BLI_assert(synced_);
+ return data_.current();
+ }
+ const GPUUniformBuf *ubo_get() const
+ {
+ return data_.current();
+ }
+ bool is_panoramic() const
+ {
+ return eevee::is_panoramic(data_.current().type);
+ }
+ bool is_orthographic() const
+ {
+ return data_.current().type == CAMERA_ORTHO;
+ }
+ const float3 &position() const
+ {
+ return *reinterpret_cast<const float3 *>(data_.current().viewinv[3]);
+ }
+ const float3 &forward() const
+ {
+ return *reinterpret_cast<const float3 *>(data_.current().viewinv[2]);
+ }
+};
+
+/** \} */
+
} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh
index 35eb33671db..7141928a20d 100644
--- a/source/blender/draw/engines/eevee_next/eevee_defines.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh
@@ -11,9 +11,11 @@
#pragma once
-/* Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536. */
-/* Current limiting factor is the sorting phase which is single pass and only sort within a
- * threadgroup which maximum size is 1024. */
+/**
+ Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536.
+ * Current limiting factor is the sorting phase which is single pass and only sort within a
+ * thread-group which maximum size is 1024.
+ */
#define CULLING_BATCH_SIZE 1024
/**
diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.cc b/source/blender/draw/engines/eevee_next/eevee_engine.cc
index a7d183c1c88..be0adfad568 100644
--- a/source/blender/draw/engines/eevee_next/eevee_engine.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_engine.cc
@@ -5,6 +5,7 @@
#include "BKE_global.h"
#include "BLI_rect.h"
+#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "ED_view3d.h"
@@ -24,10 +25,17 @@ struct EEVEE_Data {
DRWViewportEmptyList *psl;
DRWViewportEmptyList *stl;
eevee::Instance *instance;
+
+ char info[GPU_INFO_SIZE];
};
static void eevee_engine_init(void *vedata)
{
+ /* TODO(fclem): Remove once it is minimum required. */
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
+
EEVEE_Data *ved = reinterpret_cast<EEVEE_Data *>(vedata);
if (ved->instance == nullptr) {
ved->instance = new eevee::Instance();
@@ -81,31 +89,50 @@ static void eevee_engine_init(void *vedata)
static void eevee_draw_scene(void *vedata)
{
+ EEVEE_Data *ved = reinterpret_cast<EEVEE_Data *>(vedata);
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ STRNCPY(ved->info, "Error: No shader storage buffer support");
+ return;
+ }
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- reinterpret_cast<EEVEE_Data *>(vedata)->instance->draw_viewport(dfbl);
+ ved->instance->draw_viewport(dfbl);
+ STRNCPY(ved->info, ved->instance->info.c_str());
}
static void eevee_cache_init(void *vedata)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
reinterpret_cast<EEVEE_Data *>(vedata)->instance->begin_sync();
}
static void eevee_cache_populate(void *vedata, Object *object)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
reinterpret_cast<EEVEE_Data *>(vedata)->instance->object_sync(object);
}
static void eevee_cache_finish(void *vedata)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
reinterpret_cast<EEVEE_Data *>(vedata)->instance->end_sync();
}
static void eevee_engine_free()
{
+ eevee::ShaderModule::module_free();
}
static void eevee_instance_free(void *instance)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
delete reinterpret_cast<eevee::Instance *>(instance);
}
@@ -114,11 +141,17 @@ static void eevee_render_to_image(void *UNUSED(vedata),
struct RenderLayer *layer,
const struct rcti *UNUSED(rect))
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
UNUSED_VARS(engine, layer);
}
static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
{
+ if (!GPU_shader_storage_buffer_objects_support()) {
+ return;
+ }
UNUSED_VARS(engine, scene, view_layer);
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc
index 922f6c9e1ae..606630bcdef 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc
@@ -8,6 +8,8 @@
* An instance contains all structures needed to do a complete render.
*/
+#include <sstream>
+
#include "BKE_global.h"
#include "BKE_object.h"
#include "BLI_rect.h"
@@ -21,9 +23,9 @@
namespace blender::eevee {
/* -------------------------------------------------------------------- */
-/** \name Init
+/** \name Initialization
*
- * Init funcions need to be called once at the start of a frame.
+ * Initialization functions need to be called once at the start of a frame.
* Active camera, render extent and enabled render passes are immutable until next init.
* This takes care of resizing output buffers and view in case a parameter changed.
* IMPORTANT: xxx.init() functions are NOT meant to acquire and allocate DRW resources.
@@ -41,26 +43,36 @@ void Instance::init(const int2 &output_res,
const View3D *v3d_,
const RegionView3D *rv3d_)
{
- UNUSED_VARS(light_probe_, camera_object_, output_rect);
+ UNUSED_VARS(light_probe_, output_rect);
render = render_;
depsgraph = depsgraph_;
+ camera_orig_object = camera_object_;
render_layer = render_layer_;
drw_view = drw_view_;
v3d = v3d_;
rv3d = rv3d_;
+ info = "";
+
update_eval_members();
main_view.init(output_res);
}
+void Instance::set_time(float time)
+{
+ BLI_assert(render);
+ DRW_render_set_time(render, depsgraph, floorf(time), fractf(time));
+ update_eval_members();
+}
+
void Instance::update_eval_members()
{
scene = DEG_get_evaluated_scene(depsgraph);
view_layer = DEG_get_evaluated_view_layer(depsgraph);
- // camera_eval_object = (camera_orig_object) ?
- // DEG_get_evaluated_object(depsgraph, camera_orig_object) :
- // nullptr;
+ camera_eval_object = (camera_orig_object) ?
+ DEG_get_evaluated_object(depsgraph, camera_orig_object) :
+ nullptr;
}
/** \} */
@@ -76,6 +88,7 @@ void Instance::update_eval_members()
void Instance::begin_sync()
{
materials.begin_sync();
+ velocity.begin_sync();
pipelines.sync();
main_view.sync();
@@ -135,6 +148,7 @@ void Instance::object_sync(Object *ob)
void Instance::end_sync()
{
+ velocity.end_sync();
}
void Instance::render_sync()
@@ -171,6 +185,13 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl)
{
UNUSED_VARS(dfbl);
render_sample();
+ velocity.step_swap();
+
+ if (materials.queued_shaders_count > 0) {
+ std::stringstream ss;
+ ss << "Compiling Shaders " << materials.queued_shaders_count;
+ info = ss.str();
+ }
}
/** \} */
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh
index c3cf08c8390..84be59fc5f0 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh
@@ -15,6 +15,7 @@
#include "DNA_lightprobe_types.h"
#include "DRW_render.h"
+#include "eevee_camera.hh"
#include "eevee_material.hh"
#include "eevee_pipeline.hh"
#include "eevee_shader.hh"
@@ -29,11 +30,15 @@ namespace blender::eevee {
* \brief A running instance of the engine.
*/
class Instance {
+ friend VelocityModule;
+
public:
ShaderModule &shaders;
SyncModule sync;
MaterialModule materials;
PipelineModule pipelines;
+ VelocityModule velocity;
+ Camera camera;
MainView main_view;
World world;
@@ -42,6 +47,8 @@ class Instance {
/** Evaluated IDs. */
Scene *scene;
ViewLayer *view_layer;
+ Object *camera_eval_object;
+ Object *camera_orig_object;
/** Only available when rendering for final render. */
const RenderLayer *render_layer;
RenderEngine *render;
@@ -51,7 +58,7 @@ class Instance {
const RegionView3D *rv3d;
/* Info string displayed at the top of the render / viewport. */
- char info[64];
+ std::string info = "";
public:
Instance()
@@ -59,6 +66,8 @@ class Instance {
sync(*this),
materials(*this),
pipelines(*this),
+ velocity(*this),
+ camera(*this),
main_view(*this),
world(*this){};
~Instance(){};
@@ -83,12 +92,37 @@ class Instance {
void draw_viewport(DefaultFramebufferList *dfbl);
+ bool is_viewport(void)
+ {
+ return !DRW_state_is_scene_render();
+ }
+
+ bool use_scene_lights(void) const
+ {
+ return (!v3d) ||
+ ((v3d->shading.type == OB_MATERIAL) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER));
+ }
+
+ /* Light the scene using the selected HDRI in the viewport shading pop-over. */
+ bool use_studio_light(void) const
+ {
+ return (v3d) && (((v3d->shading.type == OB_MATERIAL) &&
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD) == 0)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)));
+ }
+
private:
void render_sample();
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
void update_eval_members();
+
+ void set_time(float time);
};
} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc
index 7452e5c26a4..1676c89d679 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_material.cc
@@ -51,7 +51,6 @@ DefaultSurfaceNodeTree::~DefaultSurfaceNodeTree()
MEM_SAFE_FREE(ntree_);
}
-/* Configure a default nodetree with the given material. */
bNodeTree *DefaultSurfaceNodeTree::nodetree_get(::Material *ma)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
@@ -75,11 +74,11 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
{
bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
- diffuse_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default diffuse");
- diffuse_mat_->nodetree = ntree;
- diffuse_mat_->use_nodes = true;
+ diffuse_mat = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default diffuse");
+ diffuse_mat->nodetree = ntree;
+ diffuse_mat->use_nodes = true;
/* To use the forward pipeline. */
- diffuse_mat_->blend_method = MA_BM_BLEND;
+ diffuse_mat->blend_method = MA_BM_BLEND;
bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_DIFFUSE);
bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
@@ -98,11 +97,11 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
{
bNodeTree *ntree = ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
- glossy_mat_ = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default metal");
- glossy_mat_->nodetree = ntree;
- glossy_mat_->use_nodes = true;
+ glossy_mat = (::Material *)BKE_id_new_nomain(ID_MA, "EEVEE default metal");
+ glossy_mat->nodetree = ntree;
+ glossy_mat->use_nodes = true;
/* To use the forward pipeline. */
- glossy_mat_->blend_method = MA_BM_BLEND;
+ glossy_mat->blend_method = MA_BM_BLEND;
bNode *bsdf = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_GLOSSY);
bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
@@ -149,14 +148,14 @@ MaterialModule::~MaterialModule()
for (Material *mat : material_map_.values()) {
delete mat;
}
- BKE_id_free(nullptr, glossy_mat_);
- BKE_id_free(nullptr, diffuse_mat_);
+ BKE_id_free(nullptr, glossy_mat);
+ BKE_id_free(nullptr, diffuse_mat);
BKE_id_free(nullptr, error_mat_);
}
void MaterialModule::begin_sync()
{
- queued_shaders_count_ = 0;
+ queued_shaders_count = 0;
for (Material *mat : material_map_.values()) {
mat->init = false;
@@ -180,7 +179,7 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
case GPU_MAT_SUCCESS:
break;
case GPU_MAT_QUEUED:
- queued_shaders_count_++;
+ queued_shaders_count++;
blender_mat = (geometry_type == MAT_GEOM_VOLUME) ? BKE_material_default_volume() :
BKE_material_default_surface();
matpass.gpumat = inst_.shaders.material_shader_get(
@@ -223,7 +222,7 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
/* IMPORTANT: We always create a subgroup so that all subgroups are inserted after the
* first "empty" shgroup. This avoids messing the order of subgroups when there is more
* nested subgroup (i.e: hair drawing). */
- /* TODO(fclem) Remove material resource binding from the first group creation. */
+ /* TODO(@fclem): Remove material resource binding from the first group creation. */
matpass.shgrp = DRW_shgroup_create_sub(grp);
DRW_shgroup_add_material_resources(matpass.shgrp, matpass.gpumat);
}
@@ -232,21 +231,25 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
return matpass;
}
-Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeometry geometry_type)
+Material &MaterialModule::material_sync(::Material *blender_mat,
+ eMaterialGeometry geometry_type,
+ bool has_motion)
{
eMaterialPipeline surface_pipe = (blender_mat->blend_method == MA_BM_BLEND) ? MAT_PIPE_FORWARD :
MAT_PIPE_DEFERRED;
eMaterialPipeline prepass_pipe = (blender_mat->blend_method == MA_BM_BLEND) ?
- MAT_PIPE_FORWARD_PREPASS :
- MAT_PIPE_DEFERRED_PREPASS;
+ (has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY :
+ MAT_PIPE_FORWARD_PREPASS) :
+ (has_motion ? MAT_PIPE_DEFERRED_PREPASS_VELOCITY :
+ MAT_PIPE_DEFERRED_PREPASS);
- /* Test */
+ /* TEST until we have deferred pipeline up and running. */
surface_pipe = MAT_PIPE_FORWARD;
- prepass_pipe = MAT_PIPE_FORWARD_PREPASS;
+ prepass_pipe = has_motion ? MAT_PIPE_FORWARD_PREPASS_VELOCITY : MAT_PIPE_FORWARD_PREPASS;
MaterialKey material_key(blender_mat, geometry_type, surface_pipe);
- /* TODO allocate in blocks to avoid memory fragmentation. */
+ /* TODO: allocate in blocks to avoid memory fragmentation. */
auto add_cb = [&]() { return new Material(); };
Material &mat = *material_map_.lookup_or_add_cb(material_key, add_cb);
@@ -270,7 +273,6 @@ Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeomet
return mat;
}
-/* Return correct material or empty default material if slot is empty. */
::Material *MaterialModule::material_from_slot(Object *ob, int slot)
{
if (ob->base_flag & BASE_HOLDOUT) {
@@ -281,16 +283,12 @@ Material &MaterialModule::material_sync(::Material *blender_mat, eMaterialGeomet
if (ob->type == OB_VOLUME) {
return BKE_material_default_volume();
}
- else {
- return BKE_material_default_surface();
- }
+ return BKE_material_default_surface();
}
return ma;
}
-/* Returned Material references are valid until the next call to this function or
- * material_get(). */
-MaterialArray &MaterialModule::material_array_get(Object *ob)
+MaterialArray &MaterialModule::material_array_get(Object *ob, bool has_motion)
{
material_array_.materials.clear();
material_array_.gpu_materials.clear();
@@ -299,22 +297,23 @@ MaterialArray &MaterialModule::material_array_get(Object *ob)
for (auto i : IndexRange(materials_len)) {
::Material *blender_mat = material_from_slot(ob, i);
- Material &mat = material_sync(blender_mat, to_material_geometry(ob));
+ Material &mat = material_sync(blender_mat, to_material_geometry(ob), has_motion);
material_array_.materials.append(&mat);
material_array_.gpu_materials.append(mat.shading.gpumat);
}
return material_array_;
}
-/* Returned Material references are valid until the next call to this function or
- * material_array_get(). */
-Material &MaterialModule::material_get(Object *ob, int mat_nr, eMaterialGeometry geometry_type)
+Material &MaterialModule::material_get(Object *ob,
+ bool has_motion,
+ int mat_nr,
+ eMaterialGeometry geometry_type)
{
::Material *blender_mat = material_from_slot(ob, mat_nr);
- Material &mat = material_sync(blender_mat, geometry_type);
+ Material &mat = material_sync(blender_mat, geometry_type, has_motion);
return mat;
}
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh
index 56f9b077f7a..23165a741b9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_material.hh
@@ -27,19 +27,21 @@ class Instance;
enum eMaterialPipeline {
MAT_PIPE_DEFERRED = 0,
- MAT_PIPE_FORWARD = 1,
- MAT_PIPE_DEFERRED_PREPASS = 2,
- MAT_PIPE_FORWARD_PREPASS = 3,
- MAT_PIPE_VOLUME = 4,
- MAT_PIPE_SHADOW = 5,
+ MAT_PIPE_FORWARD,
+ MAT_PIPE_DEFERRED_PREPASS,
+ MAT_PIPE_DEFERRED_PREPASS_VELOCITY,
+ MAT_PIPE_FORWARD_PREPASS,
+ MAT_PIPE_FORWARD_PREPASS_VELOCITY,
+ MAT_PIPE_VOLUME,
+ MAT_PIPE_SHADOW,
};
enum eMaterialGeometry {
MAT_GEOM_MESH = 0,
- MAT_GEOM_CURVES = 1,
- MAT_GEOM_GPENCIL = 2,
- MAT_GEOM_VOLUME = 3,
- MAT_GEOM_WORLD = 4,
+ MAT_GEOM_CURVES,
+ MAT_GEOM_GPENCIL,
+ MAT_GEOM_VOLUME,
+ MAT_GEOM_WORLD,
};
static inline void material_type_from_shader_uuid(uint64_t shader_uuid,
@@ -104,7 +106,7 @@ static inline eMaterialGeometry to_material_geometry(const Object *ob)
}
}
-/** Unique key to identify each material in the hashmap. */
+/** Unique key to identify each material in the hash-map. */
struct MaterialKey {
Material *mat;
uint64_t options;
@@ -169,7 +171,7 @@ struct ShaderKey {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Default Material Nodetree
+/** \name Default Material Node-Tree
*
* In order to support materials without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the Material even if
@@ -189,6 +191,7 @@ class DefaultSurfaceNodeTree {
DefaultSurfaceNodeTree();
~DefaultSurfaceNodeTree();
+ /** Configure a default node-tree with the given material. */
bNodeTree *nodetree_get(::Material *ma);
};
@@ -217,8 +220,10 @@ struct MaterialArray {
class MaterialModule {
public:
- ::Material *diffuse_mat_;
- ::Material *glossy_mat_;
+ ::Material *diffuse_mat;
+ ::Material *glossy_mat;
+
+ int64_t queued_shaders_count = 0;
private:
Instance &inst_;
@@ -232,20 +237,28 @@ class MaterialModule {
::Material *error_mat_;
- int64_t queued_shaders_count_ = 0;
-
public:
MaterialModule(Instance &inst);
~MaterialModule();
void begin_sync();
- MaterialArray &material_array_get(Object *ob);
- Material &material_get(Object *ob, int mat_nr, eMaterialGeometry geometry_type);
+ /**
+ * Returned Material references are valid until the next call to this function or material_get().
+ */
+ MaterialArray &material_array_get(Object *ob, bool has_motion);
+ /**
+ * Returned Material references are valid until the next call to this function or
+ * material_array_get().
+ */
+ Material &material_get(Object *ob, bool has_motion, int mat_nr, eMaterialGeometry geometry_type);
private:
- Material &material_sync(::Material *blender_mat, eMaterialGeometry geometry_type);
+ Material &material_sync(::Material *blender_mat,
+ eMaterialGeometry geometry_type,
+ bool has_motion);
+ /** Return correct material or empty default material if slot is empty. */
::Material *material_from_slot(Object *ob, int slot);
MaterialPass material_pass_get(::Material *blender_mat,
eMaterialPipeline pipeline_type,
@@ -254,4 +267,4 @@ class MaterialModule {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
index e31372e770d..33853eba06c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
@@ -54,11 +54,17 @@ void ForwardPipeline::sync()
{
DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
prepass_ps_ = DRW_pass_create("Forward.Opaque.Prepass", state);
+ prepass_velocity_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Velocity",
+ state | DRW_STATE_WRITE_COLOR);
state |= DRW_STATE_CULL_BACK;
prepass_culled_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Culled", state);
+ prepass_culled_velocity_ps_ = DRW_pass_create("Forward.Opaque.Prepass.Velocity",
+ state | DRW_STATE_WRITE_COLOR);
- DRW_pass_link(prepass_ps_, prepass_culled_ps_);
+ DRW_pass_link(prepass_ps_, prepass_velocity_ps_);
+ DRW_pass_link(prepass_velocity_ps_, prepass_culled_ps_);
+ DRW_pass_link(prepass_culled_ps_, prepass_culled_velocity_ps_);
}
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
@@ -110,11 +116,17 @@ DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, G
return grp;
}
-DRWShadingGroup *ForwardPipeline::prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat)
+DRWShadingGroup *ForwardPipeline::prepass_opaque_add(::Material *blender_mat,
+ GPUMaterial *gpumat,
+ bool has_motion)
{
- DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? prepass_culled_ps_ :
- prepass_ps_;
+ DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ?
+ (has_motion ? prepass_culled_velocity_ps_ : prepass_culled_ps_) :
+ (has_motion ? prepass_velocity_ps_ : prepass_ps_);
DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, pass);
+ if (has_motion) {
+ inst_.velocity.bind_resources(grp);
+ }
return grp;
}
@@ -181,15 +193,19 @@ DRWShadingGroup *ForwardPipeline::prepass_transparent_add(::Material *blender_ma
}
void ForwardPipeline::render(const DRWView *view,
+ Framebuffer &prepass_fb,
+ Framebuffer &combined_fb,
GPUTexture *depth_tx,
GPUTexture *UNUSED(combined_tx))
{
- UNUSED_VARS(view, depth_tx);
+ UNUSED_VARS(view, depth_tx, prepass_fb, combined_fb);
// HiZBuffer &hiz = inst_.hiz_front;
DRW_stats_group_start("ForwardOpaque");
+ GPU_framebuffer_bind(prepass_fb);
DRW_draw_pass(prepass_ps_);
+
// hiz.set_dirty();
// if (inst_.raytracing.enabled()) {
@@ -199,6 +215,7 @@ void ForwardPipeline::render(const DRWView *view,
// inst_.shadows.set_view(view, depth_tx);
+ GPU_framebuffer_bind(combined_fb);
DRW_draw_pass(opaque_ps_);
DRW_stats_group_end();
@@ -218,4 +235,4 @@ void ForwardPipeline::render(const DRWView *view,
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh
index a5a6847f62e..3bdc718767b 100644
--- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh
@@ -53,7 +53,9 @@ class ForwardPipeline {
Instance &inst_;
DRWPass *prepass_ps_ = nullptr;
+ DRWPass *prepass_velocity_ps_ = nullptr;
DRWPass *prepass_culled_ps_ = nullptr;
+ DRWPass *prepass_culled_velocity_ps_ = nullptr;
DRWPass *opaque_ps_ = nullptr;
DRWPass *opaque_culled_ps_ = nullptr;
DRWPass *transparent_ps_ = nullptr;
@@ -72,19 +74,25 @@ class ForwardPipeline {
material_opaque_add(blender_mat, gpumat);
}
- DRWShadingGroup *prepass_add(::Material *blender_mat, GPUMaterial *gpumat)
+ DRWShadingGroup *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion)
{
return (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) ?
prepass_transparent_add(blender_mat, gpumat) :
- prepass_opaque_add(blender_mat, gpumat);
+ prepass_opaque_add(blender_mat, gpumat, has_motion);
}
DRWShadingGroup *material_opaque_add(::Material *blender_mat, GPUMaterial *gpumat);
- DRWShadingGroup *prepass_opaque_add(::Material *blender_mat, GPUMaterial *gpumat);
+ DRWShadingGroup *prepass_opaque_add(::Material *blender_mat,
+ GPUMaterial *gpumat,
+ bool has_motion);
DRWShadingGroup *material_transparent_add(::Material *blender_mat, GPUMaterial *gpumat);
DRWShadingGroup *prepass_transparent_add(::Material *blender_mat, GPUMaterial *gpumat);
- void render(const DRWView *view, GPUTexture *depth_tx, GPUTexture *combined_tx);
+ void render(const DRWView *view,
+ Framebuffer &prepass_fb,
+ Framebuffer &combined_fb,
+ GPUTexture *depth_tx,
+ GPUTexture *combined_tx);
};
/** \} */
@@ -191,10 +199,15 @@ class PipelineModule {
{
switch (pipeline_type) {
case MAT_PIPE_DEFERRED_PREPASS:
- // return deferred.prepass_add(blender_mat, gpumat);
+ // return deferred.prepass_add(blender_mat, gpumat, false);
+ break;
+ case MAT_PIPE_DEFERRED_PREPASS_VELOCITY:
+ // return deferred.prepass_add(blender_mat, gpumat, true);
break;
case MAT_PIPE_FORWARD_PREPASS:
- return forward.prepass_add(blender_mat, gpumat);
+ return forward.prepass_add(blender_mat, gpumat, false);
+ case MAT_PIPE_FORWARD_PREPASS_VELOCITY:
+ return forward.prepass_add(blender_mat, gpumat, true);
case MAT_PIPE_DEFERRED:
// return deferred.material_add(blender_mat, gpumat);
break;
@@ -213,4 +226,4 @@ class PipelineModule {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc
index 086c5f9f358..09aa97e49e9 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -25,7 +25,7 @@ ShaderModule *ShaderModule::g_shader_module = nullptr;
ShaderModule *ShaderModule::module_get()
{
if (g_shader_module == nullptr) {
- /* TODO(fclem) threadsafety. */
+ /* TODO(@fclem) thread-safety. */
g_shader_module = new ShaderModule();
}
return g_shader_module;
@@ -34,7 +34,7 @@ ShaderModule *ShaderModule::module_get()
void ShaderModule::module_free()
{
if (g_shader_module != nullptr) {
- /* TODO(fclem) threadsafety. */
+ /* TODO(@fclem) thread-safety. */
delete g_shader_module;
g_shader_module = nullptr;
}
@@ -78,6 +78,8 @@ ShaderModule::~ShaderModule()
const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_type)
{
switch (shader_type) {
+ case VELOCITY_RESOLVE:
+ return "eevee_velocity_resolve";
/* To avoid compiler warning about missing case. */
case MAX_SHADER_TYPE:
return "";
@@ -148,7 +150,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
/** Noop. */
break;
case MAT_GEOM_CURVES:
- /** 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_) {
if (input.name == "orco") {
/** NOTE: Orco is generated from strand position for now. */
@@ -159,18 +161,19 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
}
}
info.vertex_inputs_.clear();
+ info.additional_info("draw_curves_infos");
break;
case MAT_GEOM_WORLD:
/**
* Only orco layer is supported by world and it is procedurally generated. These are here to
- * make the attribs_load function calls valids.
+ * make the attribs_load function calls valid.
*/
ATTR_FALLTHROUGH;
case MAT_GEOM_GPENCIL:
/**
* Only one uv and one color attribute layer are supported by gpencil objects and they are
* already declared in another createInfo. These are here to make the attribs_load
- * function calls valids.
+ * function calls valid.
*/
for (auto &input : info.vertex_inputs_) {
global_vars << input.type << " " << input.name << ";\n";
@@ -190,7 +193,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
const StageInterfaceInfo &iface = *info.vertex_out_interfaces_.first();
/* Globals the attrib_load() can write to when it is in the fragment shader. */
global_vars << "struct " << iface.name << " {\n";
- for (auto &inout : iface.inouts) {
+ for (const auto &inout : iface.inouts) {
global_vars << " " << inout.type << " " << inout.name << ";\n";
}
global_vars << "};\n";
@@ -289,6 +292,10 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
break;
default:
switch (pipeline_type) {
+ case MAT_PIPE_FORWARD_PREPASS_VELOCITY:
+ case MAT_PIPE_DEFERRED_PREPASS_VELOCITY:
+ info.additional_info("eevee_surf_depth", "eevee_velocity_geom");
+ break;
case MAT_PIPE_FORWARD_PREPASS:
case MAT_PIPE_DEFERRED_PREPASS:
case MAT_PIPE_SHADOW:
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh
index ba7c97b3b6a..0f42e880a10 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh
@@ -26,7 +26,9 @@ namespace blender::eevee {
/* Keep alphabetical order and clean prefix. */
enum eShaderType {
- MAX_SHADER_TYPE = 0,
+ VELOCITY_RESOLVE = 0,
+
+ MAX_SHADER_TYPE,
};
/**
@@ -36,7 +38,7 @@ class ShaderModule {
private:
std::array<GPUShader *, MAX_SHADER_TYPE> shaders_;
- /** Shared shader module accross all engine instances. */
+ /** Shared shader module across all engine instances. */
static ShaderModule *g_shader_module;
public:
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
index 2225ccac43a..1261c855a82 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -19,6 +19,7 @@
namespace blender::eevee {
using draw::Framebuffer;
+using draw::SwapChain;
using draw::Texture;
using draw::TextureFromPool;
@@ -27,7 +28,101 @@ using draw::TextureFromPool;
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
/* -------------------------------------------------------------------- */
-/** \name Raytracing
+/** \name Camera
+ * \{ */
+
+enum eCameraType : uint32_t {
+ CAMERA_PERSP = 0u,
+ CAMERA_ORTHO = 1u,
+ CAMERA_PANO_EQUIRECT = 2u,
+ CAMERA_PANO_EQUISOLID = 3u,
+ CAMERA_PANO_EQUIDISTANT = 4u,
+ CAMERA_PANO_MIRROR = 5u
+};
+
+static inline bool is_panoramic(eCameraType type)
+{
+ return type > CAMERA_ORTHO;
+}
+
+struct CameraData {
+ /* View Matrices of the camera, not from any view! */
+ float4x4 persmat;
+ float4x4 persinv;
+ float4x4 viewmat;
+ float4x4 viewinv;
+ float4x4 winmat;
+ float4x4 wininv;
+ /** Camera UV scale and bias. Also known as `viewcamtexcofac`. */
+ float2 uv_scale;
+ float2 uv_bias;
+ /** Panorama parameters. */
+ float2 equirect_scale;
+ float2 equirect_scale_inv;
+ float2 equirect_bias;
+ float fisheye_fov;
+ float fisheye_lens;
+ /** Clipping distances. */
+ float clip_near;
+ float clip_far;
+ /** Film pixel filter radius. */
+ float filter_size;
+ eCameraType type;
+};
+BLI_STATIC_ASSERT_ALIGN(CameraData, 16)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name VelocityModule
+ * \{ */
+
+#define VELOCITY_INVALID 512.0
+
+enum eVelocityStep : uint32_t {
+ STEP_PREVIOUS = 0,
+ STEP_NEXT = 1,
+ STEP_CURRENT = 2,
+};
+
+struct VelocityObjectIndex {
+ /** Offset inside #VelocityObjectBuf for each timestep. Indexed using eVelocityStep. */
+ int3 ofs;
+ /** Temporary index to copy this to the #VelocityIndexBuf. */
+ uint resource_id;
+
+#ifdef __cplusplus
+ VelocityObjectIndex() : ofs(-1, -1, -1), resource_id(-1){};
+#endif
+};
+BLI_STATIC_ASSERT_ALIGN(VelocityObjectIndex, 16)
+
+struct VelocityGeometryIndex {
+ /** Offset inside #VelocityGeometryBuf for each timestep. Indexed using eVelocityStep. */
+ int3 ofs;
+ /** If true, compute deformation motion blur. */
+ bool1 do_deform;
+ /** Length of data inside #VelocityGeometryBuf for each timestep. Indexed using eVelocityStep. */
+ int3 len;
+
+ int _pad0;
+
+#ifdef __cplusplus
+ VelocityGeometryIndex() : ofs(-1, -1, -1), do_deform(false), len(-1, -1, -1), _pad0(1){};
+#endif
+};
+BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
+
+struct VelocityIndex {
+ VelocityObjectIndex obj;
+ VelocityGeometryIndex geo;
+};
+BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ray-Tracing
* \{ */
enum eClosureBits : uint32_t {
@@ -83,5 +178,10 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer)
#ifdef __cplusplus
+using CameraDataBuf = draw::UniformBuffer<CameraData>;
+using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>;
+using VelocityObjectBuf = draw::StorageArrayBuffer<float4x4, 16>;
+using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>;
+
} // namespace blender::eevee
#endif
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc
index efa5fdc89ab..42af251d770 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc
@@ -104,7 +104,9 @@ static inline void shgroup_geometry_call(DRWShadingGroup *grp,
void SyncModule::sync_mesh(Object *ob, ObjectHandle &ob_handle)
{
- MaterialArray &material_array = inst_.materials.material_array_get(ob);
+ bool has_motion = inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc);
+
+ MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
ob, material_array.gpu_materials.data(), material_array.gpu_materials.size());
@@ -129,9 +131,6 @@ void SyncModule::sync_mesh(Object *ob, ObjectHandle &ob_handle)
is_alpha_blend = is_alpha_blend || material->is_alpha_blend_transparent;
}
- UNUSED_VARS(ob_handle);
- // shading_passes.velocity.mesh_add(ob, ob_handle);
-
// shadows.sync_object(ob, ob_handle, is_shadow_caster, is_alpha_blend);
}
@@ -156,8 +155,11 @@ struct gpIterData {
int vcount = 0;
bool instancing = false;
- gpIterData(Instance &inst_, Object *ob_)
- : inst(inst_), ob(ob_), material_array(inst_.materials.material_array_get(ob_))
+ gpIterData(Instance &inst_, Object *ob_, ObjectHandle &ob_handle)
+ : inst(inst_),
+ ob(ob_),
+ material_array(inst_.materials.material_array_get(
+ ob_, inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc)))
{
cfra = DEG_get_ctime(inst.depsgraph);
};
@@ -253,16 +255,12 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle)
/* TODO(fclem): Waiting for a user option to use the render engine instead of gpencil engine. */
return;
- gpIterData iter(inst_, ob);
+ gpIterData iter(inst_, ob, ob_handle);
BKE_gpencil_visible_stroke_iter((bGPdata *)ob->data, nullptr, gpencil_stroke_sync, &iter);
gpencil_drawcall_flush(iter);
- UNUSED_VARS(ob_handle);
- /* TODO(fclem) Gpencil velocity. */
- // shading_passes.velocity.gpencil_add(ob, ob_handle);
-
// bool is_caster = true; /* TODO material.shadow.shgrp. */
// bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
// shadows.sync_object(ob, ob_handle, is_caster, is_alpha_blend);
@@ -304,12 +302,13 @@ void SyncModule::sync_curves(Object *ob, ObjectHandle &ob_handle, ModifierData *
mat_nr = part_settings->omat;
}
- Material &material = inst_.materials.material_get(ob, mat_nr - 1, MAT_GEOM_CURVES);
+ bool has_motion = inst_.velocity.step_object_sync(ob, ob_handle.object_key, ob_handle.recalc);
+ Material &material = inst_.materials.material_get(ob, has_motion, mat_nr - 1, MAT_GEOM_CURVES);
shgroup_curves_call(material.shading, ob, part_sys, modifier_data);
shgroup_curves_call(material.prepass, ob, part_sys, modifier_data);
shgroup_curves_call(material.shadow, ob, part_sys, modifier_data);
- UNUSED_VARS(ob_handle);
+
/* TODO(fclem) Hair velocity. */
// shading_passes.velocity.gpencil_add(ob, ob_handle);
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.hh b/source/blender/draw/engines/eevee_next/eevee_sync.hh
index 51e0f86fe5c..bd8147a2882 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.hh
@@ -27,7 +27,8 @@ class Instance;
/* -------------------------------------------------------------------- */
/** \name ObjectKey
*
- * Unique key to identify each object in the hashmap.
+ * Unique key to identify each object in the hash-map.
+ * Note that we get a unique key for each object component.
* \{ */
struct ObjectKey {
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
new file mode 100644
index 00000000000..9f8dce43910
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
@@ -0,0 +1,420 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * The velocity pass outputs motion vectors to use for either
+ * temporal re-projection or motion blur.
+ *
+ * It is the module that tracks the objects between frames updates.
+ *
+ * #VelocityModule contains all motion steps data and logic.
+ * #VelocityPass contains the resolve pass for static geometry.
+ * #VelocityView is a per view instance that contain the velocity buffer.
+ */
+
+#include "BKE_duplilist.h"
+#include "BKE_object.h"
+#include "BLI_map.hh"
+#include "DEG_depsgraph_query.h"
+#include "DNA_rigidbody_types.h"
+
+#include "eevee_instance.hh"
+// #include "eevee_renderpasses.hh"
+#include "eevee_shader.hh"
+#include "eevee_shader_shared.hh"
+#include "eevee_velocity.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name VelocityModule
+ *
+ * \{ */
+
+void VelocityModule::init()
+{
+#if 0 /* TODO renderpasses */
+ if (inst_.render && (inst_.render_passes.vector != nullptr)) {
+ /* No motion blur and the vector pass was requested. Do the step sync here. */
+ const Scene *scene = inst_.scene;
+ float initial_time = scene->r.cfra + scene->r.subframe;
+ step_sync(STEP_PREVIOUS, initial_time - 1.0f);
+ step_sync(STEP_NEXT, initial_time + 1.0f);
+ inst_.set_time(initial_time);
+ }
+#endif
+}
+
+static void step_object_sync_render(void *velocity,
+ Object *ob,
+ RenderEngine *UNUSED(engine),
+ Depsgraph *UNUSED(depsgraph))
+{
+ ObjectKey object_key(ob);
+ reinterpret_cast<VelocityModule *>(velocity)->step_object_sync(ob, object_key);
+}
+
+void VelocityModule::step_sync(eVelocityStep step, float time)
+{
+ inst_.set_time(time);
+ step_ = step;
+ object_steps_usage[step_] = 0;
+ step_camera_sync();
+ DRW_render_object_iter(this, inst_.render, inst_.depsgraph, step_object_sync_render);
+}
+
+void VelocityModule::step_camera_sync()
+{
+ inst_.camera.sync();
+ *camera_steps[step_] = inst_.camera.data_get();
+}
+
+bool VelocityModule::step_object_sync(Object *ob,
+ ObjectKey &object_key,
+ int /*IDRecalcFlag*/ recalc)
+{
+ bool has_motion = object_has_velocity(ob) || (recalc & ID_RECALC_TRANSFORM);
+ /* NOTE: Fragile. This will only work with 1 frame of lag since we can't record every geometry
+ * just in case there might be an update the next frame. */
+ bool has_deform = object_is_deform(ob) || (recalc & ID_RECALC_GEOMETRY);
+
+ if (!has_motion && !has_deform) {
+ return false;
+ }
+
+ uint32_t resource_id = DRW_object_resource_id_get(ob);
+
+ /* Object motion. */
+ /* FIXME(fclem) As we are using original objects pointers, there is a chance the previous
+ * object key matches a totally different object if the scene was changed by user or python
+ * callback. In this case, we cannot correctly match objects between updates.
+ * What this means is that there will be incorrect motion vectors for these objects.
+ * We live with that until we have a correct way of identifying new objects. */
+ VelocityObjectData &vel = velocity_map.lookup_or_add_default(object_key);
+ vel.obj.ofs[step_] = object_steps_usage[step_]++;
+ vel.obj.resource_id = resource_id;
+ vel.id = (ID *)ob->data;
+ object_steps[step_]->get_or_resize(vel.obj.ofs[step_]) = ob->obmat;
+ if (step_ == STEP_CURRENT) {
+ /* Replace invalid steps. Can happen if object was hidden in one of those steps. */
+ if (vel.obj.ofs[STEP_PREVIOUS] == -1) {
+ vel.obj.ofs[STEP_PREVIOUS] = object_steps_usage[STEP_PREVIOUS]++;
+ object_steps[STEP_PREVIOUS]->get_or_resize(vel.obj.ofs[STEP_PREVIOUS]) = ob->obmat;
+ }
+ if (vel.obj.ofs[STEP_NEXT] == -1) {
+ vel.obj.ofs[STEP_NEXT] = object_steps_usage[STEP_NEXT]++;
+ object_steps[STEP_NEXT]->get_or_resize(vel.obj.ofs[STEP_NEXT]) = ob->obmat;
+ }
+ }
+
+ /* Geometry motion. */
+ if (has_deform) {
+ auto add_cb = [&]() {
+ VelocityGeometryData data;
+ switch (ob->type) {
+ case OB_CURVES:
+ data.pos_buf = DRW_curves_pos_buffer_get(ob);
+ break;
+ default:
+ data.pos_buf = DRW_cache_object_pos_vertbuf_get(ob);
+ break;
+ }
+ return data;
+ };
+
+ const VelocityGeometryData &data = geometry_map.lookup_or_add_cb(vel.id, add_cb);
+
+ if (data.pos_buf == nullptr) {
+ has_deform = false;
+ }
+ }
+
+ /* Avoid drawing object that has no motions but were tagged as such. */
+ if (step_ == STEP_CURRENT && has_motion == true && has_deform == false) {
+ float4x4 &obmat_curr = (*object_steps[STEP_CURRENT])[vel.obj.ofs[STEP_CURRENT]];
+ float4x4 &obmat_prev = (*object_steps[STEP_PREVIOUS])[vel.obj.ofs[STEP_PREVIOUS]];
+ float4x4 &obmat_next = (*object_steps[STEP_NEXT])[vel.obj.ofs[STEP_NEXT]];
+ if (inst_.is_viewport()) {
+ has_motion = (obmat_curr != obmat_prev);
+ }
+ else {
+ has_motion = (obmat_curr != obmat_prev || obmat_curr != obmat_next);
+ }
+ }
+
+#if 0
+ if (!has_motion && !has_deform) {
+ std::cout << "Detected no motion on " << ob->id.name << std::endl;
+ }
+ if (has_deform) {
+ std::cout << "Geometry Motion on " << ob->id.name << std::endl;
+ }
+ if (has_motion) {
+ std::cout << "Object Motion on " << ob->id.name << std::endl;
+ }
+#endif
+
+ if (!has_motion && !has_deform) {
+ return false;
+ }
+
+ /* TODO(@fclem): Reset sampling here? Should ultimately be covered by depsgraph update tags. */
+ // inst_.sampling.reset();
+
+ return true;
+}
+
+/**
+ * Moves next frame data to previous frame data. Nullify next frame data.
+ * IMPORTANT: This runs AFTER drawing in the viewport (so after `begin_sync()`) but BEFORE drawing
+ * in render mode (so before `begin_sync()`). In viewport the data will be used the next frame.
+ */
+void VelocityModule::step_swap()
+{
+ {
+ /* Now that vertex buffers are guaranteed to be updated, proceed with
+ * offset computation and copy into the geometry step buffer. */
+ uint dst_ofs = 0;
+ for (VelocityGeometryData &geom : geometry_map.values()) {
+ uint src_len = GPU_vertbuf_get_vertex_len(geom.pos_buf);
+ geom.len = src_len;
+ geom.ofs = dst_ofs;
+ dst_ofs += src_len;
+ }
+ /* TODO(@fclem): Fail gracefully (disable motion blur + warning print) if
+ `tot_len * sizeof(float4)` is greater than max SSBO size. */
+ geometry_steps[step_]->resize(max_ii(16, dst_ofs));
+
+ for (VelocityGeometryData &geom : geometry_map.values()) {
+ GPU_storagebuf_copy_sub_from_vertbuf(*geometry_steps[step_],
+ geom.pos_buf,
+ geom.ofs * sizeof(float4),
+ 0,
+ geom.len * sizeof(float4));
+ }
+ /* Copy back the #VelocityGeometryIndex into #VelocityObjectData which are
+ * indexed using persistent keys (unlike geometries which are indexed by volatile ID). */
+ for (VelocityObjectData &vel : velocity_map.values()) {
+ const VelocityGeometryData &geom = geometry_map.lookup_default(vel.id,
+ VelocityGeometryData());
+ vel.geo.len[step_] = geom.len;
+ vel.geo.ofs[step_] = geom.ofs;
+ /* Avoid reuse. */
+ vel.id = nullptr;
+ }
+
+ geometry_map.clear();
+ }
+
+ auto swap_steps = [&](eVelocityStep step_a, eVelocityStep step_b) {
+ SWAP(VelocityObjectBuf *, object_steps[step_a], object_steps[step_b]);
+ SWAP(VelocityGeometryBuf *, geometry_steps[step_a], geometry_steps[step_b]);
+ SWAP(CameraDataBuf *, camera_steps[step_a], camera_steps[step_b]);
+
+ for (VelocityObjectData &vel : velocity_map.values()) {
+ vel.obj.ofs[step_a] = vel.obj.ofs[step_b];
+ vel.obj.ofs[step_b] = (uint)-1;
+ vel.geo.ofs[step_a] = vel.geo.ofs[step_b];
+ vel.geo.len[step_a] = vel.geo.len[step_b];
+ vel.geo.ofs[step_b] = (uint)-1;
+ vel.geo.len[step_b] = (uint)-1;
+ }
+ };
+
+ if (inst_.is_viewport()) {
+ /* For viewport we only use the last rendered redraw as previous frame.
+ * We swap current with previous step at the end of a redraw.
+ * We do not support motion blur as it is rendered to avoid conflicting motions
+ * for temporal reprojection. */
+ swap_steps(eVelocityStep::STEP_PREVIOUS, eVelocityStep::STEP_CURRENT);
+ }
+ else {
+ /* Render case: The STEP_CURRENT is left untouched. */
+ swap_steps(eVelocityStep::STEP_PREVIOUS, eVelocityStep::STEP_NEXT);
+ }
+}
+
+void VelocityModule::begin_sync()
+{
+ if (inst_.is_viewport()) {
+ /* Viewport always evaluate current step. */
+ step_ = STEP_CURRENT;
+ }
+ step_camera_sync();
+ object_steps_usage[step_] = 0;
+}
+
+/* This is the end of the current frame sync. Not the step_sync. */
+void VelocityModule::end_sync()
+{
+ Vector<ObjectKey, 0> deleted_obj;
+
+ uint32_t max_resource_id_ = 0u;
+
+ for (Map<ObjectKey, VelocityObjectData>::Item item : velocity_map.items()) {
+ if (item.value.obj.resource_id == (uint)-1) {
+ deleted_obj.append(item.key);
+ }
+ else {
+ max_resource_id_ = max_uu(max_resource_id_, item.value.obj.resource_id);
+ }
+ }
+
+ if (deleted_obj.size() > 0) {
+ // inst_.sampling.reset();
+ }
+
+ for (auto key : deleted_obj) {
+ velocity_map.remove(key);
+ }
+
+ indirection_buf.resize(power_of_2_max_u(max_resource_id_ + 1));
+
+ /* Avoid uploading more data to the GPU as well as an extra level of
+ * indirection on the GPU by copying back offsets the to VelocityIndex. */
+ for (VelocityObjectData &vel : velocity_map.values()) {
+ /* Disable deform if vertex count mismatch. */
+ if (inst_.is_viewport()) {
+ /* Current geometry step will be copied at the end of the frame.
+ * Thus vel.geo.len[STEP_CURRENT] is not yet valid and the current length is manually
+ * retrieved. */
+ GPUVertBuf *pos_buf = geometry_map.lookup_default(vel.id, VelocityGeometryData()).pos_buf;
+ vel.geo.do_deform = pos_buf != nullptr &&
+ (vel.geo.len[STEP_PREVIOUS] == GPU_vertbuf_get_vertex_len(pos_buf));
+ }
+ else {
+ vel.geo.do_deform = (vel.geo.len[STEP_PREVIOUS] == vel.geo.len[STEP_CURRENT]) &&
+ (vel.geo.len[STEP_NEXT] == vel.geo.len[STEP_CURRENT]);
+ }
+ indirection_buf[vel.obj.resource_id] = vel;
+ /* Reset for next sync. */
+ vel.obj.resource_id = (uint)-1;
+ }
+
+ object_steps[STEP_PREVIOUS]->push_update();
+ object_steps[STEP_NEXT]->push_update();
+ camera_steps[STEP_PREVIOUS]->push_update();
+ camera_steps[STEP_CURRENT]->push_update();
+ camera_steps[STEP_NEXT]->push_update();
+ indirection_buf.push_update();
+
+ {
+ resolve_ps_ = DRW_pass_create("Velocity.Resolve", (DRWState)0);
+ GPUShader *sh = inst_.shaders.static_shader_get(VELOCITY_RESOLVE);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, resolve_ps_);
+ DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &input_depth_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "velocity_view_img", &velocity_view_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "velocity_camera_img", &velocity_camera_tx_);
+ DRW_shgroup_uniform_block(grp, "camera_prev", *camera_steps[STEP_PREVIOUS]);
+ DRW_shgroup_uniform_block(grp, "camera_curr", *camera_steps[STEP_CURRENT]);
+ DRW_shgroup_uniform_block(grp, "camera_next", *camera_steps[STEP_NEXT]);
+ DRW_shgroup_call_compute_ref(grp, resolve_dispatch_size_);
+ }
+}
+
+bool VelocityModule::object_has_velocity(const Object *ob)
+{
+#if 0
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Active rigidbody objects only, as only those are affected by sim. */
+ const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
+ /* For now we assume dupli objects are moving. */
+ const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0;
+ const bool object_moves = is_dupli || has_rigidbody || BKE_object_moves_in_time(ob, true);
+#else
+ UNUSED_VARS(ob);
+ /* BKE_object_moves_in_time does not work in some cases.
+ * Better detect non moving object after evaluation. */
+ const bool object_moves = true;
+#endif
+ return object_moves;
+}
+
+bool VelocityModule::object_is_deform(const Object *ob)
+{
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Active rigidbody objects only, as only those are affected by sim. */
+ const bool has_rigidbody = (rbo && (rbo->type == RBO_TYPE_ACTIVE));
+ const bool is_deform = BKE_object_is_deform_modified(inst_.scene, (Object *)ob) ||
+ (has_rigidbody && (rbo->flag & RBO_FLAG_USE_DEFORM) != 0);
+
+ return is_deform;
+}
+
+void VelocityModule::bind_resources(DRWShadingGroup *grp)
+{
+ /* For viewport, only previous motion is supported.
+ * Still bind previous step to avoid undefined behavior. */
+ eVelocityStep next = inst_.is_viewport() ? STEP_PREVIOUS : STEP_NEXT;
+ DRW_shgroup_storage_block_ref(grp, "velocity_obj_prev_buf", &(*object_steps[STEP_PREVIOUS]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_obj_next_buf", &(*object_steps[next]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_geo_prev_buf", &(*geometry_steps[STEP_PREVIOUS]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_geo_next_buf", &(*geometry_steps[next]));
+ DRW_shgroup_uniform_block_ref(grp, "camera_prev", &(*camera_steps[STEP_PREVIOUS]));
+ DRW_shgroup_uniform_block_ref(grp, "camera_curr", &(*camera_steps[STEP_CURRENT]));
+ DRW_shgroup_uniform_block_ref(grp, "camera_next", &(*camera_steps[next]));
+ DRW_shgroup_storage_block_ref(grp, "velocity_indirection_buf", &indirection_buf);
+}
+
+/* Resolve pass for static geometry and to camera space projection. */
+void VelocityModule::resolve_camera_motion(GPUTexture *depth_tx,
+ GPUTexture *velocity_view_tx,
+ GPUTexture *velocity_camera_tx)
+{
+ input_depth_tx_ = depth_tx;
+ velocity_view_tx_ = velocity_view_tx;
+ velocity_camera_tx_ = velocity_camera_tx;
+
+ resolve_dispatch_size_.x = divide_ceil_u(GPU_texture_width(depth_tx), 8);
+ resolve_dispatch_size_.y = divide_ceil_u(GPU_texture_height(depth_tx), 8);
+
+ DRW_draw_pass(resolve_ps_);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Velocity View
+ * \{ */
+
+void VelocityView::sync()
+{
+ /* TODO: Remove. */
+ velocity_view_tx_.sync();
+ velocity_camera_tx_.sync();
+}
+
+void VelocityView::acquire(int2 extent)
+{
+ /* WORKAROUND: View name should be unique and static.
+ * With this, we can reuse the same texture across views. */
+ DrawEngineType *owner = (DrawEngineType *)view_name_.c_str();
+
+ /* Only RG16F when only doing only reprojection or motion blur. */
+ eGPUTextureFormat format = inst_.is_viewport() ? GPU_RG16F : GPU_RGBA16F;
+ velocity_view_tx_.acquire(extent, format, owner);
+ if (false /* TODO(fclem): Panoramic camera. */) {
+ velocity_camera_tx_.acquire(extent, format, owner);
+ }
+ else {
+ velocity_camera_tx_.acquire(int2(1), format, owner);
+ }
+}
+
+void VelocityView::resolve(GPUTexture *depth_tx)
+{
+ inst_.velocity.resolve_camera_motion(depth_tx, velocity_view_tx_, velocity_camera_tx_);
+}
+
+void VelocityView::release()
+{
+ velocity_view_tx_.release();
+ velocity_camera_tx_.release();
+}
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
new file mode 100644
index 00000000000..1bfd9f8c18f
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * The velocity pass outputs motion vectors to use for either
+ * temporal re-projection or motion blur.
+ *
+ * It is the module that tracks the objects data between frames updates.
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+
+#include "eevee_shader_shared.hh"
+#include "eevee_sync.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name VelocityModule
+ *
+ * \{ */
+
+/** Container for scene velocity data. */
+class VelocityModule {
+ friend class VelocityView;
+
+ public:
+ struct VelocityObjectData : public VelocityIndex {
+ /** ID to retrieve the corresponding #VelocityGeometryData after copy. */
+ ID *id;
+ };
+ struct VelocityGeometryData {
+ /** VertBuf not yet ready to be copied to the #VelocityGeometryBuf. */
+ GPUVertBuf *pos_buf = nullptr;
+ /* Offset in the #VelocityGeometryBuf to the start of the data. In vertex. */
+ int ofs;
+ /* Length of the vertex buffer. In vertex. */
+ int len;
+ };
+ /**
+ * The map contains indirection indices to the obmat and geometry in each step buffer.
+ * Note that each object component gets its own resource id so one component correspond to one
+ * geometry offset.
+ */
+ Map<ObjectKey, VelocityObjectData> velocity_map;
+ /** Geometry to be copied to VelocityGeometryBuf. Indexed by evaluated ID *. Empty after */
+ Map<ID *, VelocityGeometryData> geometry_map;
+ /** Contains all objects matrices for each time step. */
+ std::array<VelocityObjectBuf *, 3> object_steps;
+ /** Contains all Geometry steps from deforming objects for each time step. */
+ std::array<VelocityGeometryBuf *, 3> geometry_steps;
+ /** Number of occupied slot in each `object_steps`. */
+ int3 object_steps_usage = int3(0);
+ /** Buffer of all #VelocityIndex used in this frame. Indexed by draw manager resource id. */
+ VelocityIndexBuf indirection_buf;
+
+ /**
+ * Copies of camera data. One for previous and one for next time step.
+ */
+ std::array<CameraDataBuf *, 3> camera_steps;
+
+ private:
+ Instance &inst_;
+
+ eVelocityStep step_ = STEP_CURRENT;
+
+ DRWPass *resolve_ps_ = nullptr;
+
+ /** Reference only. Not owned. */
+ GPUTexture *input_depth_tx_;
+ GPUTexture *velocity_view_tx_;
+ GPUTexture *velocity_camera_tx_;
+
+ int3 resolve_dispatch_size_ = int3(1, 1, 1);
+
+ public:
+ VelocityModule(Instance &inst) : inst_(inst)
+ {
+ for (VelocityObjectBuf *&step_buf : object_steps) {
+ step_buf = new VelocityObjectBuf();
+ }
+ for (VelocityGeometryBuf *&step_buf : geometry_steps) {
+ step_buf = new VelocityGeometryBuf();
+ }
+ for (CameraDataBuf *&step_buf : camera_steps) {
+ step_buf = new CameraDataBuf();
+ }
+ };
+
+ ~VelocityModule()
+ {
+ for (VelocityObjectBuf *step_buf : object_steps) {
+ delete step_buf;
+ }
+ for (VelocityGeometryBuf *step_buf : geometry_steps) {
+ delete step_buf;
+ }
+ for (CameraDataBuf *step_buf : camera_steps) {
+ delete step_buf;
+ }
+ }
+
+ void init();
+
+ void step_camera_sync();
+ void step_sync(eVelocityStep step, float time);
+
+ /* Gather motion data. Returns true if the object **can** have motion. */
+ bool step_object_sync(Object *ob, ObjectKey &ob_key, int recalc = 0);
+
+ /* Moves next frame data to previous frame data. Nullify next frame data. */
+ void step_swap();
+
+ void begin_sync();
+ void end_sync();
+
+ void bind_resources(DRWShadingGroup *grp);
+
+ private:
+ bool object_has_velocity(const Object *ob);
+ bool object_is_deform(const Object *ob);
+
+ void resolve_camera_motion(GPUTexture *depth_tx,
+ GPUTexture *velocity_view_tx,
+ GPUTexture *velocity_camera_tx);
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Velocity
+ *
+ * \{ */
+
+/**
+ * Per view module.
+ */
+class VelocityView {
+ private:
+ Instance &inst_;
+
+ StringRefNull view_name_;
+
+ TextureFromPool velocity_camera_tx_ = {"velocity_camera_tx_"};
+ TextureFromPool velocity_view_tx_ = {"velocity_view_tx_"};
+
+ public:
+ VelocityView(Instance &inst, const char *name) : inst_(inst), view_name_(name){};
+ ~VelocityView(){};
+
+ void sync();
+
+ void acquire(int2 extent);
+ void release();
+
+ void resolve(GPUTexture *depth_tx);
+
+ /**
+ * Getters
+ **/
+ GPUTexture *view_vectors_get() const
+ {
+ return velocity_view_tx_;
+ }
+ GPUTexture *camera_vectors_get() const
+ {
+ return (velocity_camera_tx_.is_valid()) ? velocity_camera_tx_ : velocity_view_tx_;
+ }
+};
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc
index df45200c712..e21342c5ef6 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_view.cc
@@ -9,7 +9,7 @@
* - The entire main view.
* - A fragment of the main view (for panoramic projections).
* - A shadow map view.
- * - A lightprobe view (either planar, cubemap, irradiance grid).
+ * - A light-probe view (either planar, cube-map, irradiance grid).
*
* A pass is a container for scene data. It is view agnostic but has specific logic depending on
* its type. Passes are shared between views.
@@ -40,7 +40,7 @@ void ShadingView::sync(int2 render_extent_)
int64_t render_pixel_count = render_extent_.x * (int64_t)render_extent_.y;
/* Divide pixel count between the 6 views. Rendering to a square target. */
extent_[0] = extent_[1] = ceilf(sqrtf(1 + (render_pixel_count / 6)));
- /* TODO(fclem) Clip unused views heres. */
+ /* TODO(@fclem): Clip unused views here. */
is_enabled_ = true;
}
else {
@@ -60,8 +60,8 @@ void ShadingView::sync(int2 render_extent_)
const float(*viewmat_p)[4] = viewmat.ptr(), (*winmat_p)[4] = winmat.ptr();
#if 0
if (false /* inst_.camera.is_panoramic() */) {
- /* TODO(fclem) Overscans. */
- /* For now a mandatory 5% overscan for DoF. */
+ /* TODO(@fclem) Over-scans. */
+ /* For now a mandatory 5% over-scan for DoF. */
float side = data.clip_near * 1.05f;
float near = data.clip_near;
float far = data.clip_far;
@@ -86,7 +86,7 @@ void ShadingView::sync(int2 render_extent_)
// dof_.sync(winmat_p, extent_);
// mb_.sync(extent_);
- // velocity_.sync(extent_);
+ velocity_.sync();
// rt_buffer_opaque_.sync(extent_);
// rt_buffer_refract_.sync(extent_);
// inst_.hiz_back.view_sync(extent_);
@@ -108,22 +108,30 @@ void ShadingView::render()
* With this, we can reuse the same texture across views. */
DrawEngineType *owner = (DrawEngineType *)name_;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
depth_tx_.ensure_2d(GPU_DEPTH24_STENCIL8, extent_);
combined_tx_.acquire(extent_, GPU_RGBA16F, owner);
- view_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_), GPU_ATTACHMENT_TEXTURE(combined_tx_));
+ velocity_.acquire(extent_);
+ // combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_), GPU_ATTACHMENT_TEXTURE(combined_tx_));
+ // prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_),
+ // GPU_ATTACHMENT_TEXTURE(velocity_.view_vectors_get()));
+ combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color));
+ prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(velocity_.view_vectors_get()));
update_view();
DRW_stats_group_start(name_);
// DRW_view_set_active(render_view_);
+ float4 clear_velocity(VELOCITY_INVALID);
+ GPU_framebuffer_bind(prepass_fb_);
+ GPU_framebuffer_clear_color(prepass_fb_, clear_velocity);
/* Alpha stores transmittance. So start at 1. */
float4 clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
- // GPU_framebuffer_bind(view_fb_);
- // GPU_framebuffer_clear_color_depth(view_fb_, clear_color, 1.0f);
- DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- GPU_framebuffer_bind(dfbl->default_fb);
- GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_color, 1.0f);
+ GPU_framebuffer_bind(combined_fb_);
+ GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f);
inst_.pipelines.world.render();
@@ -134,12 +142,13 @@ void ShadingView::render()
// inst_.lookdev.render_overlay(view_fb_);
- inst_.pipelines.forward.render(render_view_, depth_tx_, combined_tx_);
+ inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_, depth_tx_, combined_tx_);
// inst_.lights.debug_draw(view_fb_);
// inst_.shadows.debug_draw(view_fb_);
- // velocity_.render(depth_tx_);
+ // velocity_.resolve(depth_tx_);
+ velocity_.resolve(dtxl->depth);
// if (inst_.render_passes.vector) {
// inst_.render_passes.vector->accumulate(velocity_.camera_vectors_get(), sub_view_);
@@ -159,6 +168,7 @@ void ShadingView::render()
combined_tx_.release();
postfx_tx_.release();
+ velocity_.release();
}
GPUTexture *ShadingView::render_post(GPUTexture *input_tx)
@@ -205,4 +215,4 @@ void ShadingView::update_view()
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index ab7b5722de1..95ec1760c63 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -8,7 +8,7 @@
* A view is either:
* - The entire main view.
* - A portion of the main view (for panoramic projections).
- * - A lightprobe view (either planar, cubemap, irradiance grid).
+ * - A light-probe view (either planar, cube-map, irradiance grid).
*
* A pass is a container for scene data. It is view agnostic but has specific logic depending on
* its type. Passes are shared between views.
@@ -21,6 +21,7 @@
#include "eevee_camera.hh"
#include "eevee_pipeline.hh"
#include "eevee_shader.hh"
+#include "eevee_velocity.hh"
namespace blender::eevee {
@@ -43,13 +44,14 @@ class ShadingView {
/** Post-fx modules. */
// DepthOfField dof_;
// MotionBlur mb_;
- // Velocity velocity_;
+ VelocityView velocity_;
/** Raytracing persistent buffers. Only opaque and refraction can have surface tracing. */
// RaytraceBuffer rt_buffer_opaque_;
// RaytraceBuffer rt_buffer_refract_;
- Framebuffer view_fb_;
+ Framebuffer prepass_fb_;
+ Framebuffer combined_fb_;
Texture depth_tx_;
TextureFromPool combined_tx_;
TextureFromPool postfx_tx_;
@@ -69,7 +71,7 @@ class ShadingView {
public:
ShadingView(Instance &inst, const char *name, const float (*face_matrix)[4])
- : inst_(inst), name_(name), face_matrix_(face_matrix){};
+ : inst_(inst), name_(name), face_matrix_(face_matrix), velocity_(inst, name){};
~ShadingView(){};
@@ -154,4 +156,4 @@ class MainView {
/** \} */
-} // namespace blender::eevee \ No newline at end of file
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc
index 939f6087137..b9cb24fe30a 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_world.cc
@@ -64,19 +64,17 @@ void World::sync()
// }
::World *bl_world = inst_.scene->world;
-
if (bl_world == nullptr) {
// bl_world = BKE_world_default();
return;
}
- else {
- WorldHandle &wo_handle = inst_.sync.sync_world(bl_world);
- if (wo_handle.recalc != 0) {
- // inst_.lightprobes.set_world_dirty();
- }
- wo_handle.reset_recalc_flag();
+ WorldHandle &wo_handle = inst_.sync.sync_world(bl_world);
+
+ if (wo_handle.recalc != 0) {
+ // inst_.lightprobes.set_world_dirty();
}
+ wo_handle.reset_recalc_flag();
/* TODO(fclem) This should be detected to scene level. */
::World *orig_world = (::World *)DEG_get_original_id(&bl_world->id);
diff --git a/source/blender/draw/engines/eevee_next/eevee_world.hh b/source/blender/draw/engines/eevee_next/eevee_world.hh
index 56554051eea..05177928436 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_world.hh
@@ -18,7 +18,7 @@ namespace blender::eevee {
class Instance;
/* -------------------------------------------------------------------- */
-/** \name Default World Nodetree
+/** \name Default World Node-Tree
*
* In order to support worlds without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the World even if
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index 3c5acf62e30..1b113e529b6 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -112,6 +112,7 @@ float attr_load_float(float attr)
/** \name Curve
*
* Curve objects loads attributes from buffers through sampler buffers.
+ * Per attribute scope follows loading order.
* \{ */
# ifdef OBINFO_LIB
@@ -122,6 +123,22 @@ vec3 attr_load_orco(vec4 orco)
return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
}
# endif
+
+int g_curves_attr_id = 0;
+
+/* Return the index to use for looking up the attribute value in the sampler
+ * based on the attribute scope (point or spline). */
+int curves_attribute_element_id()
+{
+ int id = interp.curves_strand_id;
+ if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ id = hair_get_base_id();
+ }
+
+ g_curves_attr_id += 1;
+ return id;
+}
+
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
/* Not supported for the moment. */
@@ -137,19 +154,19 @@ vec4 attr_load_color(samplerBuffer cd_buf)
}
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rgba;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgba;
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rgb;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rgb;
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).rg;
+ return texelFetch(cd_buf, curves_attribute_element_id()).rg;
}
float attr_load_float(samplerBuffer cd_buf)
{
- return texelFetch(cd_buf, interp.curves_strand_id).r;
+ return texelFetch(cd_buf, curves_attribute_element_id()).r;
}
/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl
new file mode 100644
index 00000000000..f79e9102d76
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl
@@ -0,0 +1,166 @@
+
+/**
+ * Camera projection / uv functions and utils.
+ **/
+
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
+/* -------------------------------------------------------------------- */
+/** \name Panoramic Projections
+ *
+ * Adapted from Cycles to match EEVEE's coordinate system.
+ * \{ */
+
+vec2 camera_equirectangular_from_direction(CameraData cam, vec3 dir)
+{
+ float phi = atan(-dir.z, dir.x);
+ float theta = acos(dir.y / length(dir));
+ return (vec2(phi, theta) - cam.equirect_bias) * cam.equirect_scale_inv;
+}
+
+vec3 camera_equirectangular_to_direction(CameraData cam, vec2 uv)
+{
+ uv = uv * cam.equirect_scale + cam.equirect_bias;
+ float phi = uv.x;
+ float theta = uv.y;
+ float sin_theta = sin(theta);
+ return vec3(sin_theta * cos(phi), cos(theta), -sin_theta * sin(phi));
+}
+
+vec2 camera_fisheye_from_direction(CameraData cam, vec3 dir)
+{
+ float r = atan(length(dir.xy), -dir.z) / cam.fisheye_fov;
+ float phi = atan(dir.y, dir.x);
+ vec2 uv = r * vec2(cos(phi), sin(phi)) + 0.5;
+ return (uv - cam.uv_bias) / cam.uv_scale;
+}
+
+vec3 camera_fisheye_to_direction(CameraData cam, vec2 uv)
+{
+ uv = uv * cam.uv_scale + cam.uv_bias;
+ uv = (uv - 0.5) * 2.0;
+ float r = length(uv);
+ if (r > 1.0) {
+ return vec3(0.0);
+ }
+ float phi = safe_acos(uv.x * safe_rcp(r));
+ float theta = r * cam.fisheye_fov * 0.5;
+ if (uv.y < 0.0) {
+ phi = -phi;
+ }
+ return vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), -cos(theta));
+}
+
+vec2 camera_mirror_ball_from_direction(CameraData cam, vec3 dir)
+{
+ dir = normalize(dir);
+ dir.z -= 1.0;
+ dir *= safe_rcp(2.0 * safe_sqrt(-0.5 * dir.z));
+ vec2 uv = 0.5 * dir.xy + 0.5;
+ return (uv - cam.uv_bias) / cam.uv_scale;
+}
+
+vec3 camera_mirror_ball_to_direction(CameraData cam, vec2 uv)
+{
+ uv = uv * cam.uv_scale + cam.uv_bias;
+ vec3 dir;
+ dir.xy = uv * 2.0 - 1.0;
+ if (len_squared(dir.xy) > 1.0) {
+ return vec3(0.0);
+ }
+ dir.z = -safe_sqrt(1.0 - sqr(dir.x) - sqr(dir.y));
+ const vec3 I = vec3(0.0, 0.0, 1.0);
+ return reflect(I, dir);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Regular projections
+ * \{ */
+
+vec3 camera_view_from_uv(mat4 projmat, vec2 uv)
+{
+ return project_point(projmat, vec3(uv * 2.0 - 1.0, 0.0));
+}
+
+vec2 camera_uv_from_view(mat4 projmat, bool is_persp, vec3 vV)
+{
+ vec4 tmp = projmat * vec4(vV, 1.0);
+ if (is_persp && tmp.w <= 0.0) {
+ /* Return invalid coordinates for points behind the camera.
+ * This can happen with panoramic projections. */
+ return vec2(-1.0);
+ }
+ return (tmp.xy / tmp.w) * 0.5 + 0.5;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name General functions handling all projections
+ * \{ */
+
+vec3 camera_view_from_uv(CameraData cam, vec2 uv)
+{
+ vec3 vV;
+ switch (cam.type) {
+ default:
+ case CAMERA_ORTHO:
+ case CAMERA_PERSP:
+ return camera_view_from_uv(cam.wininv, uv);
+ case CAMERA_PANO_EQUIRECT:
+ vV = camera_equirectangular_to_direction(cam, uv);
+ break;
+ case CAMERA_PANO_EQUIDISTANT:
+ /* ATTR_FALLTHROUGH; */
+ case CAMERA_PANO_EQUISOLID:
+ vV = camera_fisheye_to_direction(cam, uv);
+ break;
+ case CAMERA_PANO_MIRROR:
+ vV = camera_mirror_ball_to_direction(cam, uv);
+ break;
+ }
+ return vV;
+}
+
+vec2 camera_uv_from_view(CameraData cam, vec3 vV)
+{
+ switch (cam.type) {
+ default:
+ case CAMERA_ORTHO:
+ return camera_uv_from_view(cam.winmat, false, vV);
+ case CAMERA_PERSP:
+ return camera_uv_from_view(cam.winmat, true, vV);
+ case CAMERA_PANO_EQUIRECT:
+ return camera_equirectangular_from_direction(cam, vV);
+ case CAMERA_PANO_EQUISOLID:
+ /* ATTR_FALLTHROUGH; */
+ case CAMERA_PANO_EQUIDISTANT:
+ return camera_fisheye_from_direction(cam, vV);
+ case CAMERA_PANO_MIRROR:
+ return camera_mirror_ball_from_direction(cam, vV);
+ }
+}
+
+vec2 camera_uv_from_world(CameraData cam, vec3 V)
+{
+ vec3 vV = transform_point(cam.viewmat, V);
+ switch (cam.type) {
+ default:
+ case CAMERA_ORTHO:
+ return camera_uv_from_view(cam.persmat, false, V);
+ case CAMERA_PERSP:
+ return camera_uv_from_view(cam.persmat, true, V);
+ case CAMERA_PANO_EQUIRECT:
+ return camera_equirectangular_from_direction(cam, vV);
+ case CAMERA_PANO_EQUISOLID:
+ /* ATTR_FALLTHROUGH; */
+ case CAMERA_PANO_EQUIDISTANT:
+ return camera_fisheye_from_direction(cam, vV);
+ case CAMERA_PANO_MIRROR:
+ return camera_mirror_ball_from_direction(cam, vV);
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
index 708bd153e84..87154ba6db1 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
@@ -5,6 +5,7 @@
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
@@ -27,6 +28,19 @@ void main()
interp.N = cross(T, interp.curves_binormal);
interp.curves_strand_id = hair_get_strand_id();
interp.barycentric_coords = hair_get_barycentric();
+#ifdef MAT_VELOCITY
+ /* Due to the screen space nature of the vertex positioning, we compute only the motion of curve
+ * strand, not its cylinder. Otherwise we would add the rotation velocity. */
+ int vert_idx = hair_get_base_id();
+ vec3 prv, nxt, pos = texelFetch(hairPointBuffer, vert_idx).point_position;
+ velocity_local_pos_get(pos, vert_idx, prv, nxt);
+ /* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
+ * ignores motion from animated displacement. Supporting animated displacement motion vectors
+ * would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
+ * different times, but also with different attributes (maybe we could assume static attribute at
+ * least). */
+ velocity_vertex(prv, pos, nxt, motion.prev, motion.next);
+#endif
init_globals();
attrib_load();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
index 5b404ec5237..c60527162f7 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
@@ -3,6 +3,7 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
@@ -38,6 +39,16 @@ void main()
aspect,
thickness,
hardness);
+#ifdef MAT_VELOCITY
+ /* GPencil do not support deformation motion blur. */
+ vec3 lP_curr = transform_point(ModelMatrixInverse, interp.P);
+ /* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
+ * ignores motion from animated displacement. Supporting animated displacement motion vectors
+ * would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
+ * different times, but also with different attributes (maybe we could assume static attribute at
+ * least). */
+ velocity_vertex(lP_curr, lP_curr, lP_curr, motion.prev, motion.next);
+#endif
init_globals();
attrib_load();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
index 7b38057f41a..c07a8ae0eea 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
@@ -3,6 +3,7 @@
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
@@ -10,6 +11,16 @@ void main()
interp.P = point_object_to_world(pos);
interp.N = normal_object_to_world(nor);
+#ifdef MAT_VELOCITY
+ vec3 prv, nxt;
+ velocity_local_pos_get(pos, gl_VertexID, prv, nxt);
+ /* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
+ * ignores motion from animated displacement. Supporting animated displacement motion vectors
+ * would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
+ * different times, but also with different attributes (maybe we could assume static attribute at
+ * least). */
+ velocity_vertex(prv, pos, nxt, motion.prev, motion.next);
+#endif
init_globals();
attrib_load();
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
index 002eed91130..7ddf941df7c 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_depth_frag.glsl
@@ -8,6 +8,7 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire. */
float hash(vec2 a)
@@ -69,4 +70,16 @@ void main()
discard;
}
#endif
+
+#ifdef MAT_VELOCITY
+ vec4 out_velocity_camera; /* TODO(fclem): Panoramic cameras. */
+ velocity_camera(interp.P + motion.prev,
+ interp.P,
+ interp.P - motion.next,
+ out_velocity_camera,
+ out_velocity_view);
+
+ /* For testing in viewport. */
+ out_velocity_view.zw = vec2(0.0);
+#endif
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
new file mode 100644
index 00000000000..435ae6658c9
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_lib.glsl
@@ -0,0 +1,101 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_camera_lib.glsl)
+
+#ifdef VELOCITY_CAMERA
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy)
+ */
+vec4 velocity_view(vec3 P_prev, vec3 P, vec3 P_next)
+{
+ vec2 prev_uv, curr_uv, next_uv;
+
+ prev_uv = transform_point(ProjectionMatrix, transform_point(camera_prev.viewmat, P_prev)).xy;
+ curr_uv = transform_point(ViewProjectionMatrix, P).xy;
+ next_uv = transform_point(ProjectionMatrix, transform_point(camera_next.viewmat, P_next)).xy;
+
+ vec4 motion;
+ motion.xy = prev_uv - curr_uv;
+ motion.zw = curr_uv - next_uv;
+ /* Convert NDC velocity to UV velocity */
+ motion *= 0.5;
+
+ return motion;
+}
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns uv space motion vectors in pairs (motion_prev.xy, motion_next.xy)
+ * \a velocity_camera is the motion in film UV space after camera projection.
+ * \a velocity_view is the motion in ShadingView UV space. It is different
+ * from velocity_camera for multi-view rendering.
+ */
+void velocity_camera(vec3 P_prev, vec3 P, vec3 P_next, out vec4 vel_camera, out vec4 vel_view)
+{
+ vec2 prev_uv, curr_uv, next_uv;
+ prev_uv = camera_uv_from_world(camera_prev, P_prev);
+ curr_uv = camera_uv_from_world(camera_curr, P);
+ next_uv = camera_uv_from_world(camera_next, P_next);
+
+ vel_camera.xy = prev_uv - curr_uv;
+ vel_camera.zw = curr_uv - next_uv;
+
+ if (is_panoramic(camera_curr.type)) {
+ /* This path is only used if using using panoramic projections. Since the views always have
+ * the same 45° aperture angle, we can safely reuse the projection matrix. */
+ prev_uv = transform_point(ProjectionMatrix, transform_point(camera_prev.viewmat, P_prev)).xy;
+ curr_uv = transform_point(ViewProjectionMatrix, P).xy;
+ next_uv = transform_point(ProjectionMatrix, transform_point(camera_next.viewmat, P_next)).xy;
+
+ vel_view.xy = prev_uv - curr_uv;
+ vel_view.zw = curr_uv - next_uv;
+ /* Convert NDC velocity to UV velocity */
+ vel_view *= 0.5;
+ }
+ else {
+ vel_view = vel_camera;
+ }
+}
+
+#endif
+
+#ifdef MAT_VELOCITY
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns a tuple of world space motion deltas.
+ */
+void velocity_local_pos_get(vec3 lP, int vert_id, out vec3 lP_prev, out vec3 lP_next)
+{
+ VelocityIndex vel = velocity_indirection_buf[resource_id];
+ lP_next = lP_prev = lP;
+ if (vel.geo.do_deform) {
+ if (vel.geo.ofs[STEP_PREVIOUS] != -1) {
+ lP_prev = velocity_geo_prev_buf[vel.geo.ofs[STEP_PREVIOUS] + vert_id].xyz;
+ }
+ if (vel.geo.ofs[STEP_NEXT] != -1) {
+ lP_next = velocity_geo_next_buf[vel.geo.ofs[STEP_NEXT] + vert_id].xyz;
+ }
+ }
+}
+
+/**
+ * Given a triple of position, compute the previous and next motion vectors.
+ * Returns a tuple of world space motion deltas.
+ */
+void velocity_vertex(
+ vec3 lP_prev, vec3 lP, vec3 lP_next, out vec3 motion_prev, out vec3 motion_next)
+{
+ VelocityIndex vel = velocity_indirection_buf[resource_id];
+ mat4 obmat_prev = velocity_obj_prev_buf[vel.obj.ofs[STEP_PREVIOUS]];
+ mat4 obmat_next = velocity_obj_next_buf[vel.obj.ofs[STEP_NEXT]];
+ vec3 P_prev = transform_point(obmat_prev, lP_prev);
+ vec3 P_next = transform_point(obmat_next, lP_next);
+ vec3 P = transform_point(ModelMatrix, lP);
+ motion_prev = P_prev - P;
+ motion_next = P_next - P;
+}
+
+#endif
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl
new file mode 100644
index 00000000000..b68b2eaf117
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_velocity_resolve_comp.glsl
@@ -0,0 +1,58 @@
+
+/**
+ * Fullscreen pass that compute motion vector for static geometry.
+ * Animated geometry has already written correct motion vectors.
+ */
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
+
+#define is_valid_output(img_) (imageSize(img_).x > 1)
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+ vec4 motion = imageLoad(velocity_view_img, texel);
+
+ bool pixel_has_valid_motion = (motion.x != VELOCITY_INVALID);
+ float depth = texelFetch(depth_tx, texel, 0).r;
+ bool is_background = (depth == 1.0f);
+
+ vec2 uv = vec2(texel) * drw_view.viewport_size_inverse;
+ vec3 P_next, P_prev, P_curr;
+
+ if (pixel_has_valid_motion) {
+ /* Animated geometry. View motion already computed during prepass. Convert only to camera. */
+ // P_prev = get_world_space_from_depth(uv + motion.xy, 0.5);
+ // P_curr = get_world_space_from_depth(uv, 0.5);
+ // P_next = get_world_space_from_depth(uv + motion.zw, 0.5);
+ return;
+ }
+ else if (is_background) {
+ /* NOTE: Use viewCameraVec to avoid imprecision if camera is far from origin. */
+ vec3 vV = viewCameraVec(get_view_space_from_depth(uv, 1.0));
+ vec3 V = transform_direction(ViewMatrixInverse, vV);
+ /* Background has no motion under camera translation. Translate view vector with the camera. */
+ /* WATCH(fclem): Might create precision issues. */
+ P_next = camera_next.viewinv[3].xyz + V;
+ P_curr = camera_curr.viewinv[3].xyz + V;
+ P_prev = camera_prev.viewinv[3].xyz + V;
+ }
+ else {
+ /* Static geometry. No translation in world space. */
+ P_curr = get_world_space_from_depth(uv, depth);
+ P_prev = P_curr;
+ P_next = P_curr;
+ }
+
+ vec4 vel_camera, vel_view;
+ velocity_camera(P_prev, P_curr, P_next, vel_camera, vel_view);
+
+ if (in_texture_range(texel, depth_tx)) {
+ imageStore(velocity_view_img, texel, vel_view);
+
+ if (is_valid_output(velocity_camera_img)) {
+ imageStore(velocity_camera_img, texel, vel_camera);
+ }
+ }
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index 4d6895bcde0..49250b5741e 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -22,6 +22,7 @@ GPU_SHADER_CREATE_INFO(eevee_sampling_data)
* \{ */
GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_MESH")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
@@ -29,16 +30,19 @@ GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
.additional_info("draw_mesh", "draw_resource_id_varying", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_gpencil)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_GPENCIL")
.vertex_source("eevee_geom_gpencil_vert.glsl")
.additional_info("draw_gpencil", "draw_resource_id_varying", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_curves)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_CURVES")
.vertex_source("eevee_geom_curves_vert.glsl")
.additional_info("draw_hair", "draw_resource_id_varying", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_world)
+ .additional_info("eevee_shared")
.define("MAT_GEOM_WORLD")
.builtins(BuiltinBits::VERTEX_ID)
.vertex_source("eevee_geom_world_vert.glsl")
@@ -66,7 +70,7 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
.vertex_out(eevee_surf_iface)
- /* Note: This removes the possibility of using gl_FragDepth. */
+ /* NOTE: This removes the possibility of using gl_FragDepth. */
// .early_fragment_test(true)
/* Direct output. */
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
@@ -95,7 +99,7 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward)
.fragment_source("eevee_surf_forward_frag.glsl")
// .additional_info("eevee_sampling_data",
// "eevee_lightprobe_data",
- /* Optionnally added depending on the material. */
+ /* Optionally added depending on the material. */
// "eevee_raytrace_data",
// "eevee_transmittance_data",
// "eevee_utility_texture",
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
new file mode 100644
index 00000000000..a5f16363466
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
@@ -0,0 +1,55 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Surface Velocity
+ *
+ * Combined with the depth prepass shader.
+ * Outputs the view motion vectors for animated objects.
+ * \{ */
+
+/* Pass world space deltas to the fragment shader.
+ * This is to make sure that the resulting motion vectors are valid even with displacement. */
+GPU_SHADER_INTERFACE_INFO(eevee_velocity_surface_iface, "motion")
+ .smooth(Type::VEC3, "prev")
+ .smooth(Type::VEC3, "next");
+
+GPU_SHADER_CREATE_INFO(eevee_velocity_camera)
+ .define("VELOCITY_CAMERA")
+ .uniform_buf(1, "CameraData", "camera_prev")
+ .uniform_buf(2, "CameraData", "camera_curr")
+ .uniform_buf(3, "CameraData", "camera_next");
+
+GPU_SHADER_CREATE_INFO(eevee_velocity_geom)
+ .define("MAT_VELOCITY")
+ .auto_resource_location(true)
+ .storage_buf(4, Qualifier::READ, "mat4", "velocity_obj_prev_buf[]", Frequency::PASS)
+ .storage_buf(5, Qualifier::READ, "mat4", "velocity_obj_next_buf[]", Frequency::PASS)
+ .storage_buf(6, Qualifier::READ, "vec4", "velocity_geo_prev_buf[]", Frequency::PASS)
+ .storage_buf(7, Qualifier::READ, "vec4", "velocity_geo_next_buf[]", Frequency::PASS)
+ .storage_buf(
+ 7, Qualifier::READ, "VelocityIndex", "velocity_indirection_buf[]", Frequency::PASS)
+ .vertex_out(eevee_velocity_surface_iface)
+ .fragment_out(0, Type::VEC4, "out_velocity_view")
+ .additional_info("eevee_velocity_camera");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Velocity Resolve
+ *
+ * Computes velocity for static objects.
+ * Also converts motion to camera space (as opposed to view space) if needed.
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(eevee_velocity_resolve)
+ .do_static_compilation(true)
+ .local_group_size(8, 8)
+ .sampler(0, ImageType::DEPTH_2D, "depth_tx")
+ .image(0, GPU_RG16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "velocity_view_img")
+ .image(1, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "velocity_camera_img")
+ .additional_info("eevee_shared")
+ .compute_source("eevee_velocity_resolve_comp.glsl")
+ .additional_info("draw_view", "eevee_velocity_camera");
+
+/** \} */
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 40ebd262df5..ec44fdf42d5 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -290,7 +290,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
/* Masking: Go through mask list and extract valid masks in a bitmap. */
if (is_masked) {
bool valid_mask = false;
- /* Warning: only GP_MAX_MASKBITS amount of bits.
+ /* WARNING: only #GP_MAX_MASKBITS amount of bits.
* TODO(fclem): Find a better system without any limitation. */
tgp_layer->mask_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
tgp_layer->mask_invert_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 19afdb3de5a..c7ef8677336 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -61,10 +61,10 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
/* Depth need to be remapped to [0..1] range. */
pix_z = MEM_dupallocN(pix_z);
- int pix_ct = rpass_z_src->rectx * rpass_z_src->recty;
+ int pix_num = rpass_z_src->rectx * rpass_z_src->recty;
if (DRW_view_is_persp_get(view)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
}
@@ -74,7 +74,7 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
float near = DRW_view_near_distance_get(view);
float far = DRW_view_far_distance_get(view);
float range_inv = 1.0f / fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
pix_z[i] = (pix_z[i] + near) * range_inv;
pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
}
@@ -172,11 +172,11 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
- int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert GPU depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -192,7 +192,7 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index 5c5226bfe65..9531b0dd983 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -124,7 +124,7 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
}
}
- /* Handles and curve point for Curve Edit submode. */
+ /* Handles and curve point for Curve Edit sub-mode. */
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
DRWState state = DRW_STATE_WRITE_COLOR;
DRW_PASS_CREATE(psl->edit_gpencil_curve_ps, state | pd->clipping_state);
@@ -297,7 +297,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
}
const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
- int line_ct = gridlines * 4 + 2;
+ const int line_count = gridlines * 4 + 2;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL;
@@ -311,8 +311,8 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]);
DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]);
DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]);
- DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2);
- DRW_shgroup_call_procedural_lines(grp, NULL, line_ct);
+ DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_count / 2);
+ DRW_shgroup_call_procedural_lines(grp, NULL, line_count);
}
}
diff --git a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
index a765d881682..b9b1b73dbd4 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
@@ -284,7 +284,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_particle_iface, "").flat(Type::VEC4, "finalCol
GPU_SHADER_CREATE_INFO(overlay_particle)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
- .push_constant(Type::VEC4, "color") /* Drawsize packed in alpha */
+ .push_constant(Type::VEC4, "color") /* Draw-size packed in alpha. */
.vertex_in(0, Type::VEC3, "part_pos")
.vertex_in(1, Type::VEC4, "part_rot")
.vertex_in(2, Type::FLOAT, "part_val")
diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
index 713c8c2dc4b..5853e974eeb 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
@@ -48,7 +48,7 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity_needle)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Volume Gridlines
+/** \name Volume Grid-Lines
* \{ */
GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, "finalColor");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
index 43367121d6a..16b59f6bb7d 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
@@ -21,7 +21,7 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.sampler(0, ImageType::DEPTH_2D, "depthTex")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
- .vertex_in(2, Type::FLOAT, "wd") /* wiredata */
+ .vertex_in(2, Type::FLOAT, "wd") /* wire-data. */
.vertex_out(overlay_wireframe_iface)
.vertex_source("wireframe_vert.glsl")
.fragment_source("wireframe_frag.glsl")
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index c33bb474d96..3e3c0e4e89f 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -347,7 +347,7 @@ void main()
line_end = vec2(0.0, 0.5);
break;
default:
- /* Ensure values are assigned to, avoids undefined behaviour for
+ /* Ensure values are assigned to, avoids undefined behavior for
* divergent control-flow. This can occur if discard is called
* as discard is not treated as a return in Metal 2.2. So
* side-effects can still cause problems. */
diff --git a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
index ad0de61ffc3..e3166582197 100644
--- a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
+++ b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh
@@ -3,7 +3,7 @@
#include "gpu_shader_create_info.hh"
/* -------------------------------------------------------------------- */
-/** \name Select ID fo Edit Mesh selection
+/** \name Select ID for Edit Mesh Selection
* \{ */
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "id");
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
index e2a54788c72..735e7b6d867 100644
--- a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
@@ -91,7 +91,7 @@ GPU_SHADER_CREATE_INFO(workbench_material)
* \{ */
GPU_SHADER_CREATE_INFO(workbench_transparent_accum)
- /* Note: Blending will be skipped on objectId because output is a
+ /* NOTE: Blending will be skipped on objectId because output is a
* non-normalized integer buffer. */
.fragment_out(0, Type::VEC4, "transparentAccum")
.fragment_out(1, Type::VEC4, "revealageAccum")
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 36059b6076f..49e26cd3e0c 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -218,13 +218,13 @@ void main()
/* Manual depth test. TODO: remove. */
float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
if (gl_FragCoord.z >= depth) {
- /* Note: In the Metal API, prior to Metal 2.3, Discard is not an explicit return and can
- * produce undefined behaviour. This is especially prominent with derivatives if control-flow
+ /* NOTE: In the Metal API, prior to Metal 2.3, Discard is not an explicit return and can
+ * produce undefined behavior. This is especially prominent with derivatives if control-flow
* divergence is present.
*
- * Adding a return call eliminates undefined behaviour and a later out-of-bounds read causing
+ * Adding a return call eliminates undefined behavior and a later out-of-bounds read causing
* a crash on AMD platforms.
- * This behaviour can also affect OpenGL on certain devices. */
+ * This behavior can also affect OpenGL on certain devices. */
discard;
return;
}
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 1279682e899..e5dcf6c5624 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -115,11 +115,11 @@ static void workbench_render_result_z(struct RenderLayer *rl,
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
- int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ int pix_num = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
/* Convert ogl depth [0..1] to view Z [near..far] */
if (DRW_view_is_persp_get(NULL)) {
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
@@ -135,7 +135,7 @@ static void workbench_render_result_z(struct RenderLayer *rl,
float far = DRW_view_far_distance_get(NULL);
float range = fabsf(far - near);
- for (int i = 0; i < pix_ct; i++) {
+ for (int i = 0; i < pix_num; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 2c902e9b627..ce7773e7439 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -124,12 +124,12 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
double noise_ofs;
BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs);
float dim[3], step_length, max_slice;
- float slice_ct[3] = {fds->res[0], fds->res[1], fds->res[2]};
- mul_v3_fl(slice_ct, max_ff(0.001f, fds->slice_per_voxel));
- max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
+ float slice_count[3] = {fds->res[0], fds->res[1], fds->res[2]};
+ mul_v3_fl(slice_count, max_ff(0.001f, fds->slice_per_voxel));
+ max_slice = max_fff(slice_count[0], slice_count[1], slice_count[2]);
BKE_object_dimensions_get(ob, dim);
- invert_v3(slice_ct);
- mul_v3_v3(dim, slice_ct);
+ invert_v3(slice_count);
+ mul_v3_v3(dim, slice_count);
step_length = len_v3(dim);
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
@@ -273,12 +273,12 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
float step_length, max_slice;
int resolution[3];
GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
- float slice_ct[3] = {resolution[0], resolution[1], resolution[2]};
- mul_v3_fl(slice_ct, max_ff(0.001f, 5.0f));
- max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
- invert_v3(slice_ct);
- mul_v3_v3(slice_ct, world_size);
- step_length = len_v3(slice_ct);
+ float slice_count[3] = {resolution[0], resolution[1], resolution[2]};
+ mul_v3_fl(slice_count, max_ff(0.001f, 5.0f));
+ max_slice = max_fff(slice_count[0], slice_count[1], slice_count[2]);
+ invert_v3(slice_count);
+ mul_v3_v3(slice_count, world_size);
+ step_length = len_v3(slice_count);
/* Set uniforms. */
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index d7e752a43f4..257f01a5562 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -102,7 +102,7 @@ class DataBuffer {
{
BLI_STATIC_ASSERT(!device_only, "");
BLI_assert(index >= 0);
- BLI_assert(index < len);
+ BLI_assert(index < len_);
return data_[index];
}
@@ -110,7 +110,7 @@ class DataBuffer {
{
BLI_STATIC_ASSERT(!device_only, "");
BLI_assert(index >= 0);
- BLI_assert(index < len);
+ BLI_assert(index < len_);
return data_[index];
}
@@ -139,7 +139,7 @@ class DataBuffer {
const T *end() const
{
BLI_STATIC_ASSERT(!device_only, "");
- return data_ + len;
+ return data_ + len_;
}
T *begin()
@@ -150,13 +150,13 @@ class DataBuffer {
T *end()
{
BLI_STATIC_ASSERT(!device_only, "");
- return data_ + len;
+ return data_ + len_;
}
operator Span<T>() const
{
BLI_STATIC_ASSERT(!device_only, "");
- return Span<T>(data_, len);
+ return Span<T>(data_, len_);
}
};
@@ -217,7 +217,9 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
if (name) {
name_ = name;
}
- init(len);
+ this->len_ = len;
+ constexpr GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
+ ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
}
~StorageCommon()
@@ -225,15 +227,6 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
GPU_storagebuf_free(ssbo_);
}
- void resize(int64_t new_size)
- {
- BLI_assert(new_size > 0);
- if (new_size != this->len_) {
- GPU_storagebuf_free(ssbo_);
- this->init(new_size);
- }
- }
-
void push_update(void)
{
BLI_assert(device_only == false);
@@ -249,14 +242,6 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
{
return &ssbo_;
}
-
- private:
- void init(int64_t new_size)
- {
- this->len_ = new_size;
- GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
- ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
- }
};
} // namespace detail
@@ -333,6 +318,34 @@ class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
{
MEM_freeN(this->data_);
}
+
+ void resize(int64_t new_size)
+ {
+ BLI_assert(new_size > 0);
+ if (new_size != this->len_) {
+ /* Manual realloc since MEM_reallocN_aligned does not exists. */
+ T *new_data_ = (T *)MEM_mallocN_aligned(new_size * sizeof(T), 16, this->name_);
+ memcpy(new_data_, this->data_, min_uu(this->len_, new_size) * sizeof(T));
+ MEM_freeN(this->data_);
+ this->data_ = new_data_;
+ GPU_storagebuf_free(this->ssbo_);
+
+ this->len_ = new_size;
+ constexpr GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
+ this->ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
+ }
+ }
+
+ /* Resize on access. */
+ T &get_or_resize(int64_t index)
+ {
+ BLI_assert(index >= 0);
+ if (index >= this->len_) {
+ size_t size = power_of_2_max_u(index + 1);
+ this->resize(size);
+ }
+ return this->data_[index];
+ }
};
template<
@@ -880,4 +893,56 @@ class Framebuffer : NonCopyable {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Double & Triple buffering util
+ *
+ * This is not strictly related to a GPU type and could be moved elsewhere.
+ * \{ */
+
+template<typename T, int64_t len> class SwapChain {
+ private:
+ std::array<T, len> chain_;
+ int64_t index_ = 0;
+
+ public:
+ void swap()
+ {
+ index_ = (index_ + 1) % len;
+ }
+
+ T &current()
+ {
+ return chain_[index_];
+ }
+
+ T &previous()
+ {
+ /* Avoid modulo operation with negative numbers. */
+ return chain_[(index_ + len - 1) % len];
+ }
+
+ T &next()
+ {
+ return chain_[(index_ + 1) % len];
+ }
+
+ const T &current() const
+ {
+ return chain_[index_];
+ }
+
+ const T &previous() const
+ {
+ /* Avoid modulo operation with negative numbers. */
+ return chain_[(index_ + len - 1) % len];
+ }
+
+ const T &next() const
+ {
+ return chain_[(index_ + 1) % len];
+ }
+};
+
+/** \} */
+
} // namespace blender::draw
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 712118e8282..07105757b2c 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -296,6 +296,8 @@ void DRW_shader_library_free(DRWShaderLibrary *lib);
* therefore they aren't ordered as a bit mask.
*/
typedef enum {
+ /** To be used for compute passes. */
+ DRW_STATE_NO_DRAW = 0,
/** Write mask */
DRW_STATE_WRITE_DEPTH = (1 << 0),
DRW_STATE_WRITE_COLOR = (1 << 1),
@@ -430,12 +432,12 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
DRW_shgroup_call_ex(shgroup, ob, NULL, geom, true, NULL)
void DRW_shgroup_call_range(
- DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_num);
/**
* A count of 0 instance will use the default number of instance in the batch.
*/
void DRW_shgroup_call_instance_range(
- DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct);
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_num);
void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
int groups_x_len,
@@ -621,6 +623,12 @@ void DRW_shgroup_vertex_buffer_ex(DRWShadingGroup *shgroup,
void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
const char *name,
struct GPUVertBuf **vertex_buffer DRW_DEBUG_FILE_LINE_ARGS);
+void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup,
+ const char *name,
+ struct GPUVertBuf *vertex_buffer);
+void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
+ const char *name,
+ struct GPUVertBuf **vertex_buffer);
#ifdef DRW_UNUSED_RESOURCE_TRACKING
# define DRW_shgroup_vertex_buffer(shgroup, name, vert) \
@@ -738,6 +746,7 @@ const DRWView *DRW_view_get_active(void);
*/
void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len);
void DRW_view_camtexco_set(DRWView *view, float texco[4]);
+void DRW_view_camtexco_get(const DRWView *view, float r_texco[4]);
/* For all getters, if view is NULL, default view is assumed. */
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
new file mode 100644
index 00000000000..714f1dbb3d1
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#include "draw_attributes.h"
+
+/* Return true if the given DRW_AttributeRequest is already in the requests. */
+static bool drw_attributes_has_request(const DRW_Attributes *requests, DRW_AttributeRequest req)
+{
+ for (int i = 0; i < requests->num_requests; i++) {
+ const DRW_AttributeRequest src_req = requests->requests[i];
+ if (src_req.domain != req.domain) {
+ continue;
+ }
+ if (src_req.layer_index != req.layer_index) {
+ continue;
+ }
+ if (src_req.cd_type != req.cd_type) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+static void drw_attributes_merge_requests(const DRW_Attributes *src_requests,
+ DRW_Attributes *dst_requests)
+{
+ for (int i = 0; i < src_requests->num_requests; i++) {
+ if (dst_requests->num_requests == GPU_MAX_ATTR) {
+ return;
+ }
+
+ if (drw_attributes_has_request(dst_requests, src_requests->requests[i])) {
+ continue;
+ }
+
+ dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
+ dst_requests->num_requests += 1;
+ }
+}
+
+void drw_attributes_clear(DRW_Attributes *attributes)
+{
+ memset(attributes, 0, sizeof(DRW_Attributes));
+}
+
+void drw_attributes_merge(DRW_Attributes *dst,
+ const DRW_Attributes *src,
+ ThreadMutex *render_mutex)
+{
+ BLI_mutex_lock(render_mutex);
+ drw_attributes_merge_requests(src, dst);
+ BLI_mutex_unlock(render_mutex);
+}
+
+bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b)
+{
+ for (int i = 0; i < b->num_requests; i++) {
+ if (!drw_attributes_has_request(a, b->requests[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain)
+{
+ if (attrs->num_requests >= GPU_MAX_ATTR) {
+ return nullptr;
+ }
+
+ DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
+ req->cd_type = type;
+ req->layer_index = layer;
+ req->domain = domain;
+ attrs->num_requests += 1;
+ return req;
+}
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *r_type)
+{
+ const int possible_attribute_types[7] = {
+ CD_PROP_BOOL,
+ CD_PROP_INT8,
+ CD_PROP_INT32,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT2,
+ CD_PROP_FLOAT3,
+ CD_PROP_COLOR,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
+ const int attr_type = possible_attribute_types[i];
+ int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
+ if (layer_index == -1) {
+ continue;
+ }
+
+ *r_layer_index = layer_index;
+ *r_type = attr_type;
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
new file mode 100644
index 00000000000..192ffa43337
--- /dev/null
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup draw
+ *
+ * \brief Utilities for rendering attributes.
+ */
+
+#pragma once
+
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute.h"
+
+#include "BLI_sys_types.h"
+#include "BLI_threads.h"
+
+#include "GPU_shader.h"
+#include "GPU_vertex_format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DRW_AttributeRequest {
+ CustomDataType cd_type;
+ int layer_index;
+ AttributeDomain domain;
+ char attribute_name[64];
+} DRW_AttributeRequest;
+
+typedef struct DRW_Attributes {
+ DRW_AttributeRequest requests[GPU_MAX_ATTR];
+ int num_requests;
+} DRW_Attributes;
+
+void drw_attributes_clear(DRW_Attributes *attributes);
+
+void drw_attributes_merge(DRW_Attributes *dst,
+ const DRW_Attributes *src,
+ ThreadMutex *render_mutex);
+
+/* Return true if all requests in b are in a. */
+bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b);
+
+DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
+ CustomDataType type,
+ int layer,
+ AttributeDomain domain);
+
+bool drw_custom_data_match_attribute(const CustomData *custom_data,
+ const char *name,
+ int *r_layer_index,
+ int *r_type);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 67700a4274f..fb074cc728e 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3400,6 +3400,9 @@ void DRW_batch_cache_free_old(Object *ob, int ctime)
case OB_MESH:
DRW_mesh_batch_cache_free_old((Mesh *)ob->data, ctime);
break;
+ case OB_CURVES:
+ DRW_curves_batch_cache_free_old((Curves *)ob->data, ctime);
+ break;
/* TODO: all cases. */
default:
break;
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index cb6006e303a..ce3ad9923da 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -20,6 +20,8 @@ struct TaskGraph;
#include "GPU_index_buffer.h"
#include "GPU_vertex_buffer.h"
+#include "draw_attributes.h"
+
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
int defgroup_active;
@@ -67,17 +69,6 @@ typedef enum eMRIterType {
} eMRIterType;
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
-typedef struct DRW_AttributeRequest {
- CustomDataType cd_type;
- int layer_index;
- AttributeDomain domain;
-} DRW_AttributeRequest;
-
-typedef struct DRW_MeshAttributes {
- DRW_AttributeRequest requests[GPU_MAX_ATTR];
- int num_requests;
-} DRW_MeshAttributes;
-
typedef enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
@@ -294,7 +285,7 @@ typedef struct MeshBatchCache {
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
- DRW_MeshAttributes attr_used, attr_needed, attr_used_over_time;
+ DRW_Attributes attr_used, attr_needed, attr_used_over_time;
int lastmatch;
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index ec544d8e786..3d44d3d1b3f 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -793,7 +793,12 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/* The order in which extractors are added to the list matters somewhat, as some buffers are
* reused when building others. */
EXTRACT_ADD_REQUESTED(ibo, tris);
- EXTRACT_ADD_REQUESTED(vbo, pos_nor);
+
+ /* Orcos are extracted at the same time as positions. */
+ if (DRW_vbo_requested(mbuflist->vbo.pos_nor) || DRW_vbo_requested(mbuflist->vbo.orco)) {
+ extractors.append(&extract_pos_nor);
+ }
+
EXTRACT_ADD_REQUESTED(vbo, lnor);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
@@ -843,7 +848,6 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
- EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, vcol);
EXTRACT_ADD_REQUESTED(vbo, weights);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index f877c94208f..0755d5967d5 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -83,6 +83,7 @@ void DRW_batch_cache_free_old(struct Object *ob, int ctime);
* \note For now this only free the shading batches / VBO if any cd layers is not needed anymore.
*/
void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
+void DRW_curves_batch_cache_free_old(struct Curves *curves, int ctime);
/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index 7b8f34b999c..ebcdabe4942 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -108,7 +108,7 @@ static void curve_eval_render_wire_verts_edges_len_get(const blender::bke::Curve
const blender::VArray<bool> cyclic = curves.cyclic();
for (const int i : curves.curves_range()) {
const IndexRange points = curves.evaluated_points_for_curve(i);
- *r_edge_len += blender::bke::curves::curve_segment_size(points.size(), cyclic[i]);
+ *r_edge_len += blender::bke::curves::curve_segment_num(points.size(), cyclic[i]);
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index f2742f3bcc7..f9cf0021fcd 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -24,6 +24,7 @@
#include "DNA_scene_types.h"
#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "GPU_batch.h"
#include "GPU_material.h"
@@ -31,12 +32,16 @@
#include "DRW_render.h"
+#include "draw_attributes.h"
#include "draw_cache_impl.h" /* own include */
#include "draw_cache_inline.h"
#include "draw_curves_private.h" /* own include */
+#include "draw_shader.h"
+using blender::ColorGeometry4f;
using blender::float3;
using blender::IndexRange;
+using blender::MutableSpan;
using blender::Span;
/* ---------------------------------------------------------------------- */
@@ -49,6 +54,10 @@ struct CurvesBatchCache {
/* To determine if cache is invalid. */
bool is_dirty;
+
+ /** Needed when updating material data (e.g. attributes) as the same curves might be used for
+ * multiple objects with different materials. */
+ ThreadMutex render_mutex;
};
static bool curves_batch_cache_valid(const Curves &curves)
@@ -63,6 +72,7 @@ static void curves_batch_cache_init(Curves &curves)
if (!cache) {
cache = MEM_cnew<CurvesBatchCache>(__func__);
+ BLI_mutex_init(&cache->render_mutex);
curves.batch_cache = cache;
}
else {
@@ -72,6 +82,23 @@ static void curves_batch_cache_init(Curves &curves)
cache->is_dirty = false;
}
+static void curves_discard_attributes(CurvesEvalCache &curves_cache)
+{
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]);
+ }
+
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (int j = 0; j < GPU_MAX_ATTR; j++) {
+ GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]);
+ DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]);
+ }
+
+ drw_attributes_clear(&curves_cache.final[i].attr_used);
+ }
+}
+
static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
{
/* TODO: more granular update tagging. */
@@ -92,6 +119,8 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
}
}
+
+ curves_discard_attributes(curves_cache);
}
static void curves_batch_cache_clear(Curves &curves)
@@ -138,55 +167,89 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
void DRW_curves_batch_cache_free(Curves *curves)
{
curves_batch_cache_clear(*curves);
+ CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
+ BLI_mutex_end(&cache->render_mutex);
MEM_SAFE_FREE(curves->batch_cache);
}
+void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
+{
+ CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
+ if (cache == nullptr) {
+ return;
+ }
+
+ bool do_discard = false;
+
+ for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ CurvesEvalFinalCache &final_cache = cache->curves_cache.final[i];
+
+ if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) {
+ final_cache.last_attr_matching_time = ctime;
+ }
+
+ if (ctime - final_cache.last_attr_matching_time > U.vbotimeout) {
+ do_discard = true;
+ }
+
+ drw_attributes_clear(&final_cache.attr_used_over_time);
+ }
+
+ if (do_discard) {
+ curves_discard_attributes(cache->curves_cache);
+ }
+}
+
static void ensure_seg_pt_count(const Curves &curves, CurvesEvalCache &curves_cache)
{
if (curves_cache.proc_point_buf != nullptr) {
return;
}
- curves_cache.strands_len = curves.geometry.curve_size;
- curves_cache.elems_len = curves.geometry.point_size + curves.geometry.curve_size;
- curves_cache.point_len = curves.geometry.point_size;
+ curves_cache.strands_len = curves.geometry.curve_num;
+ curves_cache.elems_len = curves.geometry.point_num + curves.geometry.curve_num;
+ curves_cache.point_len = curves.geometry.point_num;
}
-static void curves_batch_cache_fill_segments_proc_pos(const Curves &curves_id,
- GPUVertBufRaw &attr_step,
- GPUVertBufRaw &length_step)
+struct PositionAndParameter {
+ float3 position;
+ float parameter;
+};
+
+static void curves_batch_cache_fill_segments_proc_pos(
+ const Curves &curves_id,
+ MutableSpan<PositionAndParameter> posTime_data,
+ MutableSpan<float> hairLength_data)
{
/* TODO: use hair radius layer if available. */
- const int curve_size = curves_id.geometry.curve_size;
+ const int curve_num = curves_id.geometry.curve_num;
const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
curves_id.geometry);
Span<float3> positions = curves.positions();
- for (const int i : IndexRange(curve_size)) {
- const IndexRange curve_range = curves.points_for_curve(i);
+ for (const int i_curve : IndexRange(curve_num)) {
+ const IndexRange points = curves.points_for_curve(i_curve);
+
+ Span<float3> curve_positions = positions.slice(points);
+ MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points);
- Span<float3> curve_positions = positions.slice(curve_range);
float total_len = 0.0f;
- float *seg_data_first;
- for (const int i_curve : curve_positions.index_range()) {
- float *seg_data = (float *)GPU_vertbuf_raw_step(&attr_step);
- copy_v3_v3(seg_data, curve_positions[i_curve]);
- if (i_curve == 0) {
- seg_data_first = seg_data;
- }
- else {
- total_len += blender::math::distance(curve_positions[i_curve - 1],
- curve_positions[i_curve]);
+ for (const int i_point : curve_positions.index_range()) {
+ if (i_point > 0) {
+ total_len += blender::math::distance(curve_positions[i_point - 1],
+ curve_positions[i_point]);
}
- seg_data[3] = total_len;
+ curve_posTime_data[i_point].position = curve_positions[i_point];
+ curve_posTime_data[i_point].parameter = total_len;
}
+ hairLength_data[i_curve] = total_len;
+
/* Assign length value. */
- *(float *)GPU_vertbuf_raw_step(&length_step) = total_len;
if (total_len > 0.0f) {
+ const float factor = 1.0f / total_len;
/* Divide by total length to have a [0-1] number. */
- for ([[maybe_unused]] const int i_curve : curve_positions.index_range()) {
- seg_data_first[3] /= total_len;
- seg_data_first += 4;
+ for (const int i_point : curve_positions.index_range()) {
+ curve_posTime_data[i_point].parameter *= factor;
}
}
}
@@ -199,26 +262,26 @@ static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
if (cache.proc_point_buf == nullptr || DRW_vbo_requested(cache.proc_point_buf)) {
/* Initialize vertex format. */
GPUVertFormat format = {0};
- uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "pos");
cache.proc_point_buf = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(cache.proc_point_buf, cache.point_len);
- GPUVertBufRaw point_step;
- GPU_vertbuf_attr_get_raw_data(cache.proc_point_buf, pos_id, &point_step);
+ MutableSpan posTime_data{
+ reinterpret_cast<PositionAndParameter *>(GPU_vertbuf_get_data(cache.proc_point_buf)),
+ cache.point_len};
GPUVertFormat length_format = {0};
- uint length_id = GPU_vertformat_attr_add(
- &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
cache.proc_length_buf = GPU_vertbuf_create_with_format(&length_format);
GPU_vertbuf_data_alloc(cache.proc_length_buf, cache.strands_len);
- GPUVertBufRaw length_step;
- GPU_vertbuf_attr_get_raw_data(cache.proc_length_buf, length_id, &length_step);
+ MutableSpan hairLength_data{
+ reinterpret_cast<float *>(GPU_vertbuf_get_data(cache.proc_length_buf)), cache.strands_len};
- curves_batch_cache_fill_segments_proc_pos(curves, point_step, length_step);
+ curves_batch_cache_fill_segments_proc_pos(curves, posTime_data, hairLength_data);
/* Create vbo immediately to bind to texture buffer. */
GPU_vertbuf_use(cache.proc_point_buf);
@@ -237,6 +300,88 @@ static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
}
}
+void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32])
+{
+ char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+ /* Attributes use auto-name. */
+ BLI_snprintf(r_sampler_name, 32, "a%s", attr_safe_name);
+}
+
+static void curves_batch_cache_ensure_procedural_final_attr(
+ CurvesEvalCache &cache, GPUVertFormat *format, int subdiv, int index, const char *name)
+{
+ CurvesEvalFinalCache &final_cache = cache.final[subdiv];
+ final_cache.attributes_buf[index] = GPU_vertbuf_create_with_format_ex(format,
+ GPU_USAGE_DEVICE_ONLY);
+
+ /* Create a destination buffer for the transform feedback. Sized appropriately */
+ /* Those are points! not line segments. */
+ GPU_vertbuf_data_alloc(final_cache.attributes_buf[index],
+ final_cache.strands_res * cache.strands_len);
+
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(final_cache.attributes_buf[index]);
+
+ final_cache.attributes_tex[index] = GPU_texture_create_from_vertbuf(
+ name, final_cache.attributes_buf[index]);
+}
+
+static void curves_batch_ensure_attribute(const Curves &curves,
+ CurvesEvalCache &cache,
+ const DRW_AttributeRequest &request,
+ int subdiv,
+ int index)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]);
+ DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]);
+
+ char sampler_name[32];
+ drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name);
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_deinterleave(&format);
+ /* All attributes use vec4, see comment below. */
+ GPU_vertformat_attr_add(&format, sampler_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ cache.proc_attributes_buf[index] = GPU_vertbuf_create_with_format(&format);
+ GPUVertBuf *attr_vbo = cache.proc_attributes_buf[index];
+
+ GPU_vertbuf_data_alloc(attr_vbo,
+ request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num :
+ curves.geometry.curve_num);
+
+ CurveComponent component;
+ component.replace(const_cast<Curves *>(&curves), GeometryOwnershipType::ReadOnly);
+
+ /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
+ * by OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following
+ * the Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a
+ * similar texture state swizzle to map the attribute correctly as for volume attributes, so we
+ * can control the conversion ourselves. */
+ blender::VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f});
+
+ MutableSpan<ColorGeometry4f> vbo_span{
+ static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_vbo)),
+ component.attribute_domain_num(request.domain)};
+
+ attribute.materialize(vbo_span);
+
+ GPU_vertbuf_use(attr_vbo);
+ cache.proc_attributes_tex[index] = GPU_texture_create_from_vertbuf(sampler_name, attr_vbo);
+
+ /* Existing final data may have been for a different attribute (with a different name or domain),
+ * free the data. */
+ GPU_VERTBUF_DISCARD_SAFE(cache.final[subdiv].attributes_buf[index]);
+ DRW_TEXTURE_FREE_SAFE(cache.final[subdiv].attributes_tex[index]);
+
+ /* Ensure final data for points. */
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ curves_batch_cache_ensure_procedural_final_attr(cache, &format, subdiv, index, sampler_name);
+ }
+}
+
static void curves_batch_cache_fill_strands_data(const Curves &curves_id,
GPUVertBufRaw &data_step,
GPUVertBufRaw &seg_step)
@@ -307,7 +452,7 @@ static void curves_batch_cache_fill_segments_indices(const Curves &curves,
const int res,
GPUIndexBufBuilder &elb)
{
- const int curves_num = curves.geometry.curve_size;
+ const int curves_num = curves.geometry.curve_num;
uint curr_point = 0;
@@ -353,6 +498,88 @@ static void curves_batch_cache_ensure_procedural_indices(Curves &curves,
prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
}
+static bool curves_ensure_attributes(const Curves &curves,
+ CurvesBatchCache &cache,
+ GPUMaterial *gpu_material,
+ int subdiv)
+{
+ ThreadMutex *render_mutex = &cache.render_mutex;
+ const CustomData *cd_curve = &curves.geometry.curve_data;
+ const CustomData *cd_point = &curves.geometry.point_data;
+
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ const char *name = gpu_attr->name;
+ int type = gpu_attr->type;
+ int layer = -1;
+ AttributeDomain domain;
+
+ if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_CURVE;
+ }
+ else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else {
+ continue;
+ }
+
+ switch (type) {
+ default:
+ break;
+ case CD_PROP_BOOL:
+ case CD_PROP_INT8:
+ case CD_PROP_INT32:
+ case CD_PROP_FLOAT:
+ case CD_PROP_FLOAT2:
+ case CD_PROP_FLOAT3:
+ case CD_PROP_COLOR: {
+ if (layer != -1) {
+ DRW_AttributeRequest *req = drw_attributes_add_request(
+ &attrs_needed, (CustomDataType)type, layer, domain);
+ if (req) {
+ BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+
+ const bool attr_overlap = drw_attributes_overlap(&final_cache.attr_used, &attrs_needed);
+ if (attr_overlap == false) {
+ /* Some new attributes have been added, free all and start over. */
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
+ }
+ drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex);
+ }
+ drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex);
+
+ bool need_tf_update = false;
+
+ for (int i = 0; i < final_cache.attr_used.num_requests; i++) {
+ const DRW_AttributeRequest &request = final_cache.attr_used.requests[i];
+
+ if (cache.curves_cache.proc_attributes_buf[i] != nullptr) {
+ continue;
+ }
+
+ if (request.domain == ATTR_DOMAIN_POINT) {
+ need_tf_update = true;
+ }
+
+ curves_batch_ensure_attribute(curves, cache.curves_cache, request, subdiv, i);
+ }
+
+ return need_tf_update;
+}
+
bool curves_ensure_procedural_data(Object *object,
CurvesEvalCache **r_hair_cache,
GPUMaterial *gpu_material,
@@ -390,6 +617,10 @@ bool curves_ensure_procedural_data(Object *object,
curves, cache.curves_cache, thickness_res, subdiv);
}
+ if (gpu_material) {
+ need_ft_update |= curves_ensure_attributes(curves, cache, gpu_material, subdiv);
+ }
+
return need_ft_update;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index dac4b7488be..a6ab2176d16 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -281,91 +281,6 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
-/** \name DRW_MeshAttributes
- *
- * Utilities for handling requested attributes.
- * \{ */
-
-/* Return true if the given DRW_AttributeRequest is already in the requests. */
-static bool has_request(const DRW_MeshAttributes *requests, DRW_AttributeRequest req)
-{
- for (int i = 0; i < requests->num_requests; i++) {
- const DRW_AttributeRequest src_req = requests->requests[i];
- if (src_req.domain != req.domain) {
- continue;
- }
- if (src_req.layer_index != req.layer_index) {
- continue;
- }
- if (src_req.cd_type != req.cd_type) {
- continue;
- }
- return true;
- }
- return false;
-}
-
-static void mesh_attrs_merge_requests(const DRW_MeshAttributes *src_requests,
- DRW_MeshAttributes *dst_requests)
-{
- for (int i = 0; i < src_requests->num_requests; i++) {
- if (dst_requests->num_requests == GPU_MAX_ATTR) {
- return;
- }
-
- if (has_request(dst_requests, src_requests->requests[i])) {
- continue;
- }
-
- dst_requests->requests[dst_requests->num_requests] = src_requests->requests[i];
- dst_requests->num_requests += 1;
- }
-}
-
-static void drw_mesh_attributes_clear(DRW_MeshAttributes *attributes)
-{
- memset(attributes, 0, sizeof(DRW_MeshAttributes));
-}
-
-static void drw_mesh_attributes_merge(DRW_MeshAttributes *dst,
- const DRW_MeshAttributes *src,
- ThreadMutex *mesh_render_mutex)
-{
- BLI_mutex_lock(mesh_render_mutex);
- mesh_attrs_merge_requests(src, dst);
- BLI_mutex_unlock(mesh_render_mutex);
-}
-
-/* Return true if all requests in b are in a. */
-static bool drw_mesh_attributes_overlap(DRW_MeshAttributes *a, DRW_MeshAttributes *b)
-{
- for (int i = 0; i < b->num_requests; i++) {
- if (!has_request(a, b->requests[i])) {
- return false;
- }
- }
-
- return true;
-}
-
-static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
- CustomDataType type,
- int layer,
- AttributeDomain domain)
-{
- if (attrs->num_requests >= GPU_MAX_ATTR) {
- return;
- }
-
- DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
- req->cd_type = type;
- req->layer_index = layer;
- req->domain = domain;
- attrs->num_requests += 1;
-}
-
-/** \} */
-
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
@@ -475,36 +390,6 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
}
}
-static bool custom_data_match_attribute(const CustomData *custom_data,
- const char *name,
- int *r_layer_index,
- int *r_type)
-{
- const int possible_attribute_types[7] = {
- CD_PROP_BOOL,
- CD_PROP_INT8,
- CD_PROP_INT32,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT2,
- CD_PROP_FLOAT3,
- CD_PROP_COLOR,
- };
-
- for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
- const int attr_type = possible_attribute_types[i];
- int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
- if (layer_index == -1) {
- continue;
- }
-
- *r_layer_index = layer_index;
- *r_type = attr_type;
- return true;
- }
-
- return false;
-}
-
static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
@@ -531,7 +416,7 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
layer_i;
}
- /* Note: this is not the same as the layer_i below. */
+ /* NOTE: this is not the same as the layer_i below. */
if (layer_i != -1) {
layer = (domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata)->layers + layer_i;
}
@@ -544,7 +429,7 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
return -1;
}
- /* Note: this is the logical index into the color attribute list,
+ /* NOTE: this is the logical index into the color attribute list,
* not the customdata index. */
int vcol_i = BKE_id_attribute_to_index(
(ID *)me_query, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -556,7 +441,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const Mesh *me,
struct GPUMaterial **gpumat_array,
int gpumat_array_len,
- DRW_MeshAttributes *attributes)
+ DRW_Attributes *attributes)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
@@ -636,16 +521,16 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
if (layer == -1) {
/* Try to match a generic attribute, we use the first attribute domain with a
* matching name. */
- if (custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
+ if (drw_custom_data_match_attribute(cd_vdata, name, &layer, &type)) {
domain = ATTR_DOMAIN_POINT;
}
- else if (custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_ldata, name, &layer, &type)) {
domain = ATTR_DOMAIN_CORNER;
}
- else if (custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_pdata, name, &layer, &type)) {
domain = ATTR_DOMAIN_FACE;
}
- else if (custom_data_match_attribute(cd_edata, name, &layer, &type)) {
+ else if (drw_custom_data_match_attribute(cd_edata, name, &layer, &type)) {
domain = ATTR_DOMAIN_EDGE;
}
else {
@@ -701,7 +586,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
break;
}
- /* Note: attr->type will always be CD_PROP_COLOR even for
+ /* NOTE: attr->type will always be CD_PROP_COLOR even for
* CD_PROP_BYTE_COLOR layers, see node_shader_gpu_vertex_color in
* node_shader_vertex_color.cc.
*/
@@ -718,7 +603,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ drw_attributes_add_request(attributes, type, layer, domain);
}
break;
}
@@ -729,7 +614,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_PROP_FLOAT:
case CD_PROP_FLOAT2: {
if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_mesh_attributes_add_request(attributes, type, layer, domain);
+ drw_attributes_add_request(attributes, type, layer, domain);
}
break;
}
@@ -1317,8 +1202,8 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
uint gpumat_array_len)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- DRW_MeshAttributes attrs_needed;
- drw_mesh_attributes_clear(&attrs_needed);
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(
object, me, gpumat_array, gpumat_array_len, &attrs_needed);
@@ -1326,7 +1211,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
ThreadMutex *mesh_render_mutex = (ThreadMutex *)me->runtime.render_mutex;
- drw_mesh_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_needed, &attrs_needed, mesh_render_mutex);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
@@ -1596,7 +1481,7 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
cache->lastmatch = ctime;
}
- if (drw_mesh_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
+ if (drw_attributes_overlap(&cache->attr_used_over_time, &cache->attr_used)) {
cache->lastmatch = ctime;
}
@@ -1605,12 +1490,12 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
}
mesh_cd_layers_type_clear(&cache->cd_used_over_time);
- drw_mesh_attributes_clear(&cache->attr_used_over_time);
+ drw_attributes_clear(&cache->attr_used_over_time);
}
static void drw_add_attributes_vbo(GPUBatch *batch,
MeshBufferList *mbuflist,
- DRW_MeshAttributes *attr_used)
+ DRW_Attributes *attr_used)
{
for (int i = 0; i < attr_used->num_requests; i++) {
DRW_vbo_request(batch, &mbuflist->vbo.attr[i]);
@@ -1721,7 +1606,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* TODO(fclem): We could be a bit smarter here and only do it per
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
- bool attr_overlap = drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed);
+ bool attr_overlap = drw_attributes_overlap(&cache->attr_used, &cache->attr_needed);
if (cd_overlap == false || attr_overlap == false) {
FOREACH_MESH_BUFFER_CACHE (cache, mbc) {
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
@@ -1741,7 +1626,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if ((cache->cd_used.vcol & cache->cd_needed.vcol) != cache->cd_needed.vcol) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.vcol);
}
- if (!drw_mesh_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
+ if (!drw_attributes_overlap(&cache->attr_used, &cache->attr_needed)) {
for (int i = 0; i < GPU_MAX_ATTR; i++) {
GPU_VERTBUF_DISCARD_SAFE(mbc->buff.vbo.attr[i]);
}
@@ -1756,13 +1641,13 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready &= ~(MBC_SURFACE);
mesh_cd_layers_type_merge(&cache->cd_used, cache->cd_needed);
- drw_mesh_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_merge(&cache->attr_used, &cache->attr_needed, mesh_render_mutex);
}
mesh_cd_layers_type_merge(&cache->cd_used_over_time, cache->cd_needed);
mesh_cd_layers_type_clear(&cache->cd_needed);
- drw_mesh_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
- drw_mesh_attributes_clear(&cache->attr_needed);
+ drw_attributes_merge(&cache->attr_used_over_time, &cache->attr_needed, mesh_render_mutex);
+ drw_attributes_clear(&cache->attr_needed);
}
if (batch_requested & MBC_EDITUV) {
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index a1c0a42ba6f..c1d609bf648 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -277,7 +277,7 @@ static void particle_calculate_parent_uvs(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_uv_layers,
const int parent_index,
- /*const*/ MTFace **mtfaces,
+ const MTFace **mtfaces,
float (*r_uv)[2])
{
if (psmd == NULL) {
@@ -306,7 +306,7 @@ static void particle_calculate_parent_mcol(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_col_layers,
const int parent_index,
- /*const*/ MCol **mcols,
+ const MCol **mcols,
MCol *r_mcol)
{
if (psmd == NULL) {
@@ -337,7 +337,7 @@ static void particle_interpolate_children_uvs(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_uv_layers,
const int child_index,
- /*const*/ MTFace **mtfaces,
+ const MTFace **mtfaces,
float (*r_uv)[2])
{
if (psmd == NULL) {
@@ -361,7 +361,7 @@ static void particle_interpolate_children_mcol(ParticleSystem *psys,
ParticleSystemModifierData *psmd,
const int num_col_layers,
const int child_index,
- /*const*/ MCol **mcols,
+ const MCol **mcols,
MCol *r_mcol)
{
if (psmd == NULL) {
@@ -388,7 +388,7 @@ static void particle_calculate_uvs(ParticleSystem *psys,
const int num_uv_layers,
const int parent_index,
const int child_index,
- /*const*/ MTFace **mtfaces,
+ const MTFace **mtfaces,
float (**r_parent_uvs)[2],
float (**r_uv)[2])
{
@@ -431,7 +431,7 @@ static void particle_calculate_mcol(ParticleSystem *psys,
const int num_col_layers,
const int parent_index,
const int child_index,
- /*const*/ MCol **mcols,
+ const MCol **mcols,
MCol **r_parent_mcol,
MCol **r_mcol)
{
@@ -482,8 +482,8 @@ static int particle_batch_cache_fill_segments(ParticleSystem *psys,
const int num_path_keys,
const int num_uv_layers,
const int num_col_layers,
- /*const*/ MTFace **mtfaces,
- /*const*/ MCol **mcols,
+ const MTFace **mtfaces,
+ const MCol **mcols,
uint *uv_id,
uint *col_id,
float (***r_parent_uvs)[2],
@@ -713,11 +713,11 @@ static int particle_batch_cache_fill_strands_data(ParticleSystem *psys,
GPUVertBufRaw *seg_step,
float (***r_parent_uvs)[2],
GPUVertBufRaw *uv_step,
- MTFace **mtfaces,
+ const MTFace **mtfaces,
int num_uv_layers,
MCol ***r_parent_mcol,
GPUVertBufRaw *col_step,
- MCol **mcols,
+ const MCol **mcols,
int num_col_layers)
{
const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
@@ -834,8 +834,8 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
GPUVertBufRaw uv_step[MAX_MTFACE];
GPUVertBufRaw col_step[MAX_MCOL];
- MTFace *mtfaces[MAX_MTFACE] = {NULL};
- MCol *mcols[MAX_MCOL] = {NULL};
+ const MTFace *mtfaces[MAX_MTFACE] = {NULL};
+ const MCol *mcols[MAX_MCOL] = {NULL};
float(**parent_uvs)[2] = NULL;
MCol **parent_mcol = NULL;
@@ -909,12 +909,13 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
BKE_mesh_tessface_ensure(psmd->mesh_final);
if (cache->num_uv_layers) {
for (int j = 0; j < cache->num_uv_layers; j++) {
- mtfaces[j] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, j);
+ mtfaces[j] = (const MTFace *)CustomData_get_layer_n(
+ &psmd->mesh_final->fdata, CD_MTFACE, j);
}
}
if (cache->num_col_layers) {
for (int j = 0; j < cache->num_col_layers; j++) {
- mcols[j] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
+ mcols[j] = (const MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
}
}
}
@@ -930,11 +931,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
&seg_step,
&parent_uvs,
uv_step,
- (MTFace **)mtfaces,
+ mtfaces,
cache->num_uv_layers,
&parent_mcol,
col_step,
- (MCol **)mcols,
+ mcols,
cache->num_col_layers);
}
else {
@@ -951,11 +952,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
&seg_step,
&parent_uvs,
uv_step,
- (MTFace **)mtfaces,
+ mtfaces,
cache->num_uv_layers,
&parent_mcol,
col_step,
- (MCol **)mcols,
+ mcols,
cache->num_col_layers);
}
if (psys->childcache) {
@@ -970,11 +971,11 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
&seg_step,
&parent_uvs,
uv_step,
- (MTFace **)mtfaces,
+ mtfaces,
cache->num_uv_layers,
&parent_mcol,
col_step,
- (MCol **)mcols,
+ mcols,
cache->num_col_layers);
}
}
@@ -1147,8 +1148,8 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
int num_col_layers = 0;
int active_uv = 0;
int active_col = 0;
- MTFace **mtfaces = NULL;
- MCol **mcols = NULL;
+ const MTFace **mtfaces = NULL;
+ const MCol **mcols = NULL;
float(**parent_uvs)[2] = NULL;
MCol **parent_mcol = NULL;
@@ -1214,13 +1215,14 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
if (num_uv_layers) {
mtfaces = MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers");
for (int i = 0; i < num_uv_layers; i++) {
- mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, i);
+ mtfaces[i] = (const MTFace *)CustomData_get_layer_n(
+ &psmd->mesh_final->fdata, CD_MTFACE, i);
}
}
if (num_col_layers) {
mcols = MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers");
for (int i = 0; i < num_col_layers; i++) {
- mcols[i] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
+ mcols[i] = (const MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
}
}
}
@@ -1304,10 +1306,10 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
MEM_freeN(parent_mcol);
}
if (num_uv_layers) {
- MEM_freeN(mtfaces);
+ MEM_freeN((void *)mtfaces);
}
if (num_col_layers) {
- MEM_freeN(mcols);
+ MEM_freeN((void *)mcols);
}
if (psmd != NULL) {
MEM_freeN(uv_id);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 8eb0509d615..dc40e15a450 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -69,6 +69,7 @@ enum {
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_ORCO,
SHADER_COMP_CUSTOM_DATA_INTERP_1D,
SHADER_COMP_CUSTOM_DATA_INTERP_2D,
SHADER_COMP_CUSTOM_DATA_INTERP_3D,
@@ -107,7 +108,8 @@ static const char *get_shader_code(int shader_type)
}
case SHADER_PATCH_EVALUATION:
case SHADER_PATCH_EVALUATION_FVAR:
- case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ case SHADER_PATCH_EVALUATION_FACE_DOTS:
+ case SHADER_PATCH_EVALUATION_ORCO: {
return datatoc_common_subdiv_patch_evaluation_comp_glsl;
}
case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
@@ -163,6 +165,9 @@ static const char *get_shader_name(int shader_type)
case SHADER_PATCH_EVALUATION_FACE_DOTS: {
return "subdiv patch evaluation face dots";
}
+ case SHADER_PATCH_EVALUATION_ORCO: {
+ return "subdiv patch evaluation orco";
+ }
case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
return "subdiv custom data interp 1D";
}
@@ -206,6 +211,12 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define FDOTS_EVALUATION\n";
}
+ else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define ORCO_EVALUATION\n";
+ }
else {
defines =
"#define OSD_PATCH_BASIS_GLSL\n"
@@ -236,7 +247,8 @@ static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
if (ELEM(shader_type,
SHADER_PATCH_EVALUATION,
SHADER_PATCH_EVALUATION_FVAR,
- SHADER_PATCH_EVALUATION_FACE_DOTS)) {
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_PATCH_EVALUATION_ORCO)) {
return get_patch_evaluation_shader(shader_type);
}
if (g_subdiv_shaders[shader_type] == nullptr) {
@@ -710,6 +722,23 @@ static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
return subdiv_cache;
}
+static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, Mesh *mesh)
+{
+ const bool has_orco = CustomData_has_layer(&mesh->vdata, CD_ORCO);
+ if (has_orco && subdiv->evaluator && !subdiv->evaluator->hasVertexData(subdiv->evaluator)) {
+ /* If we suddenly have/need original coordinates, recreate the evaluator if the extra
+ * source was not created yet. The refiner also has to be recreated as refinement for source
+ * and vertex data is done only once. */
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ subdiv->evaluator = nullptr;
+
+ if (subdiv->topology_refiner != nullptr) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ subdiv->topology_refiner = nullptr;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -745,8 +774,8 @@ struct DRWCacheBuildingContext {
/* Origindex layers from the mesh to directly look up during traversal the origindex from the
* base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in
* the shaders. */
- int *v_origindex;
- int *e_origindex;
+ const int *v_origindex;
+ const int *e_origindex;
};
static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
@@ -1230,7 +1259,9 @@ static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
}
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor)
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *orco)
{
if (!draw_subdiv_cache_need_polygon_data(cache)) {
/* Happens on meshes with only loose geometry. */
@@ -1245,6 +1276,14 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_subdiv_vertex_format());
evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+ GPUVertBuf *src_extra_buffer = nullptr;
+ if (orco) {
+ OpenSubdiv_Buffer src_extra_buffer_interface;
+ src_extra_buffer = create_buffer_and_interface(&src_extra_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcVertexDataBuffer(evaluator, &src_extra_buffer_interface);
+ }
+
OpenSubdiv_Buffer patch_arrays_buffer_interface;
GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
get_patch_array_format());
@@ -1260,7 +1299,8 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
get_patch_param_format());
evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
- GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION);
+ GPUShader *shader = get_patch_evaluation_shader(orco ? SHADER_PATCH_EVALUATION_ORCO :
+ SHADER_PATCH_EVALUATION);
GPU_shader_bind(shader);
int binding_point = 0;
@@ -1273,6 +1313,10 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ if (orco) {
+ GPU_vertbuf_bind_as_ssbo(src_extra_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(orco, binding_point++);
+ }
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1289,6 +1333,7 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPU_vertbuf_discard(patch_param_buffer);
GPU_vertbuf_discard(patch_arrays_buffer);
GPU_vertbuf_discard(src_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(src_extra_buffer);
}
void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
@@ -1935,6 +1980,8 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
return false;
}
+ draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval);
+
if (!BKE_subdiv_eval_begin_from_mesh(
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
/* This could happen in two situations:
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 779ac43178c..b6b0c94f4bf 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -13,6 +13,7 @@
extern "C" {
#endif
+struct CurvesUniformBufPool;
struct DRWShadingGroup;
struct FluidModifierData;
struct GPUMaterial;
@@ -44,7 +45,7 @@ float *DRW_color_background_blend_get(int theme_id);
bool DRW_object_is_flat(struct Object *ob, int *r_axis);
bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis);
-/* draw_hair.c */
+/* draw_hair.cc */
/**
* This creates a shading group with display hairs.
@@ -82,7 +83,8 @@ 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_init(struct DRWData *drw_data);
+void DRW_curves_ubos_pool_free(struct CurvesUniformBufPool *pool);
void DRW_curves_update(void);
void DRW_curves_free(void);
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index 88118361115..d90c63b680e 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -10,6 +10,7 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
#include "GPU_batch.h"
@@ -20,9 +21,13 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
+#include "DRW_gpu_wrapper.hh"
#include "DRW_render.h"
+#include "draw_cache_impl.h"
+#include "draw_curves_private.h"
#include "draw_hair_private.h"
+#include "draw_manager.h"
#include "draw_shader.h"
#ifndef __APPLE__
@@ -61,16 +66,43 @@ static GPUVertBuf *g_dummy_vbo = nullptr;
static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
+using CurvesInfosBuf = blender::draw::UniformBuffer<CurvesInfos>;
+
+struct CurvesUniformBufPool {
+ blender::Vector<std::unique_ptr<CurvesInfosBuf>> ubos;
+ int used = 0;
+
+ void reset()
+ {
+ used = 0;
+ }
+
+ CurvesInfosBuf &alloc()
+ {
+ if (used >= ubos.size()) {
+ ubos.append(std::make_unique<CurvesInfosBuf>());
+ return *ubos.last().get();
+ }
+ return *ubos[used++].get();
+ }
+};
+
static GPUShader *curves_eval_shader_get(CurvesEvalShader type)
{
return DRW_shader_curves_refine_get(type, drw_curves_shader_type_get());
}
-void DRW_curves_init(void)
+void DRW_curves_init(DRWData *drw_data)
{
/* Initialize legacy hair too, to avoid verbosity in callers. */
DRW_hair_init();
+ if (drw_data->curves_ubos == nullptr) {
+ drw_data->curves_ubos = MEM_new<CurvesUniformBufPool>("CurvesUniformBufPool");
+ }
+ CurvesUniformBufPool *pool = drw_data->curves_ubos;
+ pool->reset();
+
#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
g_tf_pass = DRW_pass_create("Update Curves Pass", (DRWState)0);
#else
@@ -94,63 +126,120 @@ void DRW_curves_init(void)
}
}
+void DRW_curves_ubos_pool_free(CurvesUniformBufPool *pool)
+{
+ MEM_delete(pool);
+}
+
static void drw_curves_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
CurvesEvalCache *cache,
+ GPUTexture *tex,
const int subdiv)
{
- DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex);
+ DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", tex);
DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex);
DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
}
+static void drw_curves_cache_update_compute(CurvesEvalCache *cache,
+ const int subdiv,
+ const int strands_len,
+ GPUVertBuf *buffer,
+ GPUTexture *tex)
+{
+ GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
+ drw_curves_cache_shgrp_attach_resources(shgrp, cache, tex, subdiv);
+ DRW_shgroup_vertex_buffer(shgrp, "posTime", buffer);
+
+ const int max_strands_per_call = GPU_max_work_group_count(0);
+ int strands_start = 0;
+ while (strands_start < strands_len) {
+ int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
+ DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
+ DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
+ DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
+ strands_start += batch_strands_len;
+ }
+}
+
static void drw_curves_cache_update_compute(CurvesEvalCache *cache, const int subdiv)
{
const int strands_len = cache->strands_len;
const int final_points_len = cache->final[subdiv].strands_res * strands_len;
- if (final_points_len > 0) {
- GPUShader *shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
- DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
- drw_curves_cache_shgrp_attach_resources(shgrp, cache, subdiv);
- DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf);
-
- const int max_strands_per_call = GPU_max_work_group_count(0);
- int strands_start = 0;
- while (strands_start < strands_len) {
- int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
- DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
- DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
- DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
- strands_start += batch_strands_len;
+ if (final_points_len == 0) {
+ return;
+ }
+
+ drw_curves_cache_update_compute(
+ cache, subdiv, strands_len, cache->final[subdiv].proc_buf, cache->point_tex);
+
+ const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ /* Only refine point attributes. */
+ if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) {
+ continue;
}
+
+ drw_curves_cache_update_compute(cache,
+ subdiv,
+ strands_len,
+ cache->final[subdiv].attributes_buf[i],
+ cache->proc_attributes_tex[i]);
}
}
-static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache,
+ GPUVertBuf *vbo,
+ GPUTexture *tex,
+ const int subdiv,
+ const int final_points_len)
{
- const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
- if (final_points_len > 0) {
- GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
+ GPUShader *tf_shader = curves_eval_shader_get(CURVES_EVAL_CATMULL_ROM);
#ifdef USE_TRANSFORM_FEEDBACK
- DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, vbo);
#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ CurvesEvalCall *pr_call = MEM_new<CurvesEvalCall>(__func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = vbo;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
#endif
- drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
- DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+ drw_curves_cache_shgrp_attach_resources(tf_shgrp, cache, tex, subdiv);
+ DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
+}
+
+static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, const int subdiv)
+{
+ const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
+ if (final_points_len == 0) {
+ return;
+ }
+
+ drw_curves_cache_update_transform_feedback(
+ cache, cache->final[subdiv].proc_buf, cache->point_tex, subdiv, final_points_len);
+
+ const DRW_Attributes &attrs = cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ /* Only refine point attributes. */
+ if (attrs.requests[i].domain == ATTR_DOMAIN_CURVE) {
+ continue;
+ }
+
+ drw_curves_cache_update_transform_feedback(cache,
+ cache->final[subdiv].attributes_buf[i],
+ cache->proc_attributes_tex[i],
+ subdiv,
+ final_points_len);
}
}
@@ -186,12 +275,34 @@ GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
return cache->final[subdiv].proc_buf;
}
+static int attribute_index_in_material(GPUMaterial *gpu_material, const char *name)
+{
+ if (!gpu_material) {
+ return -1;
+ }
+
+ int index = 0;
+
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ if (STREQ(gpu_attr->name, name)) {
+ return index;
+ }
+
+ index++;
+ }
+
+ return -1;
+}
+
DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRWShadingGroup *shgrp_parent,
GPUMaterial *gpu_material)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
+ CurvesUniformBufPool *pool = DST.vmempool->curves_ubos;
+ CurvesInfosBuf &curves_infos = pool->alloc();
int subdiv = scene->r.hair_subdiv;
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
@@ -209,7 +320,7 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
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_shape = 0.0f;
float hair_rad_root = 0.005f;
float hair_rad_tip = 0.0f;
bool hair_close_tip = true;
@@ -218,6 +329,43 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
if (curves_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
}
+
+ const DRW_Attributes &attrs = curves_cache->final[subdiv].attr_used;
+ for (int i = 0; i < attrs.num_requests; i++) {
+ const DRW_AttributeRequest &request = attrs.requests[i];
+
+ char sampler_name[32];
+ drw_curves_get_attribute_sampler_name(request.attribute_name, sampler_name);
+
+ if (request.domain == ATTR_DOMAIN_CURVE) {
+ if (!curves_cache->proc_attributes_tex[i]) {
+ continue;
+ }
+
+ DRW_shgroup_uniform_texture(shgrp, sampler_name, curves_cache->proc_attributes_tex[i]);
+ }
+ else {
+ if (!curves_cache->final[subdiv].attributes_tex[i]) {
+ continue;
+ }
+ DRW_shgroup_uniform_texture(
+ shgrp, sampler_name, curves_cache->final[subdiv].attributes_tex[i]);
+ }
+
+ /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so
+ * we need to find the right index for this attribute as uniforms defining the scope of the
+ * attributes are based on attribute loading order, which is itself based on the material's
+ * attributes. */
+ const int index = attribute_index_in_material(gpu_material, request.attribute_name);
+ if (index != -1) {
+ curves_infos.is_point_attribute[index] = request.domain == ATTR_DOMAIN_POINT;
+ }
+ }
+
+ curves_infos.push_update();
+
+ DRW_shgroup_uniform_block(shgrp, "drw_curves", curves_infos);
+
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h
index 76d5f15319d..ed4dd50dfbe 100644
--- a/source/blender/draw/intern/draw_curves_private.h
+++ b/source/blender/draw/intern/draw_curves_private.h
@@ -7,6 +7,11 @@
#pragma once
+#include "BKE_attribute.h"
+#include "GPU_shader.h"
+
+#include "draw_attributes.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -35,6 +40,23 @@ typedef struct CurvesEvalFinalCache {
/* Points per curve, at least 2. */
int strands_res;
+
+ /* Attributes currently being or about to be drawn. */
+ DRW_Attributes attr_used;
+
+ /* Attributes which were used at some point. This is used for garbage collection, to remove
+ * attributes which are not used in shaders anymore due to user edits. */
+ DRW_Attributes attr_used_over_time;
+
+ /* Last time, in seconds, the `attr_used` and `attr_used_over_time` were exactly the same.
+ * If the delta between this time and the current scene time is greater than the timeout set in
+ * user preferences (`U.vbotimeout`) then garbage collection is performed. */
+ int last_attr_matching_time;
+
+ /* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes
+ * on point domain. */
+ GPUVertBuf *attributes_buf[GPU_MAX_ATTR];
+ GPUTexture *attributes_tex[GPU_MAX_ATTR];
} CurvesEvalFinalCache;
/* Curves procedural display: Evaluation is done on the GPU. */
@@ -56,6 +78,11 @@ typedef struct CurvesEvalCache {
CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
+ /* For point attributes, which need subdivision, these are the input data.
+ * For spline attributes, which need not subdivision, these are the final data. */
+ GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR];
+ GPUTexture *proc_attributes_tex[GPU_MAX_ATTR];
+
int strands_len;
int elems_len;
int point_len;
@@ -70,6 +97,8 @@ bool curves_ensure_procedural_data(struct Object *object,
int subdiv,
int thickness_res);
+void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sampler_name[32]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.cc
index 8351452769d..0a3c16e0d71 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.cc
@@ -35,7 +35,7 @@
# define USE_COMPUTE_SHADERS
#endif
-BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
+BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get()
{
#ifdef USE_COMPUTE_SHADERS
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
@@ -49,21 +49,21 @@ BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
}
#ifndef USE_TRANSFORM_FEEDBACK
-typedef struct ParticleRefineCall {
+struct ParticleRefineCall {
struct ParticleRefineCall *next;
GPUVertBuf *vbo;
DRWShadingGroup *shgrp;
uint vert_len;
-} ParticleRefineCall;
+};
-static ParticleRefineCall *g_tf_calls = NULL;
+static ParticleRefineCall *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 = NULL;
-static GPUTexture *g_dummy_texture = NULL;
+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 *hair_refine_shader_get(ParticleRefineShader refinement)
@@ -74,12 +74,12 @@ static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
void DRW_hair_init(void)
{
#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
- g_tf_pass = DRW_pass_create("Update Hair Pass", 0);
+ g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_NO_DRAW);
#else
g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
#endif
- if (g_dummy_vbo == NULL) {
+ 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);
@@ -141,7 +141,7 @@ static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache
#else
DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ ParticleRefineCall *pr_call = (ParticleRefineCall *)MEM_mallocN(sizeof(*pr_call), __func__);
pr_call->next = g_tf_calls;
pr_call->vbo = cache->final[subdiv].proc_buf;
pr_call->shgrp = tf_shgrp;
@@ -153,7 +153,7 @@ static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache
#endif
drw_hair_particle_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ DRW_shgroup_call_procedural_points(tf_shgrp, nullptr, final_points_len);
}
}
@@ -188,7 +188,7 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
ParticleHairCache *cache = drw_hair_particle_cache_get(
- object, psys, md, NULL, subdiv, thickness_res);
+ object, psys, md, nullptr, subdiv, thickness_res);
return cache->final[subdiv].proc_buf;
}
@@ -201,11 +201,11 @@ void DRW_hair_duplimat_get(Object *object,
Object *dupli_parent = DRW_object_get_dupli_parent(object);
DupliObject *dupli_object = DRW_object_get_dupli(object);
- if ((dupli_parent != NULL) && (dupli_object != NULL)) {
+ if ((dupli_parent != nullptr) && (dupli_object != nullptr)) {
if (dupli_object->type & OB_DUPLICOLLECTION) {
unit_m4(dupli_mat);
Collection *collection = dupli_parent->instance_collection;
- if (collection != NULL) {
+ if (collection != nullptr) {
sub_v3_v3(dupli_mat[3], collection->instance_offset);
}
mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat);
@@ -291,7 +291,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
return shgrp;
}
-void DRW_hair_update(void)
+void DRW_hair_update()
{
#ifndef USE_TRANSFORM_FEEDBACK
/**
@@ -304,7 +304,7 @@ void DRW_hair_update(void)
* and the most local workaround that still uses the power of the GPU.
*/
- if (g_tf_calls == NULL) {
+ if (g_tf_calls == nullptr) {
return;
}
@@ -319,21 +319,22 @@ void DRW_hair_update(void)
* 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, (void *)DRW_hair_update);
+ GPUTexture *tex = DRW_texture_pool_query_2d(
+ width, height, GPU_RGBA32F, (DrawEngineType *)DRW_hair_update);
g_tf_target_height = height;
g_tf_target_width = width;
- GPUFrameBuffer *fb = NULL;
+ GPUFrameBuffer *fb = nullptr;
GPU_framebuffer_ensure_config(&fb,
{
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(tex),
});
- float *data = MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer");
+ float *data = (float *)MEM_mallocN(sizeof(float[4]) * width * height, "tf fallback buffer");
GPU_framebuffer_bind(fb);
- while (g_tf_calls != NULL) {
+ while (g_tf_calls != nullptr) {
ParticleRefineCall *pr_call = g_tf_calls;
g_tf_calls = g_tf_calls->next;
@@ -342,7 +343,7 @@ void DRW_hair_update(void)
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);
- /* Readback result to main memory. */
+ /* 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);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 4bbcf6eaf42..1372b843442 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -479,6 +479,7 @@ void DRW_viewport_data_free(DRWData *drw_data)
MEM_freeN(drw_data->obinfos_ubo);
}
DRW_volume_ubos_pool_free(drw_data->volume_grids_ubos);
+ DRW_curves_ubos_pool_free(drw_data->curves_ubos);
MEM_freeN(drw_data);
}
@@ -501,7 +502,7 @@ static DRWData *drw_viewport_data_ensure(GPUViewport *viewport)
* - size can be NULL to get it from viewport.
* - if viewport and size are NULL, size is set to (1, 1).
*
- * Important: drw_manager_init can be called multiple times before drw_manager_exit.
+ * IMPORTANT: #drw_manager_init can be called multiple times before #drw_manager_exit.
*/
static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int size[2])
{
@@ -529,7 +530,7 @@ static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int s
dst->view_data_active = dst->vmempool->view_data[view];
dst->resource_handle = 0;
dst->pass_handle = 0;
- dst->primary_view_ct = 0;
+ dst->primary_view_num = 0;
drw_viewport_data_reset(dst->vmempool);
@@ -1650,7 +1651,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
DRW_globals_update();
drw_debug_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2022,7 +2023,7 @@ 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_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2079,7 +2080,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
drw_manager_init(&DST, NULL, NULL);
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2114,7 +2115,7 @@ void DRW_cache_restart(void)
DST.buffer_finish_called = false;
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
}
@@ -2433,7 +2434,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
@@ -2607,7 +2608,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
/* Init engines */
drw_engines_init();
- DRW_curves_init();
+ DRW_curves_init(DST.vmempool);
DRW_volume_init(DST.vmempool);
DRW_smoke_init(DST.vmempool);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 7a9585262ff..6d384c599d8 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -319,6 +319,8 @@ typedef enum {
DRW_UNIFORM_STORAGE_BLOCK,
DRW_UNIFORM_STORAGE_BLOCK_REF,
DRW_UNIFORM_TFEEDBACK_TARGET,
+ DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE,
+ DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF,
/** Per drawcall uniforms/UBO */
@@ -536,6 +538,8 @@ typedef struct DRWData {
struct DRWTexturePool *texture_pool;
/** Per stereo view data. Contains engine data and default framebuffers. */
struct DRWViewData *view_data[2];
+ /** Per draw-call curves object data. */
+ struct CurvesUniformBufPool *curves_ubos;
} DRWData;
/* ------------- DRAW MANAGER ------------ */
@@ -617,7 +621,7 @@ typedef struct DRWManager {
DRWView *view_default;
DRWView *view_active;
DRWView *view_previous;
- uint primary_view_ct;
+ uint primary_view_num;
/** TODO(@fclem): Remove this. Only here to support
* shaders without common_view_lib.glsl */
ViewInfos view_storage_cpy;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index b5432da0957..f0960c5324b 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -547,6 +547,29 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF, vertex_buffer, 0, 0, 1);
}
+void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup,
+ const char *name,
+ GPUVertBuf *vertex_buffer)
+{
+ int location = GPU_shader_get_ssbo(shgroup->shader, name);
+ if (location == -1) {
+ return;
+ }
+ drw_shgroup_uniform_create_ex(
+ shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE, vertex_buffer, 0, 0, 1);
+}
+
+void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
+ const char *name,
+ GPUVertBuf **vertex_buffer)
+{
+ int location = GPU_shader_get_ssbo(shgroup->shader, name);
+ if (location == -1) {
+ return;
+ }
+ drw_shgroup_uniform_create_ex(
+ shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF, vertex_buffer, 0, 0, 1);
+}
/** \} */
/* -------------------------------------------------------------------- */
@@ -937,25 +960,25 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
}
void DRW_shgroup_call_range(
- DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_ct)
+ DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_num)
{
BLI_assert(geom != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
- drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
+ drw_command_draw_range(shgroup, geom, handle, v_sta, v_num);
}
void DRW_shgroup_call_instance_range(
- DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_num)
{
BLI_assert(geom != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
- drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_ct);
+ drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_num);
}
void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
@@ -1905,8 +1928,8 @@ DRWView *DRW_view_create(const float viewmat[4][4],
{
DRWView *view = BLI_memblock_alloc(DST.vmempool->views);
- if (DST.primary_view_ct < MAX_CULLED_VIEWS) {
- view->culling_mask = 1u << DST.primary_view_ct++;
+ if (DST.primary_view_num < MAX_CULLED_VIEWS) {
+ view->culling_mask = 1u << DST.primary_view_num++;
}
else {
BLI_assert(0);
@@ -2058,6 +2081,11 @@ void DRW_view_camtexco_set(DRWView *view, float texco[4])
copy_v4_v4(view->storage.viewcamtexcofac, texco);
}
+void DRW_view_camtexco_get(const DRWView *view, float r_texco[4])
+{
+ copy_v4_v4(r_texco, view->storage.viewcamtexcofac);
+}
+
void DRW_view_frustum_corners_get(const DRWView *view, BoundBox *corners)
{
memcpy(corners, &view->frustum_corners, sizeof(view->frustum_corners));
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 2c5b02f88a9..e7e0e0ce41f 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -693,6 +693,12 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
*use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
((GPUVertBuf *)uni->pvalue));
break;
+ case DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF:
+ GPU_vertbuf_bind_as_texture(*uni->vertbuf_ref, uni->location);
+ break;
+ case DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE:
+ GPU_vertbuf_bind_as_texture(uni->vertbuf, uni->location);
+ break;
case DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF:
GPU_vertbuf_bind_as_ssbo(*uni->vertbuf_ref, uni->location);
break;
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.cc
index 063aec24b94..001ceb0ae8d 100644
--- a/source/blender/draw/intern/draw_shader.c
+++ b/source/blender/draw/intern/draw_shader.cc
@@ -16,15 +16,15 @@
#include "draw_shader.h"
-extern char datatoc_common_hair_lib_glsl[];
+extern "C" char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_hair_refine_vert_glsl[];
-extern char datatoc_common_hair_refine_comp_glsl[];
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern "C" char datatoc_common_hair_refine_vert_glsl[];
+extern "C" char datatoc_common_hair_refine_comp_glsl[];
+extern "C" char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
static struct {
struct GPUShader *hair_refine_sh[PART_REFINE_MAX_SHADER];
-} e_data = {{NULL}};
+} e_data = {{nullptr}};
/* -------------------------------------------------------------------- */
/** \name Hair refinement
@@ -38,19 +38,19 @@ static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(
static GPUShader *hair_refine_shader_transform_feedback_create(
ParticleRefineShader UNUSED(refinement))
{
- GPUShader *sh = NULL;
+ GPUShader *sh = nullptr;
+
+ std::string shader_src = std::string(datatoc_common_hair_lib_glsl) +
+ std::string(datatoc_common_hair_refine_vert_glsl);
- char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
- datatoc_common_hair_refine_vert_glsl);
const char *var_names[1] = {"finalColor"};
- sh = DRW_shader_create_with_transform_feedback(shader_src,
- NULL,
+ sh = DRW_shader_create_with_transform_feedback(shader_src.c_str(),
+ nullptr,
"#define HAIR_PHASE_SUBDIV\n"
"#define USE_TF\n",
GPU_SHADER_TFB_POINTS,
var_names,
1);
- MEM_freeN(shader_src);
return sh;
}
@@ -64,8 +64,8 @@ static GPUShader *hair_refine_shader_transform_feedback_workaround_create(
GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
eParticleRefineShaderType sh_type)
{
- if (e_data.hair_refine_sh[refinement] == NULL) {
- GPUShader *sh = NULL;
+ if (e_data.hair_refine_sh[refinement] == nullptr) {
+ GPUShader *sh = nullptr;
switch (sh_type) {
case PART_REFINE_SHADER_COMPUTE:
sh = hair_refine_shader_compute_create(refinement);
@@ -88,8 +88,8 @@ GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader 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;
+ if (e_data.hair_refine_sh[type] == nullptr) {
+ GPUShader *sh = nullptr;
switch (sh_type) {
case PART_REFINE_SHADER_COMPUTE:
sh = hair_refine_shader_compute_create(PART_REFINE_CATMULL_ROM);
@@ -111,7 +111,7 @@ GPUShader *DRW_shader_curves_refine_get(CurvesEvalShader type, eParticleRefineSh
/** \} */
-void DRW_shaders_free(void)
+void DRW_shaders_free()
{
for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) {
DRW_SHADER_FREE_SAFE(e_data.hair_refine_sh[i]);
diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h
index 650e78c9362..63d755cc334 100644
--- a/source/blender/draw/intern/draw_shader.h
+++ b/source/blender/draw/intern/draw_shader.h
@@ -22,7 +22,7 @@ typedef enum eParticleRefineShaderType {
PART_REFINE_SHADER_COMPUTE,
} eParticleRefineShaderType;
-/* draw_shader.c */
+/* draw_shader.cc */
struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement,
eParticleRefineShaderType sh_type);
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index db128fffde7..94c0c53dab7 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -1,12 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef GPU_SHADER
+# include "GPU_shader.h"
# include "GPU_shader_shared_utils.h"
typedef struct ViewInfos ViewInfos;
typedef struct ObjectMatrices ObjectMatrices;
typedef struct ObjectInfos ObjectInfos;
typedef struct VolumeInfos VolumeInfos;
+typedef struct CurvesInfos CurvesInfos;
#endif
#define DRW_SHADER_SHARED_H
@@ -16,6 +18,10 @@ typedef struct VolumeInfos VolumeInfos;
/* Define the maximum number of grid we allow in a volume UBO. */
#define DRW_GRID_PER_VOLUME_MAX 16
+/* Define the maximum number of attribute we allow in a curves UBO.
+ * This should be kept in sync with `GPU_ATTR_MAX` */
+#define DRW_ATTRIBUTE_PER_CURVES_MAX 15
+
struct ViewInfos {
/* View matrices */
float4x4 persmat;
@@ -79,6 +85,14 @@ struct VolumeInfos {
};
BLI_STATIC_ASSERT_ALIGN(VolumeInfos, 16)
+struct CurvesInfos {
+ /* Per attribute scope, follows loading order.
+ * NOTE: uint as bool in GLSL is 4 bytes. */
+ uint is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX];
+ int _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 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_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index b7cd520f54f..7bddd000ecb 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -160,8 +160,8 @@ typedef struct DRWSubdivCache {
/* Contains the start loop index and the smooth flag for each coarse polygon. */
struct GPUVertBuf *extra_coarse_face_data;
- /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices ->
- * subdivided loop */
+ /* Computed for `ibo.points`, one value per subdivided vertex,
+ * mapping coarse vertices -> subdivided loop. */
int *point_indices;
/* Material offsets. */
@@ -235,7 +235,9 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor);
-void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, struct GPUVertBuf *pos_nor);
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *orco);
void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
struct GPUVertBuf *src_data,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index d55386dfd7d..b88cd9e77d2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -67,7 +67,7 @@ typedef struct MeshRenderData {
const float (*bm_poly_normals)[3];
const float (*bm_poly_centers)[3];
- int *v_origindex, *e_origindex, *p_origindex;
+ const int *v_origindex, *e_origindex, *p_origindex;
int edge_crease_ofs;
int vert_crease_ofs;
int bweight_ofs;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index f9e58709c6e..e08aa1da420 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -14,6 +14,7 @@
#include "BKE_attribute.h"
+#include "draw_attributes.h"
#include "draw_subdivision.h"
#include "extract_mesh.h"
@@ -180,7 +181,7 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
const MPoly *mpoly = mr->mpoly;
const MLoop *mloop = mr->mloop;
- const AttributeType *attr_data = static_cast<AttributeType *>(
+ const AttributeType *attr_data = static_cast<const AttributeType *>(
CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
using converter = attribute_type_converter<AttributeType, VBOType>;
@@ -284,7 +285,7 @@ static void extract_attr_init(const MeshRenderData *mr,
void *UNUSED(tls_data),
int index)
{
- const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_Attributes *attrs_used = &cache->attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index];
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
@@ -337,7 +338,7 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(tls_data),
int index)
{
- const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_Attributes *attrs_used = &cache->attr_used;
const DRW_AttributeRequest &request = attrs_used->requests[index];
Mesh *coarse_mesh = subdiv_cache->mesh;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index 4ced14ab11a..fb4b95885fc 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -26,7 +26,7 @@ struct UVStretchAngle {
struct MeshExtract_StretchAngle_Data {
UVStretchAngle *vbo_data;
- MLoopUV *luv;
+ const MLoopUV *luv;
float auv[2][2], last_auv[2];
float av[2][3], last_av[3];
int cd_ofs;
@@ -98,7 +98,7 @@ static void extract_edituv_stretch_angle_init(const MeshRenderData *mr,
}
else {
BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH));
- data->luv = (MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ data->luv = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
}
}
@@ -236,7 +236,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdi
draw_subdiv_get_pos_nor_format(),
subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
- draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor);
+ draw_subdiv_extract_pos_nor(subdiv_cache, pos_nor, nullptr);
}
/* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
index 26f0b07f676..e7a3cb03903 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
@@ -17,7 +17,7 @@ namespace blender::draw {
struct MeshExtract_FdotUV_Data {
float (*vbo_data)[2];
- MLoopUV *uv_data;
+ const MLoopUV *uv_data;
int cd_ofs;
};
@@ -49,7 +49,7 @@ static void extract_fdots_uv_init(const MeshRenderData *mr,
data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
}
else {
- data->uv_data = (MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
+ data->uv_data = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
index ed1a0ccd178..94674a54f12 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
@@ -7,8 +7,6 @@
#include "extract_mesh.h"
-#include "draw_subdivision.h"
-
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -17,7 +15,7 @@ namespace blender::draw {
struct MeshExtract_Orco_Data {
float (*vbo_data)[4];
- float (*orco)[3];
+ const float (*orco)[3];
};
static void extract_orco_init(const MeshRenderData *mr,
@@ -42,7 +40,7 @@ static void extract_orco_init(const MeshRenderData *mr,
MeshExtract_Orco_Data *data = static_cast<MeshExtract_Orco_Data *>(tls_data);
data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo);
- data->orco = static_cast<float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
+ data->orco = static_cast<const float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
/* Make sure `orco` layer was requested only if needed! */
BLI_assert(data->orco);
}
@@ -79,77 +77,12 @@ static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
}
}
-static void extract_orco_init_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buffer,
- void *UNUSED(data))
-{
- static GPUVertFormat format = {0};
- if (format.attr_len == 0) {
- /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
- * attributes. This is a substantial waste of video-ram and should be done another way.
- * Unfortunately, at the time of writing, I did not found any other "non disruptive"
- * alternative. */
- GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
-
- GPUVertBuf *coarse_vbo = GPU_vertbuf_calloc();
- /* Dynamic as we upload and interpolate layers one at a time. */
- GPU_vertbuf_init_with_format_ex(coarse_vbo, &format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(coarse_vbo, mr->loop_len);
-
- float(*coarse_vbo_data)[4] = static_cast<float(*)[4]>(GPU_vertbuf_get_data(coarse_vbo));
-
- CustomData *cd_vdata = &mr->me->vdata;
- float(*orco)[3] = static_cast<float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO));
-
- if (mr->extract_type == MR_EXTRACT_MESH) {
- const MLoop *mloop = mr->mloop;
- const MPoly *mp = mr->mpoly;
-
- int ml_index = 0;
- for (int i = 0; i < mr->poly_len; i++, mp++) {
- const MLoop *ml = &mloop[mp->loopstart];
-
- for (int j = 0; j < mp->totloop; j++, ml++, ml_index++) {
- float *loop_orco = coarse_vbo_data[ml_index];
- copy_v3_v3(loop_orco, orco[ml->v]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- }
- }
- }
- else {
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter;
- BMLoop *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- const int l_index = BM_elem_index_get(l_iter);
- float *loop_orco = coarse_vbo_data[l_index];
- copy_v3_v3(loop_orco, orco[BM_elem_index_get(l_iter->v)]);
- loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
-
- draw_subdiv_interp_custom_data(subdiv_cache, coarse_vbo, dst_buffer, 4, 0, false);
-
- GPU_vertbuf_discard(coarse_vbo);
-}
-
constexpr MeshExtract create_extractor_orco()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_orco_init;
extractor.iter_poly_bm = extract_orco_iter_poly_bm;
extractor.iter_poly_mesh = extract_orco_iter_poly_mesh;
- extractor.init_subdiv = extract_orco_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_Orco_Data);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index ea46d9c4caa..f80b33e28f2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -201,7 +201,7 @@ static GPUVertFormat *get_custom_normals_format()
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -216,11 +216,25 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
return;
}
- draw_subdiv_extract_pos_nor(subdiv_cache, vbo);
+ GPUVertBuf *orco_vbo = cache->final.buff.vbo.orco;
+
+ if (orco_vbo) {
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
+ * attributes. This is a substantial waste of video-ram and should be done another way.
+ * Unfortunately, at the time of writing, I did not found any other "non disruptive"
+ * alternative. */
+ GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(orco_vbo, &format, subdiv_cache->num_subdiv_loops);
+ }
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, orco_vbo);
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
- float(*lnors)[3] = static_cast<float(*)[3]>(
+ const float(*lnors)[3] = static_cast<float(*)[3]>(
CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL));
BLI_assert(lnors != nullptr);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
index 96595df9276..5658ed85c8b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
@@ -42,8 +42,8 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
CustomData *cd_pdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
- int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
+ const float *cd_mask = (const float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
+ const int *cd_face_set = (const int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
@@ -54,7 +54,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
};
gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo);
- MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP);
+ const MLoop *loops = (const MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP);
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK);
@@ -126,7 +126,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* First, interpolate mask if available. */
GPUVertBuf *mask_vbo = nullptr;
GPUVertBuf *subdiv_mask_vbo = nullptr;
- float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
+ const float *cd_mask = (const float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
if (cd_mask) {
GPUVertFormat mask_format = {0};
@@ -167,7 +167,7 @@ static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
};
gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo);
- int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
+ const int *cd_face_set = (const int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
GPUVertFormat *format = get_sculpt_data_format();
GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
index 2a4a6a186be..f4c54b2f881 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
@@ -188,7 +188,7 @@ static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
- /* Each element points to an element in the ibo.points. */
+ /* Each element points to an element in the `ibo.points`. */
draw_subdiv_init_origindex_buffer(
vbo,
(int32_t *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index),
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
index 25f78d68914..91cd675d32f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
@@ -291,7 +291,8 @@ static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
for (int i = 0; i < tan_len; i++) {
float(*tan_data)[4] = (float(*)[4])GPU_vertbuf_get_data(coarse_vbo);
const char *name = tangent_names[i];
- float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(&loop_data, CD_TANGENT, name);
+ const float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
+ &loop_data, CD_TANGENT, name);
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
copy_v3_v3(*tan_data, layer_data[ml_index]);
(*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? 1.0f : -1.0f;
@@ -306,7 +307,7 @@ static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
if (use_orco_tan) {
float(*tan_data)[4] = (float(*)[4])GPU_vertbuf_get_data(coarse_vbo);
- float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
+ const float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
copy_v3_v3(*tan_data, layer_data[ml_index]);
(*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? 1.0f : -1.0f;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
index 5fb4b401ae3..2808a0a3a71 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
@@ -108,7 +108,8 @@ static void extract_uv_init(const MeshRenderData *mr,
}
}
else {
- MLoopUV *layer_data = (MLoopUV *)CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
+ const MLoopUV *layer_data = (const MLoopUV *)CustomData_get_layer_n(
+ cd_ldata, CD_MLOOPUV, i);
for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) {
memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
}
diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl
index 0460ba56e4c..a8931292064 100644
--- a/source/blender/draw/intern/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl
@@ -110,7 +110,7 @@ layout(std140) uniform globalsBlock
vec4 screenVecs[2];
vec4 sizeViewport; /* Inverted size in zw. */
- float sizePixel; /* This one is for dpi scaling */
+ float sizePixel; /* This one is for DPI scaling. */
float pixelFac; /* To use with mul_project_m4_v3_zfac() */
float sizeObjectCenter;
float sizeLightCenter;
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index ff52b483d77..dfa2f307800 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -212,8 +212,8 @@ void hair_get_pos_tan_binor_time(bool is_persp,
wpos += wbinor * thick_time * scale;
}
else {
- /* Note: Ensures 'hairThickTime' is initialised -
- * avoids undefined behaviour on certain macOS configurations. */
+ /* NOTE: Ensures 'hairThickTime' is initialized -
+ * avoids undefined behavior on certain macOS configurations. */
thick_time = 0.0;
}
}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
index 65cf4ebb90f..bf1f0f95787 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -89,6 +89,16 @@ layout(std430, binding = 8) writeonly buffer outputVertexData
{
PosNorLoop output_verts[];
};
+# if defined(ORCO_EVALUATION)
+layout(std430, binding = 9) buffer src_extra_buffer
+{
+ float srcExtraVertexBuffer[];
+};
+layout(std430, binding = 10) writeonly buffer outputOrcoData
+{
+ vec4 output_orcos[];
+};
+# endif
#endif
vec2 read_vec2(int index)
@@ -108,6 +118,17 @@ vec3 read_vec3(int index)
return result;
}
+#if defined(ORCO_EVALUATION)
+vec3 read_vec3_extra(int index)
+{
+ vec3 result;
+ result.x = srcExtraVertexBuffer[index * 3];
+ result.y = srcExtraVertexBuffer[index * 3 + 1];
+ result.z = srcExtraVertexBuffer[index * 3 + 2];
+ return result;
+}
+#endif
+
OsdPatchArray GetPatchArray(int arrayIndex)
{
return patchArrayBuffer[arrayIndex];
@@ -290,6 +311,31 @@ void evaluate_patches_limits(
dv += src_vertex * wDv[cv];
}
}
+
+# if defined(ORCO_EVALUATION)
+/* Evaluate the patches limits from the extra source vertex buffer. */
+void evaluate_patches_limits_extra(int patch_index, float u, float v, inout vec3 dst)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec3 src_vertex = read_vec3_extra(index);
+
+ dst += src_vertex * wP[cv];
+ }
+}
+# endif
#endif
/* ------------------------------------------------------------------------------
@@ -407,6 +453,16 @@ void main()
set_vertex_pos(vertex_data, pos);
set_vertex_nor(vertex_data, nor, flag);
output_verts[loop_index] = vertex_data;
+
+# if defined(ORCO_EVALUATION)
+ pos = vec3(0.0);
+ evaluate_patches_limits_extra(patch_co.patch_index, uv.x, uv.y, pos);
+
+ /* Set w = 0.0 to indicate that this is not a generic attribute.
+ * See comments in `extract_mesh_vbo_orco.cc`. */
+ vec4 orco_data = vec4(pos, 0.0);
+ output_orcos[loop_index] = orco_data;
+# endif
}
}
#endif
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 c74a043ec97..8fd55ea351f 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -10,3 +10,7 @@ GPU_SHADER_CREATE_INFO(draw_object_infos)
GPU_SHADER_CREATE_INFO(draw_volume_infos)
.typedef_source("draw_shader_shared.h")
.uniform_buf(2, "VolumeInfos", "drw_volume", Frequency::BATCH);
+
+GPU_SHADER_CREATE_INFO(draw_curves_infos)
+ .typedef_source("draw_shader_shared.h")
+ .uniform_buf(2, "CurvesInfos", "drw_curves", Frequency::BATCH);