Merge branch 'blender-v4.5-release'
This commit is contained in:
@@ -116,7 +116,8 @@ const UserDef U_default = {
|
||||
#else
|
||||
.gpu_backend = GPU_BACKEND_OPENGL,
|
||||
#endif
|
||||
.max_shader_compilation_subprocesses = 0,
|
||||
.gpu_shader_workers = 0,
|
||||
.shader_compilation_method = USER_SHADER_COMPILE_THREAD,
|
||||
|
||||
/** Initialized by: #BKE_studiolight_default. */
|
||||
.light_param = {{0}},
|
||||
|
||||
@@ -30,7 +30,6 @@ url_manual_mapping = (
|
||||
("bpy.types.clothcollisionsettings.vertex_group_object_collisions*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings-vertex-group-object-collisions"),
|
||||
("bpy.types.gpencilsculptsettings.use_automasking_material_active*", "grease_pencil/modes/sculpting/introduction.html#bpy-types-gpencilsculptsettings-use-automasking-material-active"),
|
||||
("bpy.types.gpencilsculptsettings.use_automasking_material_stroke*", "grease_pencil/modes/sculpting/introduction.html#bpy-types-gpencilsculptsettings-use-automasking-material-stroke"),
|
||||
("bpy.types.preferencessystem.max_shader_compilation_subprocesses*", "editors/preferences/system.html#bpy-types-preferencessystem-max-shader-compilation-subprocesses"),
|
||||
("bpy.types.cycleslightsettings.use_multiple_importance_sampling*", "render/cycles/light_settings.html#bpy-types-cycleslightsettings-use-multiple-importance-sampling"),
|
||||
("bpy.types.fluiddomainsettings.sndparticle_potential_max_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-energy"),
|
||||
("bpy.types.fluiddomainsettings.sndparticle_potential_min_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-energy"),
|
||||
@@ -80,6 +79,7 @@ url_manual_mapping = (
|
||||
("bpy.types.preferencesedit.grease_pencil_euclidean_distance*", "editors/preferences/editing.html#bpy-types-preferencesedit-grease-pencil-euclidean-distance"),
|
||||
("bpy.types.preferencesedit.grease_pencil_manhattan_distance*", "editors/preferences/editing.html#bpy-types-preferencesedit-grease-pencil-manhattan-distance"),
|
||||
("bpy.types.preferencesinput.mouse_emulate_3_button_modifier*", "editors/preferences/input.html#bpy-types-preferencesinput-mouse-emulate-3-button-modifier"),
|
||||
("bpy.types.preferencessystem.max_shader_compilation_workers*", "editors/preferences/system.html#bpy-types-preferencessystem-max-shader-compilation-workers"),
|
||||
("bpy.types.brushgpencilsettings.use_stroke_random_strength*", "grease_pencil/modes/draw/brushes/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-strength"),
|
||||
("bpy.types.clothsettings.vertex_group_structural_stiffness*", "physics/cloth/settings/property_weights.html#bpy-types-clothsettings-vertex-group-structural-stiffness"),
|
||||
("bpy.types.cyclesrendersettings.film_transparent_roughness*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-roughness"),
|
||||
|
||||
@@ -23,7 +23,8 @@ class SPREADSHEET_HT_header(bpy.types.Header):
|
||||
row.prop(space, "use_filter", toggle=True, icon='FILTER', icon_only=True)
|
||||
|
||||
def selection_filter_available(self, space):
|
||||
root_context = space.viewer_path.path[0]
|
||||
if (root_context := next(iter(space.viewer_path.path), None)) is None:
|
||||
return False
|
||||
if root_context.type != 'ID':
|
||||
return False
|
||||
if not isinstance(root_context.id, bpy.types.Object):
|
||||
|
||||
@@ -809,8 +809,11 @@ class USERPREF_PT_system_memory(SystemPanel, CenterAlignMixIn, Panel):
|
||||
|
||||
if sys.platform != "darwin":
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.prop(system, "max_shader_compilation_subprocesses")
|
||||
col = layout.column(align=True)
|
||||
col.active = system.gpu_backend != 'VULKAN'
|
||||
col.row().prop(system, "shader_compilation_method", expand=True)
|
||||
label = "Threads" if system.shader_compilation_method == 'THREAD' else "Subprocesses"
|
||||
col.prop(system, "gpu_shader_workers", text=label)
|
||||
|
||||
|
||||
class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel):
|
||||
|
||||
@@ -1496,6 +1496,12 @@ void blo_do_versions_userdef(UserDef *userdef)
|
||||
}
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(405, 86)) {
|
||||
if (userdef->gpu_shader_workers > 0) {
|
||||
userdef->shader_compilation_method = USER_SHADER_COMPILE_SUBPROCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a USER_VERSION_ATLEAST check.
|
||||
|
||||
@@ -722,11 +722,14 @@ void Instance::draw_viewport()
|
||||
}
|
||||
if (materials.queued_shaders_count > 0) {
|
||||
info_append_i18n("Compiling shaders ({} remaining)", materials.queued_shaders_count);
|
||||
if (!GPU_use_parallel_compilation() &&
|
||||
GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_ANY, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL))
|
||||
if (GPU_backend_get_type() == GPU_BACKEND_OPENGL && !GPU_use_subprocess_compilation() &&
|
||||
/* Only recommend subprocesses when there is known gain. */
|
||||
(GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) ||
|
||||
GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY) ||
|
||||
GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)))
|
||||
{
|
||||
info_append_i18n(
|
||||
"Increasing Preferences > System > Max Shader Compilation Subprocesses may improve "
|
||||
"Setting Preferences > System > Shader Compilation Method to Subprocess might improve "
|
||||
"compilation time.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,23 +347,30 @@ float3 DrawingPlacement::try_project_depth(const float2 co) const
|
||||
return proj_point;
|
||||
}
|
||||
|
||||
float3 DrawingPlacement::project(const float2 co) const
|
||||
float3 DrawingPlacement::project(const float2 co, bool &r_clipped) const
|
||||
{
|
||||
float3 proj_point;
|
||||
if (depth_ == DrawingPlacementDepth::Surface) {
|
||||
/* Project using the viewport depth cache. */
|
||||
proj_point = this->try_project_depth(co);
|
||||
r_clipped = false;
|
||||
}
|
||||
else {
|
||||
if (placement_plane_) {
|
||||
ED_view3d_win_to_3d_on_plane(region_, *placement_plane_, co, false, proj_point);
|
||||
r_clipped = !ED_view3d_win_to_3d_on_plane(region_, *placement_plane_, co, true, proj_point);
|
||||
}
|
||||
else {
|
||||
ED_view3d_win_to_3d(view3d_, region_, placement_loc_, co, proj_point);
|
||||
r_clipped = false;
|
||||
}
|
||||
}
|
||||
return math::transform_point(world_space_to_layer_space_, proj_point);
|
||||
}
|
||||
float3 DrawingPlacement::project(const float2 co) const
|
||||
{
|
||||
[[maybe_unused]] bool clipped_unused;
|
||||
return this->project(co, clipped_unused);
|
||||
}
|
||||
|
||||
float3 DrawingPlacement::project_with_shift(const float2 co) const
|
||||
{
|
||||
|
||||
@@ -175,6 +175,7 @@ class DrawingPlacement {
|
||||
/**
|
||||
* Projects a screen space coordinate to the local drawing space.
|
||||
*/
|
||||
float3 project(float2 co, bool &clipped) const;
|
||||
float3 project(float2 co) const;
|
||||
void project(Span<float2> src, MutableSpan<float3> dst) const;
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "BKE_compute_context_cache_fwd.hh"
|
||||
|
||||
#include "NOD_geometry_nodes_closure_location.hh"
|
||||
#include "NOD_nested_node_id.hh"
|
||||
|
||||
#include "ED_node_c.hh"
|
||||
|
||||
@@ -82,7 +83,10 @@ void std_node_socket_colors_get(int socket_type, float *r_color);
|
||||
/**
|
||||
* Find the nested node id of a currently visible node in the root tree.
|
||||
*/
|
||||
std::optional<int32_t> find_nested_node_id_in_root(const SpaceNode &snode, const bNode &node);
|
||||
std::optional<nodes::FoundNestedNodeID> find_nested_node_id_in_root(const SpaceNode &snode,
|
||||
const bNode &node);
|
||||
std::optional<nodes::FoundNestedNodeID> find_nested_node_id_in_root(
|
||||
const bNodeTree &root_tree, const ComputeContext *compute_context, const int node_id);
|
||||
|
||||
struct ObjectAndModifier {
|
||||
const Object *object;
|
||||
@@ -112,6 +116,9 @@ bool node_editor_is_for_geometry_nodes_modifier(const SpaceNode &snode,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const bNodeSocket &socket);
|
||||
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_edittree_node(
|
||||
const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNode &node);
|
||||
|
||||
/**
|
||||
* Attempts to find a compute context that the closure is evaluated in. If none is found, null is
|
||||
* returned. If multiple are found, it currently picks the first one it finds which is somewhat
|
||||
|
||||
@@ -542,6 +542,27 @@ static int project_brush_radius(ViewContext *vc, float radius, const float locat
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int project_brush_radius_grease_pencil(ViewContext *vc,
|
||||
const float radius,
|
||||
const float3 world_location,
|
||||
const float4x4 &to_world)
|
||||
{
|
||||
const float2 xy_delta = float2(1.0f, 0.0f);
|
||||
|
||||
bool z_flip;
|
||||
const float zfac = ED_view3d_calc_zfac_ex(vc->rv3d, world_location, &z_flip);
|
||||
if (z_flip) {
|
||||
/* Location is behind camera. Return 0 to make the cursor disappear. */
|
||||
return 0;
|
||||
}
|
||||
float3 delta;
|
||||
ED_view3d_win_to_delta(vc->region, xy_delta, zfac, delta);
|
||||
|
||||
const float scale = math::length(
|
||||
math::transform_direction(to_world, float3(math::numbers::inv_sqrt3)));
|
||||
return math::safe_divide(scale * radius, math::length(delta));
|
||||
}
|
||||
|
||||
/* Draw an overlay that shows what effect the brush's texture will
|
||||
* have on brush strength. */
|
||||
static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
|
||||
@@ -1584,11 +1605,18 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext &pcontext)
|
||||
const bke::greasepencil::Layer *layer = grease_pencil->get_active_layer();
|
||||
const ed::greasepencil::DrawingPlacement placement(
|
||||
*pcontext.scene, *pcontext.region, *pcontext.vc.v3d, *object, layer);
|
||||
const float3 location = math::transform_point(
|
||||
placement.to_world_space(),
|
||||
placement.project(float2(pcontext.mval.x, pcontext.mval.y)));
|
||||
pcontext.pixel_radius = project_brush_radius(
|
||||
&pcontext.vc, brush->unprojected_radius, location);
|
||||
const float2 coordinate = float2(pcontext.mval.x - pcontext.region->winrct.xmin,
|
||||
pcontext.mval.y - pcontext.region->winrct.ymin);
|
||||
bool clipped = false;
|
||||
const float3 pos = placement.project(coordinate, clipped);
|
||||
if (!clipped) {
|
||||
const float3 world_location = math::transform_point(placement.to_world_space(), pos);
|
||||
pcontext.pixel_radius = project_brush_radius_grease_pencil(
|
||||
&pcontext.vc, brush->unprojected_radius, world_location, placement.to_world_space());
|
||||
}
|
||||
else {
|
||||
pcontext.pixel_radius = 0;
|
||||
}
|
||||
brush->size = std::max(pcontext.pixel_radius, 1);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -295,6 +295,9 @@ static void gather_socket_link_operations(const bContext &C,
|
||||
}
|
||||
const bNodeTreeInterfaceSocket &interface_socket =
|
||||
reinterpret_cast<const bNodeTreeInterfaceSocket &>(item);
|
||||
if (!(interface_socket.flag & NODE_INTERFACE_SOCKET_INPUT)) {
|
||||
return true;
|
||||
}
|
||||
{
|
||||
const bke::bNodeSocketType *from_typeinfo = bke::node_socket_type_find(
|
||||
interface_socket.socket_type);
|
||||
|
||||
@@ -268,51 +268,53 @@ float2 space_node_group_offset(const SpaceNode &snode)
|
||||
return float2(0);
|
||||
}
|
||||
|
||||
static const bNode *group_node_by_name(const bNodeTree &ntree, StringRef name)
|
||||
{
|
||||
for (const bNode *node : ntree.group_nodes()) {
|
||||
if (node->name == name) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<int32_t> find_nested_node_id_in_root(const SpaceNode &snode, const bNode &query_node)
|
||||
std::optional<nodes::FoundNestedNodeID> find_nested_node_id_in_root(const SpaceNode &snode,
|
||||
const bNode &query_node)
|
||||
{
|
||||
BLI_assert(snode.edittree->runtime->nodes_by_id.contains(const_cast<bNode *>(&query_node)));
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *compute_context = compute_context_for_edittree_node(
|
||||
snode, compute_context_cache, query_node);
|
||||
if (!compute_context) {
|
||||
return {};
|
||||
}
|
||||
return find_nested_node_id_in_root(*snode.nodetree, compute_context, query_node.identifier);
|
||||
}
|
||||
|
||||
std::optional<int32_t> id_in_node;
|
||||
const char *group_node_name = nullptr;
|
||||
const bNode *node = &query_node;
|
||||
LISTBASE_FOREACH_BACKWARD (const bNodeTreePath *, path, &snode.treepath) {
|
||||
const bNodeTree *ntree = path->nodetree;
|
||||
ntree->ensure_topology_cache();
|
||||
if (group_node_name) {
|
||||
node = group_node_by_name(*ntree, group_node_name);
|
||||
std::optional<nodes::FoundNestedNodeID> find_nested_node_id_in_root(
|
||||
const bNodeTree &root_tree, const ComputeContext *compute_context, const int node_id)
|
||||
{
|
||||
nodes::FoundNestedNodeID found;
|
||||
Vector<int> node_ids;
|
||||
for (const ComputeContext *context = compute_context; context != nullptr;
|
||||
context = context->parent())
|
||||
{
|
||||
if (const auto *node_context = dynamic_cast<const bke::GroupNodeComputeContext *>(context)) {
|
||||
node_ids.append(node_context->node_id());
|
||||
}
|
||||
bool found = false;
|
||||
for (const bNestedNodeRef &ref : ntree->nested_node_refs_span()) {
|
||||
if (node->is_group()) {
|
||||
if (ref.path.node_id == node->identifier && ref.path.id_in_node == id_in_node) {
|
||||
group_node_name = path->node_name;
|
||||
id_in_node = ref.id;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ref.path.node_id == node->identifier) {
|
||||
group_node_name = path->node_name;
|
||||
id_in_node = ref.id;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else if (dynamic_cast<const bke::RepeatZoneComputeContext *>(context) != nullptr) {
|
||||
found.is_in_loop = true;
|
||||
}
|
||||
if (!found) {
|
||||
return std::nullopt;
|
||||
else if (dynamic_cast<const bke::SimulationZoneComputeContext *>(context) != nullptr) {
|
||||
found.is_in_simulation = true;
|
||||
}
|
||||
else if (dynamic_cast<const bke::ForeachGeometryElementZoneComputeContext *>(context) !=
|
||||
nullptr)
|
||||
{
|
||||
found.is_in_loop = true;
|
||||
}
|
||||
else if (dynamic_cast<const bke::EvaluateClosureComputeContext *>(context) != nullptr) {
|
||||
found.is_in_closure = true;
|
||||
}
|
||||
}
|
||||
return id_in_node;
|
||||
std::reverse(node_ids.begin(), node_ids.end());
|
||||
node_ids.append(node_id);
|
||||
const bNestedNodeRef *nested_node_ref = root_tree.nested_node_ref_from_node_id_path(node_ids);
|
||||
if (nested_node_ref == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
found.id = nested_node_ref->id;
|
||||
return found;
|
||||
}
|
||||
|
||||
std::optional<ObjectAndModifier> get_modifier_for_node_editor(const SpaceNode &snode)
|
||||
@@ -645,6 +647,22 @@ const ComputeContext *compute_context_for_edittree_socket(
|
||||
return compute_context_for_zones(zone_stack, compute_context_cache, context);
|
||||
}
|
||||
|
||||
const ComputeContext *compute_context_for_edittree_node(
|
||||
const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNode &node)
|
||||
{
|
||||
const ComputeContext *context = compute_context_for_edittree(snode, compute_context_cache);
|
||||
if (!context) {
|
||||
return nullptr;
|
||||
}
|
||||
const bke::bNodeTreeZones *zones = snode.edittree->zones();
|
||||
if (!zones) {
|
||||
return nullptr;
|
||||
}
|
||||
const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
|
||||
const Vector<const bke::bNodeTreeZone *> zone_stack = zones->get_zones_to_enter_from_root(zone);
|
||||
return compute_context_for_zones(zone_stack, compute_context_cache, context);
|
||||
}
|
||||
|
||||
/* ******************** default callbacks for node space ***************** */
|
||||
|
||||
static SpaceLink *node_create(const ScrArea * /*area*/, const Scene * /*scene*/)
|
||||
|
||||
@@ -43,7 +43,7 @@ const char *GPU_extension_get(int i);
|
||||
|
||||
int GPU_texture_size_with_limit(int res);
|
||||
|
||||
bool GPU_use_parallel_compilation();
|
||||
bool GPU_use_subprocess_compilation();
|
||||
int GPU_max_parallel_compilations();
|
||||
|
||||
bool GPU_stencil_clasify_buffer_workaround();
|
||||
|
||||
@@ -131,9 +131,9 @@ int GPU_max_samplers()
|
||||
return GCaps.max_samplers;
|
||||
}
|
||||
|
||||
bool GPU_use_parallel_compilation()
|
||||
bool GPU_use_subprocess_compilation()
|
||||
{
|
||||
return GCaps.max_parallel_compilations > 0;
|
||||
return GCaps.use_subprocess_shader_compilations;
|
||||
}
|
||||
|
||||
int GPU_max_parallel_compilations()
|
||||
|
||||
@@ -63,6 +63,8 @@ struct GPUCapabilities {
|
||||
bool node_link_instancing_workaround = false;
|
||||
bool line_directive_workaround = false;
|
||||
|
||||
bool use_subprocess_shader_compilations = false;
|
||||
|
||||
/* Vulkan related workarounds. */
|
||||
bool render_pass_workaround = false;
|
||||
|
||||
|
||||
@@ -165,9 +165,8 @@ bool GPU_pass_should_optimize(GPUPass *pass)
|
||||
return (GPU_backend_get_type() == GPU_BACKEND_METAL) && pass->should_optimize;
|
||||
|
||||
#if 0
|
||||
/* Returns optimization heuristic prepared during initial codegen.
|
||||
* NOTE: Optimization limited to parallel compilation as it causes CPU stalls otherwise. */
|
||||
return pass->should_optimize && GPU_use_parallel_compilation();
|
||||
/* Returns optimization heuristic prepared during initial codegen. */
|
||||
return pass->should_optimize;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -574,16 +574,8 @@ bool gpu_shader_create_info_compile(const char *name_starts_with_filter)
|
||||
}
|
||||
}
|
||||
|
||||
Vector<GPUShader *> result;
|
||||
if (GPU_use_parallel_compilation() == false) {
|
||||
for (const GPUShaderCreateInfo *info : infos) {
|
||||
result.append(GPU_shader_create_from_info(info));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BatchHandle batch = GPU_shader_batch_create_from_infos(infos);
|
||||
result = GPU_shader_batch_finalize(batch);
|
||||
}
|
||||
BatchHandle batch = GPU_shader_batch_create_from_infos(infos);
|
||||
Vector<GPUShader *> result = GPU_shader_batch_finalize(batch);
|
||||
|
||||
for (int i : result.index_range()) {
|
||||
const ShaderCreateInfo *info = reinterpret_cast<const ShaderCreateInfo *>(infos[i]);
|
||||
|
||||
@@ -1551,7 +1551,6 @@ MTLComputePipelineStateInstance *MTLShader::bake_compute_pipeline_state(
|
||||
MTLShaderCompiler::MTLShaderCompiler()
|
||||
: ShaderCompiler(GPU_max_parallel_compilations(), GPUWorker::ContextType::PerThread, true)
|
||||
{
|
||||
BLI_assert(GPU_use_parallel_compilation());
|
||||
}
|
||||
|
||||
Shader *MTLShaderCompiler::compile_shader(const shader::ShaderCreateInfo &info)
|
||||
|
||||
@@ -723,17 +723,66 @@ void GLBackend::capabilities_init()
|
||||
detect_workarounds();
|
||||
|
||||
#if BLI_SUBPROCESS_SUPPORT
|
||||
if (GCaps.max_parallel_compilations == -1) {
|
||||
GCaps.max_parallel_compilations = std::min(int(U.max_shader_compilation_subprocesses),
|
||||
BLI_system_thread_count());
|
||||
}
|
||||
GCaps.use_subprocess_shader_compilations = U.shader_compilation_method ==
|
||||
USER_SHADER_COMPILE_SUBPROCESS;
|
||||
#else
|
||||
GCaps.use_subprocess_shader_compilations = false;
|
||||
#endif
|
||||
if (G.debug & G_DEBUG_GPU_RENDERDOC) {
|
||||
/* Avoid crashes on RenderDoc sessions. */
|
||||
GCaps.max_parallel_compilations = 0;
|
||||
GCaps.use_subprocess_shader_compilations = false;
|
||||
}
|
||||
#else
|
||||
GCaps.max_parallel_compilations = 0;
|
||||
#endif
|
||||
|
||||
int thread_count = U.gpu_shader_workers;
|
||||
|
||||
if (thread_count == 0) {
|
||||
/* Good default based on measurements. */
|
||||
|
||||
/* Always have at least 1 worker. */
|
||||
thread_count = 1;
|
||||
|
||||
if (GCaps.use_subprocess_shader_compilations) {
|
||||
/* Use reasonable number of worker by default when there are known gains. */
|
||||
if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) ||
|
||||
GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) ||
|
||||
GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY))
|
||||
{
|
||||
/* Subprocess is too costly in memory (>150MB per worker) to have better defaults. */
|
||||
thread_count = std::max(1, std::min(4, BLI_system_thread_count() / 2));
|
||||
}
|
||||
}
|
||||
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
|
||||
/* Best middle ground between memory usage and speedup as Nvidia context memory footprint
|
||||
* is quite heavy (~25MB). Moreover we have diminishing return after this because of PSO
|
||||
* compilation blocking the main thread.
|
||||
* Can be revisited if we find a way to delete the worker thread context after finishing
|
||||
* compilation, and fix the scheduling bubbles (#139775). */
|
||||
thread_count = 4;
|
||||
}
|
||||
else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OPENSOURCE) ||
|
||||
GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY))
|
||||
{
|
||||
/* Mesa has very good compilation time and doesn't block the main thread.
|
||||
* The memory footprint of the worker context is rather small (<10MB).
|
||||
* Shader compilation gets much slower as the number of threads increases. */
|
||||
thread_count = 8;
|
||||
}
|
||||
else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
|
||||
/* AMD proprietary driver's context have huge memory footprint (~45MB).
|
||||
* There is also not much gain from parallelization. */
|
||||
thread_count = 1;
|
||||
}
|
||||
else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) {
|
||||
/* Intel windows driver offer almost no speedup with parallel compilation. */
|
||||
thread_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow thread count override option to limit the number of workers and avoid allocating more
|
||||
* workers than needed. Also ensures that there is always 1 thread available for the UI. */
|
||||
int max_thread_count = std::max(1, BLI_system_thread_count() - 1);
|
||||
|
||||
GCaps.max_parallel_compilations = std::min(thread_count, max_thread_count);
|
||||
|
||||
/* Disable this feature entirely when not debugging. */
|
||||
if ((G.debug & G_DEBUG_GPU) == 0) {
|
||||
|
||||
@@ -9,10 +9,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_platform.hh"
|
||||
|
||||
#include "gpu_backend.hh"
|
||||
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "gpu_capabilities_private.hh"
|
||||
|
||||
#ifdef WITH_RENDERDOC
|
||||
# include "renderdoc_api.hh"
|
||||
#endif
|
||||
@@ -56,7 +61,7 @@ class GLBackend : public GPUBackend {
|
||||
|
||||
void init_resources() override
|
||||
{
|
||||
if (GPU_use_parallel_compilation()) {
|
||||
if (GCaps.use_subprocess_shader_compilations) {
|
||||
compiler_ = MEM_new<GLSubprocessShaderCompiler>(__func__);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -198,8 +198,8 @@ class GLShader : public Shader {
|
||||
|
||||
class GLShaderCompiler : public ShaderCompiler {
|
||||
public:
|
||||
GLShaderCompiler(uint32_t threads_count = 1)
|
||||
: ShaderCompiler(threads_count, GPUWorker::ContextType::PerThread, true){};
|
||||
GLShaderCompiler()
|
||||
: ShaderCompiler(GPU_max_parallel_compilations(), GPUWorker::ContextType::PerThread, true){};
|
||||
|
||||
virtual void specialize_shader(ShaderSpecialization &specialization) override;
|
||||
};
|
||||
|
||||
@@ -487,13 +487,17 @@ typedef struct UserDef {
|
||||
int gpu_preferred_index;
|
||||
uint32_t gpu_preferred_vendor_id;
|
||||
uint32_t gpu_preferred_device_id;
|
||||
char _pad16[4];
|
||||
|
||||
/** Max number of parallel shader compilation workers. */
|
||||
short gpu_shader_workers;
|
||||
/** eUserpref_ShaderCompileMethod (OpenGL only). */
|
||||
short shader_compilation_method;
|
||||
|
||||
char _pad16[2];
|
||||
|
||||
/** #eGPUBackendType */
|
||||
short gpu_backend;
|
||||
|
||||
/** Max number of parallel shader compilation subprocesses. */
|
||||
short max_shader_compilation_subprocesses;
|
||||
|
||||
/** Number of samples for FPS display calculations. */
|
||||
short playback_fps_samples;
|
||||
|
||||
@@ -1125,6 +1129,11 @@ typedef enum eUserpref_SeqEditorFlags {
|
||||
USER_SEQ_ED_CONNECT_STRIPS_BY_DEFAULT = (1 << 1),
|
||||
} eUserpref_SeqEditorFlags;
|
||||
|
||||
typedef enum eUserpref_ShaderCompileMethod {
|
||||
USER_SHADER_COMPILE_THREAD = 0,
|
||||
USER_SHADER_COMPILE_SUBPROCESS = 1,
|
||||
} eUserpref_ShaderCompileMethod;
|
||||
|
||||
/* Locale Ids. Auto will try to get local from OS. Our default is English though. */
|
||||
/** #UserDef.language */
|
||||
enum {
|
||||
|
||||
@@ -215,6 +215,7 @@ DNA_STRUCT_RENAME_MEMBER(UVProjectModifierData, num_projectors, projectors_num)
|
||||
DNA_STRUCT_RENAME_MEMBER(UserDef, autokey_flag, keying_flag)
|
||||
DNA_STRUCT_RENAME_MEMBER(UserDef, gp_manhattendist, gp_manhattandist)
|
||||
DNA_STRUCT_RENAME_MEMBER(UserDef, pythondir, pythondir_legacy)
|
||||
DNA_STRUCT_RENAME_MEMBER(UserDef, max_shader_compilation_subprocesses, gpu_shader_workers)
|
||||
DNA_STRUCT_RENAME_MEMBER(VFont, name, filepath)
|
||||
DNA_STRUCT_RENAME_MEMBER(View3D, far, clip_end)
|
||||
DNA_STRUCT_RENAME_MEMBER(View3D, local_collections_uuid, local_collections_uid)
|
||||
|
||||
@@ -6349,14 +6349,36 @@ static void rna_def_userdef_system(BlenderRNA *brna)
|
||||
"Preferred device to select during detection (requires restarting "
|
||||
"Blender for changes to take effect)");
|
||||
|
||||
prop = RNA_def_property(srna, "max_shader_compilation_subprocesses", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0, INT16_MAX);
|
||||
prop = RNA_def_property(srna, "gpu_shader_workers", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0, 32);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Max Shader Compilation Subprocesses",
|
||||
"Max number of parallel shader compilation subprocesses, "
|
||||
"Shader Compilation Workers",
|
||||
"Number of shader compilation threads or subprocesses, "
|
||||
"clamped at the max threads supported by the CPU "
|
||||
"(requires restarting Blender for changes to take effect). "
|
||||
"Setting it to 0 disables subprocess shader compilation.");
|
||||
"A higher number increases the RAM usage while reducing "
|
||||
"compilation time. A value of 0 will use automatic configuration. "
|
||||
"(OpenGL only)");
|
||||
|
||||
static const EnumPropertyItem shader_compilation_method_items[] = {
|
||||
{USER_SHADER_COMPILE_THREAD, "THREAD", 0, "Thread", "Use threads for compiling shaders"},
|
||||
{USER_SHADER_COMPILE_SUBPROCESS,
|
||||
"SUBPROCESS",
|
||||
0,
|
||||
"Subprocess",
|
||||
"Use subprocesses for compiling shaders"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
prop = RNA_def_property(srna, "shader_compilation_method", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, shader_compilation_method_items);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Shader Compilation Method",
|
||||
"Compilation method used for compiling shaders in parallel. "
|
||||
"Subprocess requires a lot more RAM for each worker "
|
||||
"but might compile shaders faster on some systems. "
|
||||
"Requires restarting Blender for changes to take effect. "
|
||||
"(OpenGL only)");
|
||||
|
||||
/* Network. */
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ set(SRC
|
||||
NOD_inverse_eval_run.hh
|
||||
NOD_math_functions.hh
|
||||
NOD_multi_function.hh
|
||||
NOD_nested_node_id.hh
|
||||
NOD_node_declaration.hh
|
||||
NOD_node_extra_info.hh
|
||||
NOD_node_in_compute_context.hh
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "NOD_geometry_nodes_log.hh"
|
||||
#include "NOD_multi_function.hh"
|
||||
#include "NOD_nested_node_id.hh"
|
||||
|
||||
#include "BLI_compute_context.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
@@ -461,13 +462,6 @@ std::string make_anonymous_attribute_socket_inspection_string(const bNodeSocket
|
||||
std::string make_anonymous_attribute_socket_inspection_string(StringRef node_name,
|
||||
StringRef socket_name);
|
||||
|
||||
struct FoundNestedNodeID {
|
||||
int id;
|
||||
bool is_in_simulation = false;
|
||||
bool is_in_loop = false;
|
||||
bool is_in_closure = false;
|
||||
};
|
||||
|
||||
std::optional<FoundNestedNodeID> find_nested_node_id(const GeoNodesUserData &user_data,
|
||||
const int node_id);
|
||||
|
||||
|
||||
20
source/blender/nodes/NOD_nested_node_id.hh
Normal file
20
source/blender/nodes/NOD_nested_node_id.hh
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
/**
|
||||
* Utility struct to store information about a nested node id. Also see #bNestedNodeRef.
|
||||
* Sometimes these IDs can only be used when they are at the top level and not within zones.
|
||||
*/
|
||||
struct FoundNestedNodeID {
|
||||
int id;
|
||||
bool is_in_simulation = false;
|
||||
bool is_in_loop = false;
|
||||
bool is_in_closure = false;
|
||||
};
|
||||
|
||||
} // namespace blender::nodes
|
||||
@@ -111,6 +111,7 @@ struct BakeDrawContext {
|
||||
bool bake_still;
|
||||
bool is_baked;
|
||||
std::optional<NodesModifierBakeTarget> bake_target;
|
||||
bool is_bakeable_in_current_context;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool get_bake_draw_context(const bContext *C,
|
||||
|
||||
@@ -489,6 +489,12 @@ static void node_extra_info(NodeExtraInfoParams ¶ms)
|
||||
if (!get_bake_draw_context(¶ms.C, params.node, ctx)) {
|
||||
return;
|
||||
}
|
||||
if (!ctx.is_bakeable_in_current_context) {
|
||||
NodeExtraInfoRow row;
|
||||
row.text = TIP_("Can't bake in zone");
|
||||
row.icon = ICON_ERROR;
|
||||
params.rows.append(std::move(row));
|
||||
}
|
||||
if (ctx.is_baked) {
|
||||
NodeExtraInfoRow row;
|
||||
row.text = get_baked_string(ctx);
|
||||
@@ -503,7 +509,7 @@ static void node_layout(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
if (!get_bake_draw_context(C, node, ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayoutSetActive(layout, ctx.is_bakeable_in_current_context);
|
||||
uiLayoutSetEnabled(layout, ID_IS_EDITABLE(ctx.object));
|
||||
uiLayout *col = &layout->column(false);
|
||||
{
|
||||
@@ -524,6 +530,7 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
uiLayoutSetActive(layout, ctx.is_bakeable_in_current_context);
|
||||
uiLayoutSetEnabled(layout, ID_IS_EDITABLE(ctx.object));
|
||||
|
||||
{
|
||||
@@ -631,14 +638,15 @@ bool get_bake_draw_context(const bContext *C, const bNode &node, BakeDrawContext
|
||||
}
|
||||
r_ctx.object = object_and_modifier->object;
|
||||
r_ctx.nmd = object_and_modifier->nmd;
|
||||
const std::optional<int32_t> bake_id = ed::space_node::find_nested_node_id_in_root(*r_ctx.snode,
|
||||
*r_ctx.node);
|
||||
const std::optional<FoundNestedNodeID> bake_id = ed::space_node::find_nested_node_id_in_root(
|
||||
*r_ctx.snode, *r_ctx.node);
|
||||
if (!bake_id) {
|
||||
return false;
|
||||
}
|
||||
r_ctx.is_bakeable_in_current_context = !bake_id->is_in_loop && !bake_id->is_in_closure;
|
||||
r_ctx.bake = nullptr;
|
||||
for (const NodesModifierBake &iter_bake : Span(r_ctx.nmd->bakes, r_ctx.nmd->bakes_num)) {
|
||||
if (iter_bake.id == *bake_id) {
|
||||
if (iter_bake.id == bake_id->id) {
|
||||
r_ctx.bake = &iter_bake;
|
||||
break;
|
||||
}
|
||||
@@ -653,7 +661,7 @@ bool get_bake_draw_context(const bContext *C, const bNode &node, BakeDrawContext
|
||||
const bke::bake::ModifierCache &cache = *r_ctx.nmd->runtime->cache;
|
||||
std::lock_guard lock{cache.mutex};
|
||||
if (const std::unique_ptr<bke::bake::BakeNodeCache> *node_cache_ptr =
|
||||
cache.bake_cache_by_id.lookup_ptr(*bake_id))
|
||||
cache.bake_cache_by_id.lookup_ptr(bake_id->id))
|
||||
{
|
||||
const bke::bake::BakeNodeCache &node_cache = **node_cache_ptr;
|
||||
if (!node_cache.bake.frames.is_empty()) {
|
||||
@@ -663,7 +671,7 @@ bool get_bake_draw_context(const bContext *C, const bNode &node, BakeDrawContext
|
||||
}
|
||||
}
|
||||
else if (const std::unique_ptr<bke::bake::SimulationNodeCache> *node_cache_ptr =
|
||||
cache.simulation_cache_by_id.lookup_ptr(*bake_id))
|
||||
cache.simulation_cache_by_id.lookup_ptr(bake_id->id))
|
||||
{
|
||||
const bke::bake::SimulationNodeCache &node_cache = **node_cache_ptr;
|
||||
if (!node_cache.bake.frames.is_empty() &&
|
||||
|
||||
@@ -225,6 +225,7 @@ static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_no
|
||||
if (!get_bake_draw_context(C, output_node, ctx)) {
|
||||
return;
|
||||
}
|
||||
uiLayoutSetActive(layout, ctx.is_bakeable_in_current_context);
|
||||
|
||||
draw_simulation_state(C, layout, ntree, output_node);
|
||||
|
||||
@@ -865,6 +866,12 @@ static void node_extra_info(NodeExtraInfoParams ¶ms)
|
||||
if (!get_bake_draw_context(¶ms.C, params.node, ctx)) {
|
||||
return;
|
||||
}
|
||||
if (!ctx.is_bakeable_in_current_context) {
|
||||
NodeExtraInfoRow row;
|
||||
row.text = TIP_("Can't bake in zone");
|
||||
row.icon = ICON_ERROR;
|
||||
params.rows.append(std::move(row));
|
||||
}
|
||||
if (ctx.is_baked) {
|
||||
NodeExtraInfoRow row;
|
||||
row.text = get_baked_string(ctx);
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
#include "BKE_type_conversions.hh"
|
||||
|
||||
#include "ED_node.hh"
|
||||
|
||||
#include "FN_lazy_function_graph_executor.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
@@ -4302,38 +4304,8 @@ void GeoNodesLocalUserData::ensure_tree_logger(const GeoNodesUserData &user_data
|
||||
std::optional<FoundNestedNodeID> find_nested_node_id(const GeoNodesUserData &user_data,
|
||||
const int node_id)
|
||||
{
|
||||
FoundNestedNodeID found;
|
||||
Vector<int> node_ids;
|
||||
for (const ComputeContext *context = user_data.compute_context; context != nullptr;
|
||||
context = context->parent())
|
||||
{
|
||||
if (const auto *node_context = dynamic_cast<const bke::GroupNodeComputeContext *>(context)) {
|
||||
node_ids.append(node_context->node_id());
|
||||
}
|
||||
else if (dynamic_cast<const bke::RepeatZoneComputeContext *>(context) != nullptr) {
|
||||
found.is_in_loop = true;
|
||||
}
|
||||
else if (dynamic_cast<const bke::SimulationZoneComputeContext *>(context) != nullptr) {
|
||||
found.is_in_simulation = true;
|
||||
}
|
||||
else if (dynamic_cast<const bke::ForeachGeometryElementZoneComputeContext *>(context) !=
|
||||
nullptr)
|
||||
{
|
||||
found.is_in_loop = true;
|
||||
}
|
||||
else if (dynamic_cast<const bke::EvaluateClosureComputeContext *>(context) != nullptr) {
|
||||
found.is_in_closure = true;
|
||||
}
|
||||
}
|
||||
std::reverse(node_ids.begin(), node_ids.end());
|
||||
node_ids.append(node_id);
|
||||
const bNestedNodeRef *nested_node_ref =
|
||||
user_data.call_data->root_ntree->nested_node_ref_from_node_id_path(node_ids);
|
||||
if (nested_node_ref == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
found.id = nested_node_ref->id;
|
||||
return found;
|
||||
return ed::space_node::find_nested_node_id_in_root(
|
||||
*user_data.call_data->root_ntree, user_data.compute_context, node_id);
|
||||
}
|
||||
|
||||
GeoNodesOperatorDepsgraphs::~GeoNodesOperatorDepsgraphs()
|
||||
|
||||
Reference in New Issue
Block a user