GPv3: Cyclical set operator #111904

Merged
Falk David merged 16 commits from casey-bianco-davis/blender:GPv3-cyclical-set-operator into main 2023-10-20 10:12:34 +02:00
191 changed files with 3579 additions and 1587 deletions
Showing only changes of commit 051bad9e88 - Show all commits

View File

@ -513,6 +513,8 @@ endif()
# Misc
if(WIN32 OR APPLE)
option(WITH_INPUT_IME "Enable Input Method Editor (IME) for complex Asian character input" ON)
else()
set(WITH_INPUT_IME OFF)
endif()
option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
if(UNIX AND NOT APPLE)
@ -1138,7 +1140,7 @@ if(UNIX AND NOT (APPLE OR HAIKU))
endif()
set_and_warn_incompatible(WITH_HEADLESS WITH_GHOST_SDL OFF)
if(WIN32 OR APPLE)
if(WITH_INPUT_IME)
set_and_warn_incompatible(WITH_HEADLESS WITH_INPUT_IME OFF)
set_and_warn_incompatible(WITH_GHOST_SDL WITH_INPUT_IME OFF)
endif()

View File

@ -59,6 +59,13 @@ macro(path_ensure_trailing_slash
unset(_path_sep)
endmacro()
macro(path_strip_trailing_slash
path_new path_input
)
file(TO_NATIVE_PATH "/" _path_sep)
string(REGEX REPLACE "[${_path_sep}]+$" "" ${path_new} ${path_input})
endmacro()
# Our own version of `cmake_path(IS_PREFIX ..)`.
# This can be removed when 3.20 or greater is the minimum supported version.
macro(path_is_prefix
@ -1404,6 +1411,67 @@ Path to python site-packages or dist-packages containing '${package}' module hea
endif()
endfunction()
# Find a file in Python's module path and cache it.
# Re-generating cache upon changes to the Python installation.
# `out_var_abs`: absolute path (cached).
# `out_var_rel`: `PYTHON_ROOT` relative path (not cached).
macro(find_python_module_file
module_file
out_var_abs
out_var_rel
)
# Reset if the file isn't found.
if(DEFINED ${out_var_abs})
if(NOT EXISTS ${${out_var_abs}})
unset(${out_var_abs} CACHE)
endif()
endif()
# Reset if the version number or Python path changes.
set(_python_mod_file_deps_test "${PYTHON_LIBPATH};${PYTHON_VERSION}")
if(DEFINED _${out_var_abs}_DEPS)
if(NOT (_${out_var_abs}_DEPS STREQUAL _python_mod_file_deps_test))
unset(${out_var_abs} CACHE)
endif()
else()
unset(${out_var_abs} CACHE)
endif()
path_strip_trailing_slash(_python_root "${PYTHON_LIBPATH}")
set(_python_base "${_python_root}/python${PYTHON_VERSION}")
# This always moves up one level (even if there is a trailing slash).
get_filename_component(_python_root "${_python_root}" DIRECTORY)
path_ensure_trailing_slash(_python_root "${_python_root}")
if(NOT (DEFINED ${out_var_abs}))
message(STATUS "Finding Python Module File: ${module_file}")
find_file(${out_var_abs}
NAMES
"${module_file}"
PATHS
"${_python_base}"
PATH_SUFFIXES
"site-packages"
"dist-packages"
"vendor-packages"
""
NO_DEFAULT_PATH
)
if(${out_var_abs})
set(_${out_var_abs}_DEPS "${_python_mod_file_deps_test}" CACHE STRING "")
string(LENGTH "${_python_root}" _python_root_len)
string(SUBSTRING ${${out_var_abs}} ${_python_root_len} -1 ${out_var_rel})
unset(_python_root_len)
endif()
endif()
unset(_python_mod_file_deps_test)
unset(_python_base)
unset(_python_root)
endmacro()
# like Python's 'print(dir())'
function(print_all_vars)
get_cmake_property(_vars VARIABLES)

View File

@ -37,6 +37,14 @@ template<> struct AttributeConverter<int> {
return float(value);
}
};
template<> struct AttributeConverter<blender::float2> {
using CyclesT = float2;
static constexpr auto type_desc = TypeFloat2;
static CyclesT convert(const blender::float2 &value)
{
return make_float2(value[0], value[1]);
}
};
template<> struct AttributeConverter<blender::float3> {
using CyclesT = float3;
static constexpr auto type_desc = TypeVector;

View File

@ -345,6 +345,12 @@ string MetalDevice::preprocess_source(MetalPipelineType pso_type,
break;
case METAL_GPU_AMD:
global_defines += "#define __KERNEL_METAL_AMD__\n";
/* The increased amount of BSDF code leads to a big performance regression
* on AMD. There is currently no workaround to fix this general. Instead
* disable Principled Hair. */
if (kernel_features & KERNEL_FEATURE_NODE_PRINCIPLED_HAIR) {
global_defines += "#define WITH_PRINCIPLED_HAIR\n";
}
break;
case METAL_GPU_APPLE:
global_defines += "#define __KERNEL_METAL_APPLE__\n";

View File

@ -66,13 +66,14 @@ struct SocketType {
LINK_TEXTURE_GENERATED = (1 << 4),
LINK_TEXTURE_NORMAL = (1 << 5),
LINK_TEXTURE_UV = (1 << 6),
LINK_INCOMING = (1 << 7),
LINK_NORMAL = (1 << 8),
LINK_POSITION = (1 << 9),
LINK_TANGENT = (1 << 10),
LINK_OSL_INITIALIZER = (1 << 11),
LINK_TEXTURE_INCOMING = (1 << 7),
LINK_INCOMING = (1 << 8),
LINK_NORMAL = (1 << 9),
LINK_POSITION = (1 << 10),
LINK_TANGENT = (1 << 11),
LINK_OSL_INITIALIZER = (1 << 12),
DEFAULT_LINK_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) |
(1 << 10) | (1 << 11)
(1 << 10) | (1 << 11) | (1 << 12)
};
ustring name;

View File

@ -195,6 +195,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
sc, Ng, sd->wi, rand_xy, eval, wo, pdf, sampled_roughness);
*eta = 1.0f;
break;
# ifdef __PRINCIPLED_HAIR__
case CLOSURE_BSDF_HAIR_CHIANG_ID:
label = bsdf_hair_chiang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness);
*eta = 1.0f;
@ -203,6 +204,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
label = bsdf_hair_huang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness);
*eta = 1.0f;
break;
# endif
case CLOSURE_BSDF_SHEEN_ID:
label = bsdf_sheen_sample(sc, Ng, sd->wi, rand_xy, eval, wo, pdf);
*sampled_roughness = one_float2();
@ -325,6 +327,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
((ccl_private HairBsdf *)sc)->roughness2);
*eta = 1.0f;
break;
# ifdef __PRINCIPLED_HAIR__
case CLOSURE_BSDF_HAIR_CHIANG_ID:
alpha = ((ccl_private ChiangHairBSDF *)sc)->m0_roughness;
*roughness = make_float2(alpha, alpha);
@ -335,6 +338,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
*roughness = make_float2(alpha, alpha);
*eta = 1.0f;
break;
# endif
case CLOSURE_BSDF_SHEEN_ID:
alpha = ((ccl_private SheenBsdf *)sc)->roughness;
*roughness = make_float2(alpha, alpha);
@ -409,6 +413,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
label = LABEL_TRANSMIT | LABEL_GLOSSY;
break;
# ifdef __PRINCIPLED_HAIR__
case CLOSURE_BSDF_HAIR_CHIANG_ID:
if (bsdf_is_transmission(sc, wo))
label = LABEL_TRANSMIT | LABEL_GLOSSY;
@ -418,6 +423,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_HAIR_HUANG_ID:
label = LABEL_REFLECT | LABEL_GLOSSY;
break;
# endif
case CLOSURE_BSDF_SHEEN_ID:
label = LABEL_REFLECT | LABEL_DIFFUSE;
break;
@ -500,12 +506,14 @@ ccl_device_inline
case CLOSURE_BSDF_GLOSSY_TOON_ID:
eval = bsdf_glossy_toon_eval(sc, sd->wi, wo, pdf);
break;
# ifdef __PRINCIPLED_HAIR__
case CLOSURE_BSDF_HAIR_CHIANG_ID:
eval = bsdf_hair_chiang_eval(kg, sd, sc, wo, pdf);
break;
case CLOSURE_BSDF_HAIR_HUANG_ID:
eval = bsdf_hair_huang_eval(kg, sd, sc, wo, pdf);
break;
# endif
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
eval = bsdf_hair_reflection_eval(sc, sd->wi, wo, pdf);
break;
@ -560,12 +568,14 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
bsdf_ashikhmin_shirley_blur(sc, roughness);
break;
# ifdef __PRINCIPLED_HAIR__
case CLOSURE_BSDF_HAIR_CHIANG_ID:
bsdf_hair_chiang_blur(sc, roughness);
break;
case CLOSURE_BSDF_HAIR_HUANG_ID:
bsdf_hair_huang_blur(sc, roughness);
break;
# endif
default:
break;
}
@ -593,6 +603,7 @@ ccl_device_inline Spectrum bsdf_albedo(KernelGlobals kg,
albedo *= bsdf_microfacet_estimate_albedo(
kg, sd, (ccl_private const MicrofacetBsdf *)sc, reflection, transmission);
}
# ifdef __PRINCIPLED_HAIR__
else if (sc->type == CLOSURE_BSDF_HAIR_CHIANG_ID) {
/* TODO(lukas): Principled Hair could also be split into a glossy and a transmission component,
* similar to Glass BSDFs. */
@ -601,6 +612,7 @@ ccl_device_inline Spectrum bsdf_albedo(KernelGlobals kg,
else if (sc->type == CLOSURE_BSDF_HAIR_HUANG_ID) {
albedo *= bsdf_hair_huang_albedo(sd, sc);
}
# endif
#endif
return albedo;
}

View File

@ -638,6 +638,7 @@ ccl_device
break;
}
#ifdef __HAIR__
# ifdef __PRINCIPLED_HAIR__
case CLOSURE_BSDF_HAIR_CHIANG_ID:
case CLOSURE_BSDF_HAIR_HUANG_ID: {
uint4 data_node2 = read_node(kg, &offset);
@ -790,6 +791,7 @@ ccl_device
}
break;
}
# endif /* __PRINCIPLED_HAIR__ */
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
Spectrum weight = closure_weight * mix_weight;

View File

@ -75,6 +75,7 @@ CCL_NAMESPACE_BEGIN
#define __PASSES__
#define __PATCH_EVAL__
#define __POINTCLOUD__
#define __PRINCIPLED_HAIR__
#define __RAY_DIFFERENTIALS__
#define __SHADER_RAYTRACE__
#define __SHADOW_CATCHER__
@ -111,6 +112,10 @@ CCL_NAMESPACE_BEGIN
# undef __LIGHT_TREE__
/* Disabled due to compiler crash on Metal/AMD. */
# undef __MNEE__
/* Disable due to performance regression on Metal/AMD. */
# ifndef WITH_PRINCIPLED_HAIR
# undef __PRINCIPLED_HAIR__
# endif
#endif
/* Scene-based selective features compilation. */
@ -1681,9 +1686,7 @@ enum KernelFeatureFlag : uint32_t {
KERNEL_FEATURE_NODE_RAYTRACE = (1U << 6U),
KERNEL_FEATURE_NODE_AOV = (1U << 7U),
KERNEL_FEATURE_NODE_LIGHT_PATH = (1U << 8U),
/* Use denoising kernels and output denoising passes. */
KERNEL_FEATURE_DENOISING = (1U << 9U),
KERNEL_FEATURE_NODE_PRINCIPLED_HAIR = (1U << 9U),
/* Use path tracing kernels. */
KERNEL_FEATURE_PATH_TRACING = (1U << 10U),
@ -1732,6 +1735,9 @@ enum KernelFeatureFlag : uint32_t {
/* Light and shadow linking. */
KERNEL_FEATURE_LIGHT_LINKING = (1U << 27U),
KERNEL_FEATURE_SHADOW_LINKING = (1U << 28U),
/* Use denoising kernels and output denoising passes. */
KERNEL_FEATURE_DENOISING = (1U << 29U),
};
/* Shader node feature mask, to specialize shader evaluation for kernels. */
@ -1744,7 +1750,7 @@ enum KernelFeatureFlag : uint32_t {
#define KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW \
(KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_BUMP | \
KERNEL_FEATURE_NODE_BUMP_STATE | KERNEL_FEATURE_NODE_VORONOI_EXTRA | \
KERNEL_FEATURE_NODE_LIGHT_PATH)
KERNEL_FEATURE_NODE_LIGHT_PATH | KERNEL_FEATURE_NODE_PRINCIPLED_HAIR)
#define KERNEL_FEATURE_NODE_MASK_SURFACE \
(KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW | KERNEL_FEATURE_NODE_RAYTRACE | \
KERNEL_FEATURE_NODE_AOV | KERNEL_FEATURE_NODE_LIGHT_PATH)

View File

@ -349,13 +349,22 @@ void Shader::tag_update(Scene *scene)
has_displacement = has_displacement || output->input("Displacement")->link;
if (!has_surface) {
/* If we need to output surface AOVs, add a Transparent BSDF so that the
* surface shader runs. */
foreach (ShaderNode *node, graph->nodes) {
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
foreach (const ShaderInput *in, node->inputs) {
if (in->link) {
TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
graph->add(transparent);
graph->connect(transparent->output("BSDF"), output->input("Surface"));
has_surface = true;
break;
}
}
if (has_surface) {
break;
}
}
}
}

View File

@ -847,8 +847,9 @@ void ShaderGraph::default_inputs(bool do_osl)
/* nodes can specify default texture coordinates, for now we give
* everything the position by default, except for the sky texture */
ShaderNode *geom = NULL;
ShaderNode *texco = NULL;
GeometryNode *geom = NULL;
TextureCoordinateNode *texco = NULL;
VectorTransformNode *normal_transform = NULL;
foreach (ShaderNode *node, nodes) {
foreach (ShaderInput *input, node->inputs) {
@ -874,6 +875,20 @@ void ShaderGraph::default_inputs(bool do_osl)
connect(texco->output("UV"), input);
}
else if (input->flags() & SocketType::LINK_TEXTURE_INCOMING) {
if (!geom) {
geom = create_node<GeometryNode>();
}
if (!normal_transform) {
normal_transform = create_node<VectorTransformNode>();
normal_transform->set_transform_type(NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
normal_transform->set_convert_from(NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
normal_transform->set_convert_to(NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
connect(geom->output("Incoming"), normal_transform->input("Vector"));
}
connect(normal_transform->output("Vector"), input);
}
else if (input->flags() & SocketType::LINK_INCOMING) {
if (!geom) {
geom = create_node<GeometryNode>();
@ -912,6 +927,9 @@ void ShaderGraph::default_inputs(bool do_osl)
if (texco) {
add(texco);
}
if (normal_transform) {
add(normal_transform);
}
}
void ShaderGraph::refine_bump_nodes()

View File

@ -1336,7 +1336,7 @@ NODE_DEFINE(IESLightNode)
SOCKET_STRING(filename, "File Name", ustring());
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_NORMAL);
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_INCOMING);
SOCKET_OUT_FLOAT(fac, "Fac");

View File

@ -859,6 +859,11 @@ class PrincipledHairBsdfNode : public BsdfBaseNode {
NODE_SOCKET_API(NodePrincipledHairParametrization, parametrization)
/* Selected scattering model (near-/far-field). */
NODE_SOCKET_API(NodePrincipledHairModel, model)
virtual int get_feature()
{
return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_PRINCIPLED_HAIR;
}
};
class HairBsdfNode : public BsdfNode {

View File

@ -52,18 +52,6 @@
/* Logging, use `ghost.wl.*` prefix. */
#include "CLG_log.h"
/**
* NOTE(@ideasman42): Workaround a bug with fractional scaling with LIBDECOR.
* When fractional scaling is used the GHOST window uses a buffer-scale of 1
* with the actual scale compensated for by a #wp_viewport.
*
* This causes various glitches between the GHOST window and LIBDECOR.
* While this hack doesn't resolve all of them it does fix the problem where a new windows
* decorations don't match the window, sometimes causing a delayed decrease in the windows size.
* See #109194 for related issues.
*/
#define USE_LIBDECOR_FRACTIONAL_SCALE_HACK
static const xdg_activation_token_v1_listener *xdg_activation_listener_get();
static constexpr size_t base_dpi = 96;
@ -77,6 +65,12 @@ static constexpr size_t base_dpi = 96;
struct WGL_LibDecor_Window {
libdecor_frame *frame = nullptr;
/**
* Used at startup to set the initial window size
* (before fractional scale information is available).
*/
int scale_fractional_from_output = 0;
/** The window has been configured (see #xdg_surface_ack_configure). */
bool initial_configure_seen = false;
};
@ -119,6 +113,25 @@ static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
delete decor;
}
/* -------------------------------------------------------------------- */
/** \name Rounding Utilities
* \{ */
static void gwl_round_int_by(int *value_p, const int round_value)
{
GHOST_ASSERT(round_value > 0, "Invalid rounding value!");
*value_p = (*value_p / round_value) * round_value;
}
static void gwl_round_int2_by(int value_p[2], const int round_value)
{
GHOST_ASSERT(round_value > 0, "Invalid rounding value!");
value_p[0] = (value_p[0] / round_value) * round_value;
value_p[1] = (value_p[1] / round_value) * round_value;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Window-Viewport/Wayland to/from Scale Conversion
* \{ */
@ -531,20 +544,6 @@ static bool gwl_window_viewport_set(GWL_Window *win,
else {
wl_surface_commit(win->wl.surface);
}
#if defined(WITH_GHOST_WAYLAND_LIBDECOR) && defined(USE_LIBDECOR_FRACTIONAL_SCALE_HACK)
/* NOTE(@ideasman42): it's important this only runs when enabling the viewport
* since there is a bug with LIBDECOR not supporting the switch from non-fractional
* to fractional scaled surfaces. */
if (use_libdecor) {
WGL_LibDecor_Window &decor = *win->libdecor;
libdecor_state *state = libdecor_state_new(
gwl_window_fractional_from_viewport_round(win->frame, win->frame.size[0]),
gwl_window_fractional_from_viewport_round(win->frame, win->frame.size[1]));
libdecor_frame_commit(decor.frame, state, nullptr);
libdecor_state_free(state);
}
#endif
}
return true;
@ -1150,25 +1149,65 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
GWL_WindowFrame *frame_pending = &static_cast<GWL_Window *>(data)->frame_pending;
/* Set the size. */
int size_next[2];
int size_decor[2]{
libdecor_frame_get_content_width(frame),
libdecor_frame_get_content_height(frame),
};
int size_next[2] = {0, 0};
bool has_size = false;
{
GWL_Window *win = static_cast<GWL_Window *>(data);
const int scale = win->frame.buffer_scale;
if (!libdecor_configuration_get_content_size(
const int fractional_scale = win->frame.fractional_scale ?
win->frame.fractional_scale :
win->libdecor->scale_fractional_from_output;
/* The size from LIBDECOR wont use the GHOST windows buffer size.
* so it's important to calculate the buffer size that would have been used
* if fractional scaling wasn't supported. */
const int scale = fractional_scale ? (fractional_scale / FRACTIONAL_DENOMINATOR) + 1 :
win->frame.buffer_scale;
const int scale_as_fractional = scale * FRACTIONAL_DENOMINATOR;
if (libdecor_configuration_get_content_size(
configuration, frame, &size_next[0], &size_next[1])) {
size_next[0] = win->frame.size[0] / scale;
size_next[1] = win->frame.size[1] / scale;
}
if (win->frame.fractional_scale) {
win->frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[0]);
win->frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[1]);
}
else if (fractional_scale && (fractional_scale != (scale * FRACTIONAL_DENOMINATOR))) {
/* The windows `preferred_scale` is not yet available,
* set the size as if fractional scale is available. */
frame_pending->size[0] = ((size_next[0] * scale) * fractional_scale) / scale_as_fractional;
frame_pending->size[1] = ((size_next[1] * scale) * fractional_scale) / scale_as_fractional;
}
else {
frame_pending->size[0] = size_next[0] * scale;
frame_pending->size[1] = size_next[1] * scale;
}
if (win->frame.fractional_scale) {
win->frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[0]);
win->frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[1]);
/* Account for buffer rounding requirement, once fractional scaling is enabled
* the buffer scale will be 1, rounding is a requirement until then. */
gwl_round_int2_by(frame_pending->size, win->frame.buffer_scale);
has_size = true;
}
else {
frame_pending->size[0] = size_next[0] * scale;
frame_pending->size[1] = size_next[1] * scale;
/* The window decorations may be zero on startup. */
if (UNLIKELY(size_decor[0] == 0 || size_decor[1] == 0)) {
if (fractional_scale != 0 && (scale_as_fractional != fractional_scale)) {
/* Invert the fractional part: (1.25 -> 1.75), (2.75 -> 2.25), (1.5 -> 1.5).
* Needed to properly set the initial window size. */
const int scale_fractional_part_inv = scale_as_fractional -
(FRACTIONAL_DENOMINATOR -
(scale_as_fractional - fractional_scale));
size_decor[0] = ((win->frame.size[0] / scale_as_fractional) * scale_fractional_part_inv);
size_decor[1] = ((win->frame.size[1] / scale_as_fractional) * scale_fractional_part_inv);
}
else {
size_decor[0] = win->frame.size[0] / scale;
size_decor[1] = win->frame.size[1] / scale;
}
}
}
# ifdef USE_EVENT_BACKGROUND_THREAD
@ -1177,8 +1216,7 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
* (which uses a deferred update) and the window get noticeably out of sync.
* Rely on the new `frame_pending->size` to resize the window later. */
if (is_main_thread == false) {
size_next[0] = win->frame.size[0] / scale;
size_next[1] = win->frame.size[1] / scale;
has_size = false;
}
# endif
}
@ -1211,6 +1249,10 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
{
GWL_Window *win = static_cast<GWL_Window *>(data);
WGL_LibDecor_Window &decor = *win->libdecor;
if (has_size == false) {
size_next[0] = size_decor[0];
size_next[1] = size_decor[1];
}
libdecor_state *state = libdecor_state_new(UNPACK2(size_next));
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
@ -1424,10 +1466,10 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
* is detected and enabled. Unfortunately, it doesn't seem possible to receive the
* #wp_fractional_scale_v1_listener::preferred_scale information before the window is created
* So leave the buffer scaled up because there is no *guarantee* the fractional scaling support
* will run which could result in an incorrect buffer scale.
* Leaving the buffer scale is necessary for #USE_LIBDECOR_FRACTIONAL_SCALE_HACK to work too. */
* will run which could result in an incorrect buffer scale. */
int scale_fractional_from_output;
window_->frame.buffer_scale = outputs_uniform_scale_or_default(
system_->outputs_get(), 1, nullptr);
system_->outputs_get(), 1, &scale_fractional_from_output);
window_->frame_pending.buffer_scale = window_->frame.buffer_scale;
window_->frame.size[0] = int32_t(width);
@ -1435,10 +1477,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
/* The window surface must be rounded to the scale,
* failing to do so causes the WAYLAND-server to close the window immediately. */
window_->frame.size[0] = (window_->frame.size[0] / window_->frame.buffer_scale) *
window_->frame.buffer_scale;
window_->frame.size[1] = (window_->frame.size[1] / window_->frame.buffer_scale) *
window_->frame.buffer_scale;
gwl_round_int2_by(window_->frame.size, window_->frame.buffer_scale);
window_->is_dialog = is_dialog;
@ -1539,12 +1578,16 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
/* Causes a glitch with `libdecor` for some reason. */
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
WGL_LibDecor_Window &decor = *window_->libdecor;
if (fractional_scale_manager) {
decor.scale_fractional_from_output = scale_fractional_from_output;
}
/* Additional round-trip is needed to ensure `xdg_toplevel` is set. */
wl_display_roundtrip(system_->wl_display_get());
/* NOTE: LIBDECOR requires the window to be created & configured before the state can be set.
* Workaround this by using the underlying `xdg_toplevel` */
WGL_LibDecor_Window &decor = *window_->libdecor;
while (!decor.initial_configure_seen) {
wl_display_flush(system->wl_display_get());
wl_display_dispatch(system->wl_display_get());
@ -1709,8 +1752,11 @@ GHOST_TSuccess GHOST_WindowWayland::setClientSize(const uint32_t width, const ui
std::lock_guard lock_frame_guard{window_->frame_pending_mutex};
#endif
window_->frame_pending.size[0] = width;
window_->frame_pending.size[1] = height;
GWL_WindowFrame &frame_pending = window_->frame_pending;
frame_pending.size[0] = width;
frame_pending.size[1] = height;
gwl_round_int2_by(frame_pending.size, frame_pending.buffer_scale);
gwl_window_frame_pending_size_set(window_, nullptr, nullptr, nullptr);
@ -2219,9 +2265,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
window_->frame_pending.size[i] = (value * scale_next) / scale_prev;
}
if (window_->frame_pending.buffer_scale > 1) {
window_->frame_pending.size[i] = (window_->frame_pending.size[i] /
window_->frame_pending.buffer_scale) *
window_->frame_pending.buffer_scale;
gwl_round_int_by(&window_->frame_pending.size[i], window_->frame_pending.buffer_scale);
}
}

View File

@ -21,6 +21,8 @@ WAYLAND_DYNLOAD_FN(libdecor_configuration_get_window_state)
WAYLAND_DYNLOAD_FN(libdecor_decorate)
WAYLAND_DYNLOAD_FN(libdecor_dispatch)
WAYLAND_DYNLOAD_FN(libdecor_frame_commit)
WAYLAND_DYNLOAD_FN(libdecor_frame_get_content_height)
WAYLAND_DYNLOAD_FN(libdecor_frame_get_content_width)
WAYLAND_DYNLOAD_FN(libdecor_frame_get_xdg_toplevel)
WAYLAND_DYNLOAD_FN(libdecor_frame_map)
WAYLAND_DYNLOAD_FN(libdecor_frame_set_app_id)
@ -76,6 +78,8 @@ struct WaylandDynload_Libdecor {
void WL_DYN_FN(libdecor_frame_commit)(struct libdecor_frame *frame,
struct libdecor_state *state,
struct libdecor_configuration *configuration);
int WL_DYN_FN(libdecor_frame_get_content_width)(struct libdecor_frame *frame);
int WL_DYN_FN(libdecor_frame_get_content_height)(struct libdecor_frame *frame);
struct xdg_toplevel *WL_DYN_FN(libdecor_frame_get_xdg_toplevel)(struct libdecor_frame *frame);
void WL_DYN_FN(libdecor_frame_map)(struct libdecor_frame *frame);
void WL_DYN_FN(libdecor_frame_set_app_id)(struct libdecor_frame *frame, const char *app_id);
@ -112,6 +116,10 @@ struct WaylandDynload_Libdecor {
# define libdecor_dispatch(...) (*wayland_dynload_libdecor.libdecor_dispatch)(__VA_ARGS__)
# define libdecor_frame_commit(...) \
(*wayland_dynload_libdecor.libdecor_frame_commit)(__VA_ARGS__)
# define libdecor_frame_get_content_height(...) \
(*wayland_dynload_libdecor.libdecor_frame_get_content_height)(__VA_ARGS__)
# define libdecor_frame_get_content_width(...) \
(*wayland_dynload_libdecor.libdecor_frame_get_content_width)(__VA_ARGS__)
# define libdecor_frame_get_xdg_toplevel(...) \
(*wayland_dynload_libdecor.libdecor_frame_get_xdg_toplevel)(__VA_ARGS__)
# define libdecor_frame_map(...) (*wayland_dynload_libdecor.libdecor_frame_map)(__VA_ARGS__)

View File

@ -217,6 +217,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY_OPERATIONS(Menu):
layout.separator()
node_add_menu.add_node_type(layout, "GeometryNodeSeparateComponents")
node_add_menu.add_node_type(layout, "GeometryNodeSeparateGeometry")
node_add_menu.add_node_type(layout, "GeometryNodeSplitToInstances")
node_add_menu.draw_assets_for_catalog(layout, "Geometry/Operations")

View File

@ -554,7 +554,10 @@ class GreasePencilMaterialsPanel:
icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
row.prop(slot, "link", icon=icon_link, icon_only=True)
if not is_grease_pencil_version3 and ob.data.use_stroke_edit_mode:
if is_grease_pencil_version3 and ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("grease_pencil.stroke_change_color", text="Assign")
elif not is_grease_pencil_version3 and ob.data.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.stroke_change_color", text="Assign")
row.operator("gpencil.material_select", text="Select").deselect = False

View File

@ -270,7 +270,7 @@ class EEVEE_NEXT_MATERIAL_PT_settings(MaterialButtonsPanel, Panel):
row.prop(mat, "alpha_threshold")
if mat.blend_method not in {'OPAQUE', 'CLIP', 'HASHED'}:
col.prop(mat, "show_transparent_back", text="Transparency")
layout.prop(mat, "show_transparent_back")
layout.prop(mat, "use_screen_refraction")
layout.prop(mat, "pass_index")

View File

@ -1902,6 +1902,10 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.operator("mesh.select_axis", text="Side of Active")
layout.operator("mesh.select_mirror")
layout.separator()
layout.operator("mesh.select_by_attribute", text="By Attribute")
layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label)
@ -5823,6 +5827,7 @@ class VIEW3D_MT_edit_curves(Menu):
layout.menu("VIEW3D_MT_transform")
layout.separator()
layout.operator("curves.attribute_set")
layout.operator("curves.delete")
layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label)

View File

@ -50,7 +50,6 @@ int insert_keyframe(Main *bmain,
int array_index,
const AnimationEvalContext *anim_eval_context,
eBezTriple_KeyframeType keytype,
ListBase *nla_cache,
eInsertKeyFlags flag);
/**

View File

@ -616,7 +616,6 @@ int insert_keyframe(Main *bmain,
int array_index,
const AnimationEvalContext *anim_eval_context,
eBezTriple_KeyframeType keytype,
ListBase *nla_cache,
eInsertKeyFlags flag)
{
/* validate pointer first - exit if failure */
@ -661,10 +660,10 @@ int insert_keyframe(Main *bmain,
/* apply NLA-mapping to frame to use (if applicable) */
NlaKeyframingContext *nla_context = nullptr;
ListBase tmp_nla_cache = {nullptr, nullptr};
ListBase nla_cache = {nullptr, nullptr};
AnimData *adt = BKE_animdata_from_id(id);
const AnimationEvalContext remapped_context = nla_time_remap(
anim_eval_context, &id_ptr, adt, act, nla_cache ? nla_cache : &tmp_nla_cache, &nla_context);
anim_eval_context, &id_ptr, adt, act, &nla_cache, &nla_context);
/* Obtain values to insert. */
float value_buffer[RNA_MAX_ARRAY_LENGTH];
@ -788,7 +787,7 @@ int insert_keyframe(Main *bmain,
}
MEM_freeN(successful_remaps);
BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache);
BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
if (key_count > 0) {
if (act != nullptr) {

View File

@ -128,7 +128,6 @@ void autokeyframe_object(
/* only key on available channels */
if (adt && adt->action) {
ListBase nla_cache = {nullptr, nullptr};
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
insert_keyframe(bmain,
reports,
@ -139,11 +138,8 @@ void autokeyframe_object(
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
&nla_cache,
flag);
}
BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
}
}
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) {
@ -333,7 +329,6 @@ bool autokeyframe_property(bContext *C,
rnaindex,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
nullptr,
flag) != 0;
if (path) {
MEM_freeN(path);

View File

@ -122,7 +122,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(eAssetLibraryType l
std::string normalized_root_path = utils::normalize_directory_path(root_path);
std::unique_ptr<AssetLibrary> *lib_uptr_ptr = on_disk_libraries_.lookup_ptr(
normalized_root_path);
{library_type, normalized_root_path});
if (lib_uptr_ptr != nullptr) {
CLOG_INFO(&LOG, 2, "get \"%s\" (cached)", normalized_root_path.c_str());
AssetLibrary *lib = lib_uptr_ptr->get();
@ -139,7 +139,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(eAssetLibraryType l
/* Reload catalogs on refresh. */
lib->on_refresh_ = [](AssetLibrary &self) { self.catalog_service->reload_catalogs(); };
on_disk_libraries_.add_new(normalized_root_path, std::move(lib_uptr));
on_disk_libraries_.add_new({library_type, normalized_root_path}, std::move(lib_uptr));
CLOG_INFO(&LOG, 2, "get \"%s\" (loaded)", normalized_root_path.c_str());
return lib;
}

View File

@ -9,6 +9,7 @@
#pragma once
#include <optional>
#include <utility>
#include "AS_asset_library.hh"
@ -38,9 +39,12 @@ namespace blender::asset_system {
class AssetLibraryService {
static std::unique_ptr<AssetLibraryService> instance_;
/* Mapping absolute path of the library's root path (normalize with #normalize_directory_path()!)
* the AssetLibrary instance. */
Map<std::string, std::unique_ptr<AssetLibrary>> on_disk_libraries_;
/** Identify libraries with the library type, and the absolute path of the library's root path
* (normalize with #normalize_directory_path()!). The type is relevant since the current file
* library may point to the same path as a custom library. */
using OnDiskLibraryIdentifier = std::pair<eAssetLibraryType, std::string>;
/* Mapping of a (type, root path) pair to the AssetLibrary instance. */
Map<OnDiskLibraryIdentifier, std::unique_ptr<AssetLibrary>> on_disk_libraries_;
/** Library without a known path, i.e. the "Current File" library if the file isn't saved yet. If
* the file was saved, a valid path for the library can be determined and #on_disk_libraries_
* above should be used. */

View File

@ -113,8 +113,6 @@ TEST_F(AssetLibraryServiceTest, library_from_reference)
{
AssetLibraryService *service = AssetLibraryService::get();
AssetLibrary *const lib = service->get_asset_library_on_disk_custom(__func__,
asset_library_root_);
AssetLibrary *const curfile_lib = service->get_asset_library_current_file();
AssetLibraryReference ref{};
@ -123,12 +121,24 @@ TEST_F(AssetLibraryServiceTest, library_from_reference)
<< "Getting the local (current file) reference without a main saved on disk should return "
"the current file library";
Main dummy_main{};
std::string dummy_filepath = asset_library_root_ + SEP + "dummy.blend";
STRNCPY(dummy_main.filepath, dummy_filepath.c_str());
EXPECT_EQ(lib, service->get_asset_library(&dummy_main, ref))
<< "Getting the local (current file) reference with a main saved on disk should return "
"the an asset library for this directory";
{
Main dummy_main{};
std::string dummy_filepath = asset_library_root_ + SEP + "dummy.blend";
STRNCPY(dummy_main.filepath, dummy_filepath.c_str());
AssetLibrary *custom_lib = service->get_asset_library_on_disk_custom(__func__,
asset_library_root_);
AssetLibrary *tmp_curfile_lib = service->get_asset_library(&dummy_main, ref);
/* Requested a current file library with a (fake) file saved in the same directory as a custom
* asset library. The resulting library should never match the custom asset library, even
* though the paths match. */
EXPECT_NE(custom_lib, tmp_curfile_lib)
<< "Getting an asset library from a local (current file) library reference should never "
"match any custom asset library";
EXPECT_EQ(custom_lib->root_path(), tmp_curfile_lib->root_path());
}
}
TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes)

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 0
#define BLENDER_FILE_SUBVERSION 1
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -75,6 +75,19 @@ class PointCloudFieldContext : public fn::FieldContext {
}
};
class GreasePencilFieldContext : public fn::FieldContext {
private:
const GreasePencil &grease_pencil_;
public:
GreasePencilFieldContext(const GreasePencil &grease_pencil) : grease_pencil_(grease_pencil) {}
const GreasePencil &grease_pencil() const
{
return grease_pencil_;
}
};
class GreasePencilLayerFieldContext : public fn::FieldContext {
private:
const GreasePencil &grease_pencil_;
@ -153,6 +166,7 @@ class GeometryFieldContext : public fn::FieldContext {
int grease_pencil_layer_index);
GeometryFieldContext(const Mesh &mesh, eAttrDomain domain);
GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain);
GeometryFieldContext(const GreasePencil &grease_pencil);
GeometryFieldContext(const GreasePencil &grease_pencil, eAttrDomain domain, int layer_index);
GeometryFieldContext(const PointCloud &points);
GeometryFieldContext(const Instances &instances);

View File

@ -110,6 +110,24 @@ class Drawing : public ::GreasePencilDrawing {
bool has_users() const;
};
class DrawingReference : public ::GreasePencilDrawingReference {
public:
DrawingReference();
DrawingReference(const DrawingReference &other);
~DrawingReference();
};
const Drawing *get_eval_grease_pencil_layer_drawing(const GreasePencil &grease_pencil,
int layer_index);
Drawing *get_eval_grease_pencil_layer_drawing_for_write(GreasePencil &grease_pencil,
int layer_index);
/**
* Copies the drawings from one array to another. Assumes that \a dst_drawings is allocated but not
* initialized, e.g. it will allocate new drawings and store the pointers.
*/
void copy_drawing_array(Span<const GreasePencilDrawingBase *> src_drawings,
MutableSpan<GreasePencilDrawingBase *> dst_drawings);
class LayerGroup;
class Layer;
@ -503,6 +521,7 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
* Adds a new layer named \a name at the end of this group and returns it.
*/
Layer &add_layer(StringRefNull name);
Layer &add_layer(const Layer &duplicate_layer);
/**
* Adds a new group named \a name at the end of this group and returns it.
*/
@ -645,11 +664,6 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
void legacy_gpencil_to_grease_pencil(Main &main, GreasePencil &grease_pencil, bGPdata &gpd);
} // namespace convert
const Drawing *get_eval_grease_pencil_layer_drawing(const GreasePencil &grease_pencil,
int layer_index);
Drawing *get_eval_grease_pencil_layer_drawing_for_write(GreasePencil &grease_pencil,
int layer_index);
} // namespace greasepencil
class GreasePencilRuntime {
@ -704,6 +718,16 @@ inline const blender::bke::greasepencil::Drawing &GreasePencilDrawing::wrap() co
return *reinterpret_cast<const blender::bke::greasepencil::Drawing *>(this);
}
inline blender::bke::greasepencil::DrawingReference &GreasePencilDrawingReference::wrap()
{
return *reinterpret_cast<blender::bke::greasepencil::DrawingReference *>(this);
}
inline const blender::bke::greasepencil::DrawingReference &GreasePencilDrawingReference::wrap()
const
{
return *reinterpret_cast<const blender::bke::greasepencil::DrawingReference *>(this);
}
inline GreasePencilFrame GreasePencilFrame::null()
{
return GreasePencilFrame{-1, 0, 0};
@ -779,6 +803,8 @@ GreasePencil *BKE_grease_pencil_new_nomain();
GreasePencil *BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src);
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob);
void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *object);
void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src,
GreasePencil *grease_pencil_dst);
int BKE_grease_pencil_object_material_index_get(Object *ob, Material *ma);
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name);

View File

@ -63,6 +63,7 @@ class InstanceReference {
InstanceReference(Object &object);
InstanceReference(Collection &collection);
InstanceReference(GeometrySet geometry_set);
InstanceReference(std::unique_ptr<GeometrySet> geometry_set);
InstanceReference(const InstanceReference &other);