Cycles: new Microfacet-based Hair BSDF with elliptical cross-section support #105600

Merged
Weizhen Huang merged 114 commits from weizhen/blender:microfacet_hair into main 2023-08-18 12:46:20 +02:00
706 changed files with 18357 additions and 9976 deletions
Showing only changes of commit 08684b2601 - Show all commits

View File

@ -22,6 +22,14 @@ elseif(UNIX AND NOT APPLE)
)
endif()
# Boolean crashes with Arm assembly, see T103423.
if(BLENDER_PLATFORM_ARM)
set(GMP_OPTIONS
${GMP_OPTIONS}
--disable-assembly
)
endif()
ExternalProject_Add(external_gmp
URL file://${PACKAGE_DIR}/${GMP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}

View File

@ -83,7 +83,7 @@ enum_use_layer_samples = (
enum_sampling_pattern = (
('SOBOL_BURLEY', "Sobol-Burley", "Use on-the-fly computed Owen-scrambled Sobol for random sampling", 0),
('TABULATED_SOBOL', "Tabulated Sobol", "Use precomputed tables of Owen-scrambled Sobol for random sampling", 1),
('TABULATED_SOBOL', "Tabulated Sobol", "Use pre-computed tables of Owen-scrambled Sobol for random sampling", 1),
)
enum_emission_sampling = (
@ -905,7 +905,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
use_fast_gi: BoolProperty(
name="Fast GI Approximation",
description="Approximate diffuse indirect light with background tinted ambient occlusion. This provides fast alternative to full global illumination, for interactive viewport rendering or final renders with reduced quality",
description="Approximate diffuse indirect light with background tinted ambient occlusion. "
"This provides fast alternative to full global illumination, for interactive viewport rendering or final renders with reduced quality",
default=False,
)
@ -1539,13 +1540,16 @@ class CyclesPreferences(bpy.types.AddonPreferences):
use_metalrt: BoolProperty(
name="MetalRT (Experimental)",
description="MetalRT for ray tracing uses less memory for scenes which use curves extensively, and can give better performance in specific cases. However this support is experimental and some scenes may render incorrectly",
description="MetalRT for ray tracing uses less memory for scenes which use curves extensively, and can give better "
"performance in specific cases. However this support is experimental and some scenes may render incorrectly",
default=False,
)
kernel_optimization_level: EnumProperty(
name="Kernel Optimization",
description="Kernels can be optimized based on scene content. Optimized kernels are requested at the start of a render. If optimized kernels are not available, rendering will proceed using generic kernels until the optimized set is available in the cache. This can result in additional CPU usage for a brief time (tens of seconds).",
description="Kernels can be optimized based on scene content. Optimized kernels are requested at the start of a render. "
"If optimized kernels are not available, rendering will proceed using generic kernels until the optimized set "
"is available in the cache. This can result in additional CPU usage for a brief time (tens of seconds)",
default='FULL',
items=(
('OFF', "Off", "Disable kernel optimization. Slowest rendering, no extra background CPU usage"),

View File

@ -679,7 +679,7 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
if (num_verts == 0) {
return;
}
const MVert *verts = static_cast<const MVert *>(b_mesh.vertices[0].ptr.data);
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data);
/* STEP 1: Find out duplicated vertices and point duplicates to a single
* original vertex.
@ -765,10 +765,8 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
continue;
}
visited_edges.insert(v0, v1);
const MVert &b_vert_0 = verts[v0];
const MVert &b_vert_1 = verts[v1];
float3 co0 = make_float3(b_vert_0.co[0], b_vert_0.co[1], b_vert_0.co[2]);
float3 co1 = make_float3(b_vert_1.co[0], b_vert_1.co[1], b_vert_1.co[2]);
float3 co0 = make_float3(positions[v0][0], positions[v0][1], positions[v0][2]);
float3 co1 = make_float3(positions[v1][0], positions[v1][1], positions[v1][2]);
float3 edge = normalize(co1 - co0);
edge_accum[v0] += edge;
edge_accum[v1] += -edge;
@ -919,7 +917,7 @@ static void create_mesh(Scene *scene,
return;
}
const MVert *verts = static_cast<const MVert *>(b_mesh.vertices[0].ptr.data);
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data);
if (!subdivision) {
numtris = numfaces;
@ -942,8 +940,7 @@ static void create_mesh(Scene *scene,
/* create vertex coordinates and normals */
for (int i = 0; i < numverts; i++) {
const MVert &b_vert = verts[i];
mesh->add_vertex(make_float3(b_vert.co[0], b_vert.co[1], b_vert.co[2]));
mesh->add_vertex(make_float3(positions[i][0], positions[i][1], positions[i][2]));
}
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
@ -1252,14 +1249,13 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
float3 *mP = attr_mP->data_float3() + motion_step * numverts;
float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL;
const MVert *verts = static_cast<const MVert *>(b_mesh.vertices[0].ptr.data);
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data);
/* NOTE: We don't copy more that existing amount of vertices to prevent
* possible memory corruption.
*/
for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) {
const MVert &b_vert = verts[i];
mP[i] = make_float3(b_vert.co[0], b_vert.co[1], b_vert.co[2]);
mP[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
}
if (mN) {
const float(*b_vert_normals)[3] = static_cast<const float(*)[3]>(

View File

@ -377,7 +377,8 @@ bool MetalDevice::load_kernels(const uint _kernel_features)
/* Only request generic kernels if they aren't cached in memory. */
if (make_source_and_check_if_compile_needed(PSO_GENERIC)) {
/* If needed, load them asynchronously in order to responsively message progress to the user. */
/* If needed, load them asynchronously in order to responsively message progress to the user.
*/
int this_device_id = this->device_id;
auto compile_kernels_fn = ^() {
compile_and_load(this_device_id, PSO_GENERIC);

View File

@ -58,7 +58,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts);
/* Compute face normal. */
float3 Ng;
if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
if (object_negative_scale_applied(sd->object_flag)) {
Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0]));
}
else {

View File

@ -201,6 +201,11 @@ ccl_device_inline void object_normal_transform(KernelGlobals kg,
*N = normalize(transform_direction_transposed(&tfm, *N));
}
ccl_device_inline bool object_negative_scale_applied(const int object_flag)
{
return ((object_flag & SD_OBJECT_NEGATIVE_SCALE) && (object_flag & SD_OBJECT_TRANSFORM_APPLIED));
}
/* Transform direction vector from object to world space */
ccl_device_inline void object_dir_transform(KernelGlobals kg,

View File

@ -21,7 +21,7 @@ ccl_device_inline float3 triangle_normal(KernelGlobals kg, ccl_private ShaderDat
const float3 v2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
/* return normal */
if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
if (object_negative_scale_applied(sd->object_flag)) {
return normalize(cross(v2 - v0, v1 - v0));
}
else {
@ -50,7 +50,7 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg,
/* get object flags */
int object_flag = kernel_data_fetch(object_flag, object);
/* compute normal */
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
if (object_negative_scale_applied(object_flag)) {
*Ng = normalize(cross(v2 - v0, v1 - v0));
}
else {

View File

@ -176,8 +176,9 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
/* Geometric normal. */
vtx->ng = normalize(cross(dp_du, dp_dv));
if (sd_vtx->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED)
if (sd_vtx->object_flag & SD_OBJECT_NEGATIVE_SCALE) {
vtx->ng = -vtx->ng;
}
/* Shading normals: Interpolate normals between vertices. */
float n_len;

View File

@ -502,8 +502,15 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
rng_state,
ccl_global float *ccl_restrict render_buffer)
{
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
if (!(kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) &&
!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_CAMERA)) {
!(path_flag & PATH_RAY_CAMERA)) {
return;
}
/* Skip AO for paths that were split off for shadow catchers to avoid double-counting. */
if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
return;
}

View File

@ -979,8 +979,10 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput_phase;
if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
INTEGRATOR_STATE_WRITE(state, path, pass_diffuse_weight) = one_spectrum();
INTEGRATOR_STATE_WRITE(state, path, pass_glossy_weight) = zero_spectrum();
if (INTEGRATOR_STATE(state, path, bounce) == 0) {
INTEGRATOR_STATE_WRITE(state, path, pass_diffuse_weight) = one_spectrum();
INTEGRATOR_STATE_WRITE(state, path, pass_glossy_weight) = zero_spectrum();
}
}
/* Update path state */

View File

@ -120,7 +120,7 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
if (path_flag & PATH_RAY_SUBSURFACE_BACKFACING) {
hit_Ng = -hit_Ng;
}
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
if (object_negative_scale_applied(object_flag)) {
hit_Ng = -hit_Ng;
}

View File

@ -223,11 +223,16 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
triangle_world_space_vertices(kg, object, prim_id, -1.0f, vertices);
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
if (kemitter->emission_sampling == EMISSION_SAMPLING_FRONT) {
const bool is_front_only = (kemitter->emission_sampling == EMISSION_SAMPLING_FRONT);
const bool is_back_only = (kemitter->emission_sampling == EMISSION_SAMPLING_BACK);
if (is_front_only || is_back_only) {
dir = safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0]));
}
else if (kemitter->emission_sampling == EMISSION_SAMPLING_BACK) {
dir = -safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0]));
if (is_back_only) {
dir = -dir;
}
if (kernel_data_fetch(object_flag, object) & SD_OBJECT_NEGATIVE_SCALE) {
dir = -dir;
}
}
else {
/* Double-sided: any vector in the plane. */

View File

@ -146,7 +146,7 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
/* flip normal if necessary */
const int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
if (object_flag & SD_OBJECT_NEGATIVE_SCALE) {
ls->Ng = -ls->Ng;
}
ls->eval_fac = 1.0f;

View File

@ -122,6 +122,7 @@ shader node_image_texture(int use_mapping = 0,
vector Nob = transform("world", "object", N);
/* project from direction vector to barycentric coordinates in triangles */
vector signed_Nob = Nob;
Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2]));
Nob /= (Nob[0] + Nob[1] + Nob[2]);
@ -184,9 +185,10 @@ shader node_image_texture(int use_mapping = 0,
float tmp_alpha;
if (weight[0] > 0.0) {
point UV = point((signed_Nob[0] < 0.0) ? 1.0 - p[1] : p[1], p[2], 0.0);
Color += weight[0] * image_texture_lookup(filename,
p[1],
p[2],
UV[0],
UV[1],
tmp_alpha,
compress_as_srgb,
ignore_alpha,
@ -198,9 +200,10 @@ shader node_image_texture(int use_mapping = 0,
Alpha += weight[0] * tmp_alpha;
}
if (weight[1] > 0.0) {
point UV = point((signed_Nob[1] > 0.0) ? 1.0 - p[0] : p[0], p[2], 0.0);
Color += weight[1] * image_texture_lookup(filename,
p[0],
p[2],
UV[0],
UV[1],
tmp_alpha,
compress_as_srgb,
ignore_alpha,
@ -212,9 +215,10 @@ shader node_image_texture(int use_mapping = 0,
Alpha += weight[1] * tmp_alpha;
}
if (weight[2] > 0.0) {
point UV = point((signed_Nob[2] > 0.0) ? 1.0 - p[1] : p[1], p[0], 0.0);
Color += weight[2] * image_texture_lookup(filename,
p[1],
p[0],
UV[0],
UV[1],
tmp_alpha,
compress_as_srgb,
ignore_alpha,

View File

@ -224,7 +224,7 @@ ccl_device float3 svm_bevel(
float3 hit_Ng = isect.Ng[hit];
int object = isect.hits[hit].object;
int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
if (object_negative_scale_applied(object_flag)) {
hit_Ng = -hit_Ng;
}

View File

@ -850,8 +850,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_MOTION = (1 << 1),
/* Vertices have transform applied. */
SD_OBJECT_TRANSFORM_APPLIED = (1 << 2),
/* Vertices have negative scale applied. */
SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3),
/* The object's transform applies a negative scale. */
SD_OBJECT_NEGATIVE_SCALE = (1 << 3),
/* Object has a volume shader. */
SD_OBJECT_HAS_VOLUME = (1 << 4),
/* Object intersects AABB of an object with volume shader. */
@ -873,7 +873,7 @@ enum ShaderDataObjectFlag {
SD_OBJECT_CAUSTICS = (SD_OBJECT_CAUSTICS_CASTER | SD_OBJECT_CAUSTICS_RECEIVER),
SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | SD_OBJECT_MOTION | SD_OBJECT_TRANSFORM_APPLIED |
SD_OBJECT_NEGATIVE_SCALE_APPLIED | SD_OBJECT_HAS_VOLUME |
SD_OBJECT_NEGATIVE_SCALE | SD_OBJECT_HAS_VOLUME |
SD_OBJECT_INTERSECTS_VOLUME | SD_OBJECT_SHADOW_CATCHER |
SD_OBJECT_HAS_VOLUME_ATTRIBUTES | SD_OBJECT_CAUSTICS |
SD_OBJECT_HAS_VOLUME_MOTION)

View File

@ -32,7 +32,7 @@ static float shutter_curve_eval(float x, array<float> &shutter_curve)
return 1.0f;
}
x *= shutter_curve.size();
x = saturatef(x) * shutter_curve.size() - 1;
int index = (int)x;
float frac = x - index;
if (index < shutter_curve.size() - 1) {

View File

@ -211,6 +211,11 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
if (strcmp(in->format_name(), "dds") == 0) {
do_associate_alpha = true;
}
/* Workaround OIIO bug that sets oiio:UnassociatedAlpha on the last layer
* but not composite image that we read. */
if (strcmp(in->format_name(), "psd") == 0) {
do_associate_alpha = true;
}
}
}

View File

@ -94,14 +94,17 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
* seems to work fine */
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
if (shader->emission_sampling == EMISSION_SAMPLING_FRONT) {
/* Front only. */
const bool is_front_only = (shader->emission_sampling == EMISSION_SAMPLING_FRONT);
const bool is_back_only = (shader->emission_sampling == EMISSION_SAMPLING_BACK);
if (is_front_only || is_back_only) {
/* One-sided. */
bcone.axis = safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0]));
bcone.theta_o = 0;
}
else if (shader->emission_sampling == EMISSION_SAMPLING_BACK) {
/* Back only. */
bcone.axis = -safe_normalize(cross(vertices[1] - vertices[0], vertices[2] - vertices[0]));
if (is_back_only) {
bcone.axis = -bcone.axis;
}
if (transform_negative_scale(object->get_tfm())) {
bcone.axis = -bcone.axis;
}
bcone.theta_o = 0;
}
else {

View File

@ -435,6 +435,10 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
state->have_motion = true;
}
if (transform_negative_scale(tfm)) {
flag |= SD_OBJECT_NEGATIVE_SCALE;
}
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::POINTCLOUD) {
/* TODO: why only mesh? */
Mesh *mesh = static_cast<Mesh *>(geom);
@ -970,8 +974,6 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P
}
object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED;
if (geom->transform_negative_scaled)
object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED;
}
}

View File

@ -289,19 +289,24 @@ RenderWork Session::run_update_for_next_iteration()
RenderWork render_work;
thread_scoped_lock scene_lock(scene->mutex);
thread_scoped_lock reset_lock(delayed_reset_.mutex);
bool have_tiles = true;
bool switched_to_new_tile = false;
bool did_reset = false;
const bool did_reset = delayed_reset_.do_reset;
if (delayed_reset_.do_reset) {
thread_scoped_lock buffers_lock(buffers_mutex_);
do_delayed_reset();
/* Perform delayed reset if requested. */
{
thread_scoped_lock reset_lock(delayed_reset_.mutex);
if (delayed_reset_.do_reset) {
did_reset = true;
/* After reset make sure the tile manager is at the first big tile. */
have_tiles = tile_manager_.next();
switched_to_new_tile = true;
thread_scoped_lock buffers_lock(buffers_mutex_);
do_delayed_reset();
/* After reset make sure the tile manager is at the first big tile. */
have_tiles = tile_manager_.next();
switched_to_new_tile = true;
}
}
/* Update number of samples in the integrator.

View File

@ -16,6 +16,9 @@ void util_cdf_invert(const int resolution,
const bool make_symmetric,
vector<float> &inv_cdf)
{
const int cdf_size = cdf.size();
assert(cdf[0] == 0.0f && cdf[cdf_size - 1] == 1.0f);
const float inv_resolution = 1.0f / (float)resolution;
const float range = to - from;
inv_cdf.resize(resolution);
@ -25,12 +28,12 @@ void util_cdf_invert(const int resolution,
float x = i / (float)half_size;
int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
float t;
if (index < cdf.size() - 1) {
if (index < cdf_size - 1) {
t = (x - cdf[index]) / (cdf[index + 1] - cdf[index]);
}
else {
t = 0.0f;
index = cdf.size() - 1;
index = cdf_size - 1;
}
float y = ((index + t) / (resolution - 1)) * (2.0f * range);
inv_cdf[half_size + i] = 0.5f * (1.0f + y);
@ -39,17 +42,17 @@ void util_cdf_invert(const int resolution,
}
else {
for (int i = 0; i < resolution; i++) {
float x = from + range * (float)i * inv_resolution;
int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
float x = (i + 0.5f) * inv_resolution;
int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin() - 1;
float t;
if (index < cdf.size() - 1) {
if (index < cdf_size - 1) {
t = (x - cdf[index]) / (cdf[index + 1] - cdf[index]);
}
else {
t = 0.0f;
index = resolution;
}
inv_cdf[i] = (index + t) * inv_resolution;
inv_cdf[i] = from + range * (index + t) * inv_resolution;
}
}
}

View File

@ -26,9 +26,11 @@ void util_cdf_evaluate(
cdf[i + 1] = cdf[i] + fabsf(y);
}
/* Normalize the CDF. */
float fac = (cdf[resolution] == 0.0f) ? 0.0f : 1.0f / cdf[resolution];
for (int i = 0; i <= resolution; i++) {
cdf[i] /= cdf[resolution];
cdf[i] *= fac;
}
cdf[resolution] = 1.0f;
}
/* Invert pre-calculated CDF function. */

View File

@ -4534,7 +4534,7 @@ static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, co
CLOG_INFO(LOG, 2, "scale");
GWL_Output *output = static_cast<GWL_Output *>(data);
output->scale = factor;
output->system->output_scale_update_maybe_leave(output, false);
output->system->output_scale_update(output);
}
static const struct wl_output_listener output_listener = {
@ -4736,7 +4736,11 @@ static void gwl_registry_wl_output_remove(GWL_Display *display,
if (!on_exit) {
/* Needed for WLROOTS, does nothing if surface leave callbacks have already run. */
output->system->output_scale_update_maybe_leave(output, true);
if (output->system->output_unref(output->wl_output)) {
CLOG_WARN(LOG,
"mis-behaving compositor failed to call \"surface_listener.leave\" "
"window scale may be invalid!");
}
}
if (output->xdg_output) {
@ -6744,11 +6748,13 @@ void GHOST_SystemWayland::seat_active_set(const struct GWL_Seat *seat)
gwl_display_seat_active_set(display_, seat);
}
void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
bool GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
{
bool changed = false;
#define SURFACE_CLEAR_PTR(surface_test) \
if (surface_test == wl_surface) { \
surface_test = nullptr; \
changed = true; \
} \
((void)0);
@ -6760,37 +6766,62 @@ void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
SURFACE_CLEAR_PTR(seat->wl_surface_window_focus_dnd);
}
#undef SURFACE_CLEAR_PTR
return changed;
}
void GHOST_SystemWayland::output_scale_update_maybe_leave(GWL_Output *output, bool leave)
bool GHOST_SystemWayland::output_unref(wl_output *wl_output)
{
/* Update scale, optionally leaving the outputs beforehand. */
GHOST_WindowManager *window_manager = output->system->getWindowManager();
bool changed = false;
if (!ghost_wl_output_own(wl_output)) {
return changed;
}
/* NOTE: keep in sync with `output_scale_update`. */
GWL_Output *output = ghost_wl_output_user_data(wl_output);
GHOST_WindowManager *window_manager = getWindowManager();
if (window_manager) {
for (GHOST_IWindow *iwin : window_manager->getWindows()) {
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
if (win->outputs_leave(output)) {
changed = true;
}
}
}
for (GWL_Seat *seat : display_->seats) {
if (seat->pointer.outputs.erase(output)) {
changed = true;
}
if (seat->tablet.outputs.erase(output)) {
changed = true;
}
}
return changed;
}
void GHOST_SystemWayland::output_scale_update(GWL_Output *output)
{
/* NOTE: keep in sync with `output_unref`. */
GHOST_WindowManager *window_manager = getWindowManager();
if (window_manager) {
for (GHOST_IWindow *iwin : window_manager->getWindows()) {
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
const std::vector<GWL_Output *> &outputs = win->outputs();
bool found = leave ? win->outputs_leave(output) :
!(std::find(outputs.begin(), outputs.end(), output) == outputs.cend());
if (found) {
if (!(std::find(outputs.begin(), outputs.end(), output) == outputs.cend())) {
win->outputs_changed_update_scale();
}
}
}
for (GWL_Seat *seat : display_->seats) {
bool found;
found = leave ? seat->pointer.outputs.erase(output) : seat->pointer.outputs.count(output);
if (found) {
if (seat->pointer.outputs.count(output)) {
if (seat->cursor.wl_surface_cursor != nullptr) {
update_cursor_scale(
seat->cursor, seat->system->wl_shm(), &seat->pointer, seat->cursor.wl_surface_cursor);
}
}
found = leave ? seat->tablet.outputs.erase(output) : seat->tablet.outputs.count(output);
if (found) {
if (seat->tablet.outputs.count(output)) {
for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));

View File

@ -194,10 +194,25 @@ class GHOST_SystemWayland : public GHOST_System {
/** Set this seat to be active. */
void seat_active_set(const struct GWL_Seat *seat);
void output_scale_update_maybe_leave(GWL_Output *output, bool leave);
/**
* Clear all references to this output.
*
* \note The compositor should have already called the `wl_surface_listener.leave` callback,
* however some compositors may not (see T103586).
* So remove references to the output before it's destroyed to avoid crashing.
*
* \return true when any references were removed.
*/
bool output_unref(struct wl_output *wl_output);
/** Clear all references to this surface to prevent accessing NULL pointers. */
void window_surface_unref(const wl_surface *wl_surface);
void output_scale_update(GWL_Output *output);
/**
* Clear all references to this surface to prevent accessing NULL pointers.
*
* \return true when any references were removed.
*/
bool window_surface_unref(const wl_surface *wl_surface);
bool window_cursor_grab_set(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,

View File

@ -797,11 +797,6 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
window_->ghost_window = this;
window_->ghost_system = system;
window_->frame.size[0] = int32_t(width);
window_->frame.size[1] = int32_t(height);
window_->is_dialog = is_dialog;
/* NOTE(@campbellbarton): The scale set here to avoid flickering on startup.
* When all monitors use the same scale (which is quite common) there aren't any problems.
*
@ -813,6 +808,16 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
* avoiding a large window flashing before it's made smaller. */
window_->scale = outputs_max_scale_or_default(system_->outputs(), 1, &window_->scale_fractional);
window_->frame.size[0] = int32_t(width);
window_->frame.size[1] = int32_t(height);
/* 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_->scale) * window_->scale;
window_->frame.size[1] = (window_->frame.size[1] / window_->scale) * window_->scale;
window_->is_dialog = is_dialog;
/* Window surfaces. */
window_->wl_surface = wl_compositor_create_surface(system_->wl_compositor());
ghost_wl_surface_tag(window_->wl_surface);

View File

@ -21,7 +21,7 @@ struct Global;
/**
* This is stored per thread. Align to cache line size to avoid false sharing.
*/
struct alignas(64) Local {
struct alignas(128) Local {
/**
* Retain shared ownership of #Global to make sure that it is not destructed.
*/

@ -1 +1 @@
Subproject commit 7084c4ecd97d93459d9d23fd90f81589b09be5df
Subproject commit 7be7aff5a18c550465b3f7634539ed4168af7c51

@ -1 +1 @@
Subproject commit a9d4443c244f89399ec4bcc427e05a07950528cc
Subproject commit c226f867affd12881533a54c8c90ac6eebfaca6c

View File

@ -412,6 +412,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"selected",
"selected and lock unselected",
"selected and unlock unselected",
"screen",
"the lazy dog",
"this legacy pose library to pose assets",
"to the top level of the tree",

View File

@ -542,6 +542,7 @@ class SpellChecker:
"voronoi",
"voxel", "voxels",
"vsync",
"vulkan",
"wireframe",
"zmask",
"ztransp",

View File

@ -1342,7 +1342,7 @@ url_manual_mapping = (
("bpy.types.armature.layers_protected*", "animation/armatures/properties/skeleton.html#bpy-types-armature-layers-protected"),
("bpy.types.assetmetadata.description*", "editors/asset_browser.html#bpy-types-assetmetadata-description"),
("bpy.types.bakesettings.normal_space*", "render/cycles/baking.html#bpy-types-bakesettings-normal-space"),
("bpy.types.brush.crease_pinch_factor*", "sculpt_paint/sculpting/tools/snake_hook.html#bpy-types-brush-crease-pinch-factor"),
("bpy.types.brush.crease_pinch_factor*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-crease-pinch-factor"),
("bpy.types.brush.elastic_deform_type*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-type"),
("bpy.types.brush.texture_sample_bias*", "sculpt_paint/brush/texture.html#bpy-types-brush-texture-sample-bias"),
("bpy.types.brush.use_cloth_collision*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-use-cloth-collision"),
@ -1468,6 +1468,7 @@ url_manual_mapping = (
("bpy.types.bakesettings.cage_object*", "render/cycles/baking.html#bpy-types-bakesettings-cage-object"),
("bpy.types.bakesettings.margin_type*", "render/cycles/baking.html#bpy-types-bakesettings-margin-type"),
("bpy.types.bone.use_relative_parent*", "animation/armatures/bones/properties/relations.html#bpy-types-bone-use-relative-parent"),
("bpy.types.brush.area_radius_factor*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-area-radius-factor"),
("bpy.types.brush.auto_smooth_factor*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-auto-smooth-factor"),
("bpy.types.brush.smooth_deform_type*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-smooth-deform-type"),
("bpy.types.brush.use_connected_only*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-use-connected-only"),
@ -1781,6 +1782,7 @@ url_manual_mapping = (
("bpy.types.functionnodefloattoint*", "modeling/geometry_nodes/utilities/float_to_integer.html#bpy-types-functionnodefloattoint"),
("bpy.types.functionnodeinputcolor*", "modeling/geometry_nodes/input/color.html#bpy-types-functionnodeinputcolor"),
("bpy.types.geometrynodeconvexhull*", "modeling/geometry_nodes/geometry/convex_hull.html#bpy-types-geometrynodeconvexhull"),
("bpy.types.geometrynodeimageinput*", "modeling/geometry_nodes/input/image_input.html#bpy-types-geometrynodeimageinput"),
("bpy.types.geometrynodeinputindex*", "modeling/geometry_nodes/input/input_index.html#bpy-types-geometrynodeinputindex"),
("bpy.types.geometrynodeisviewport*", "modeling/geometry_nodes/input/is_viewport.html#bpy-types-geometrynodeisviewport"),
("bpy.types.geometrynodemeshcircle*", "modeling/geometry_nodes/mesh_primitives/mesh_circle.html#bpy-types-geometrynodemeshcircle"),
@ -2172,10 +2174,11 @@ url_manual_mapping = (
("bpy.types.bakesettings.margin*", "render/cycles/baking.html#bpy-types-bakesettings-margin"),
("bpy.types.bakesettings.target*", "render/cycles/baking.html#bpy-types-bakesettings-target"),
("bpy.types.brush.cloth_damping*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-damping"),
("bpy.types.brush.deform_target*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-deform-target"),
("bpy.types.brush.falloff_shape*", "sculpt_paint/brush/falloff.html#bpy-types-brush-falloff-shape"),
("bpy.types.brush.icon_filepath*", "sculpt_paint/brush/brush.html#bpy-types-brush-icon-filepath"),
("bpy.types.brush.stroke_method*", "sculpt_paint/brush/stroke.html#bpy-types-brush-stroke-method"),
("bpy.types.brush.tip_roundness*", "sculpt_paint/sculpting/tools/clay_strips.html#bpy-types-brush-tip-roundness"),
("bpy.types.brush.tip_roundness*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-tip-roundness"),
("bpy.types.camera.display_size*", "render/cameras.html#bpy-types-camera-display-size"),
("bpy.types.camera.sensor_width*", "render/cameras.html#bpy-types-camera-sensor-width"),
("bpy.types.compositornodedblur*", "compositing/types/filter/directional_blur.html#bpy-types-compositornodedblur"),
@ -2705,6 +2708,7 @@ url_manual_mapping = (
("bpy.types.armature.rigify*", "addons/rigging/rigify/basics.html#bpy-types-armature-rigify"),
("bpy.types.bone.use_deform*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-use-deform"),
("bpy.types.booleanmodifier*", "modeling/modifiers/generate/booleans.html#bpy-types-booleanmodifier"),
("bpy.types.brush.direction*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-direction"),
("bpy.types.brush.mask_tool*", "sculpt_paint/sculpting/tools/mask.html#bpy-types-brush-mask-tool"),
("bpy.types.constraint.mute*", "animation/constraints/interface/header.html#bpy-types-constraint-mute"),
("bpy.types.constraint.name*", "animation/constraints/interface/header.html#bpy-types-constraint-name"),
@ -2798,6 +2802,7 @@ url_manual_mapping = (
("bpy.ops.wm.save_mainfile*", "files/blend/open_save.html#bpy-ops-wm-save-mainfile"),
("bpy.types.bone.show_wire*", "animation/armatures/bones/properties/display.html#bpy-types-bone-show-wire"),
("bpy.types.brush.hardness*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-hardness"),
("bpy.types.brush.strength*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-strength"),
("bpy.types.curves.surface*", "modeling/curves/primitives.html#bpy-types-curves-surface"),
("bpy.types.curvesmodifier*", "editors/video_sequencer/sequencer/sidebar/modifiers.html#bpy-types-curvesmodifier"),
("bpy.types.ffmpegsettings*", "render/output/properties/output.html#bpy-types-ffmpegsettings"),
@ -3111,6 +3116,7 @@ url_manual_mapping = (
("bpy.types.bonegroups*", "animation/armatures/properties/bone_groups.html#bpy-types-bonegroups"),
("bpy.types.bpy_struct*", "files/data_blocks.html#bpy-types-bpy-struct"),
("bpy.types.brush.rate*", "sculpt_paint/brush/stroke.html#bpy-types-brush-rate"),
("bpy.types.brush.size*", "sculpt_paint/brush/brush_settings.html#bpy-types-brush-size"),
("bpy.types.collection*", "scene_layout/collections/collections.html#bpy-types-collection"),
("bpy.types.compositor*", "compositing/index.html#bpy-types-compositor"),
("bpy.types.constraint*", "animation/constraints/index.html#bpy-types-constraint"),

View File

@ -605,9 +605,8 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = []
for collection in (
# Built-in names.
{"position": None, "shade_smooth": None, "normal": None, "crease": None},
{"shade_smooth": None, "normal": None, "crease": None},
mesh.attributes,
mesh.uv_layers,
None if ob is None else ob.vertex_groups,
):
if collection is None:

View File

@ -605,7 +605,7 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "GPU Backend"
bl_label = "GPU Back end"
@classmethod
def poll(cls, _context):
@ -622,7 +622,7 @@ class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel):
col.prop(system, "gpu_backend")
if system.gpu_backend != gpu.platform.backend_type_get():
layout.label(text="Requires a restart of Blender to take effect.", icon='INFO')
layout.label(text="Requires a restart of Blender to take effect", icon='INFO')
class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
@ -2324,7 +2324,6 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
({"property": "use_realtime_compositor"}, "T99210"),
),
)

View File

@ -2696,14 +2696,14 @@ class VIEW3D_MT_object_context_menu(Menu):
if selected_objects_len > 1:
layout.operator("object.join")
if obj.type in {'MESH', 'CURVE', 'SURFACE', 'POINTCLOUD', 'META', 'FONT'}:
if obj.type in {'MESH', 'CURVE', 'CURVES', 'SURFACE', 'POINTCLOUD', 'META', 'FONT'}:
layout.operator_menu_enum("object.convert", "target")
if obj.type == 'GPENCIL':
layout.operator_menu_enum("gpencil.convert", "type", text="Convert To")
if (
obj.type in {'MESH', 'CURVE', 'SURFACE', 'GPENCIL', 'LATTICE', 'ARMATURE', 'META', 'FONT'} or
obj.type in {'MESH', 'CURVE', 'CURVES', 'SURFACE', 'GPENCIL', 'LATTICE', 'ARMATURE', 'META', 'FONT', 'POINTCLOUD'} or
(obj.type == 'EMPTY' and obj.instance_collection is not None)
):
layout.operator_context = 'INVOKE_REGION_WIN'
@ -3660,10 +3660,6 @@ class VIEW3D_MT_pose_propagate(Menu):
def draw(self, _context):
layout = self.layout
layout.operator("pose.propagate").mode = 'WHILE_HELD'
layout.separator()
layout.operator("pose.propagate", text="To Next Keyframe").mode = 'NEXT_KEY'
layout.operator("pose.propagate", text="To Last Keyframe (Make Cyclic)").mode = 'LAST_KEY'
@ -6216,8 +6212,7 @@ class VIEW3D_PT_shading_compositor(Panel):
@classmethod
def poll(cls, context):
return (context.space_data.shading.type in {'MATERIAL', 'RENDERED'} and
context.preferences.experimental.use_realtime_compositor)
return context.space_data.shading.type in {'MATERIAL', 'RENDERED'}
def draw(self, context):
shading = context.space_data.shading
@ -6229,7 +6224,7 @@ class VIEW3D_PT_shading_compositor(Panel):
row.active = not is_macos
row.prop(shading, "use_compositor", expand=True)
if is_macos and shading.use_compositor != "DISABLED":
self.layout.label(text="Compositor not supported on MacOS.", icon='ERROR')
self.layout.label(text="Compositor not supported on MacOS", icon='ERROR')
class VIEW3D_PT_gizmo_display(Panel):

View File

@ -257,6 +257,22 @@ static const char32_t *blf_get_sample_text(FT_Face face)
count_bits_i((uint)os2_table->ulUnicodeRange3) +
count_bits_i((uint)os2_table->ulUnicodeRange4);
/* Use OS/2 Table code page range bits to differentiate between (combined) CJK fonts.
* See https://learn.microsoft.com/en-us/typography/opentype/spec/os2#cpr */
FT_ULong codepages = os2_table->ulCodePageRange1;
if (codepages & (1 << 19) || codepages & (1 << 21)) {
return U"\ud55c\uad6d\uc5b4"; /* 한국어 Korean. */
}
if (codepages & (1 << 20)) {
return U"\u7E41\u9AD4\u5B57"; /* 繁體字 Traditional Chinese. */
}
if (codepages & (1 << 17) && !(codepages & (1 << 18))) {
return U"\u65E5\u672C\u8A9E"; /* 日本語 Japanese. */
}
if (codepages & (1 << 18) && !(codepages & (1 << 17))) {
return U"\u7B80\u4F53\u5B57"; /* 简体字 Simplified Chinese. */
}
for (uint i = 0; i < ARRAY_SIZE(unicode_samples); ++i) {
const UnicodeSample *s = &unicode_samples[i];
if (os2_table && s->field && s->mask) {

View File

@ -61,7 +61,6 @@ struct CustomData_MeshMasks;
struct Depsgraph;
struct MEdge;
struct MFace;
struct MVert;
struct Mesh;
struct ModifierData;
struct Object;
@ -125,7 +124,10 @@ struct DerivedMesh {
* and freed on the next ->release(). consider using getVert/Edge/Face if
* you are only interested in a few verts/edges/faces.
*/
struct MVert *(*getVertArray)(DerivedMesh *dm);
/**
* \warning The real return type is `float(*)[3]`.
*/
float *(*getVertArray)(DerivedMesh *dm);
struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
struct MLoop *(*getLoopArray)(DerivedMesh *dm);
struct MPoly *(*getPolyArray)(DerivedMesh *dm);
@ -133,7 +135,7 @@ struct DerivedMesh {
/** Copy all verts/edges/faces from the derived mesh into
* *{vert/edge/face}_r (must point to a buffer large enough)
*/
void (*copyVertArray)(DerivedMesh *dm, struct MVert *r_vert);
void (*copyVertArray)(DerivedMesh *dm, float (*r_positions)[3]);
void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *r_edge);
void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *r_loop);
void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *r_poly);

View File

@ -47,6 +47,8 @@ class AnonymousAttributeID {
return name_;
}
virtual std::string user_name() const;
void user_add() const
{
users_.fetch_add(1);

View File

@ -131,6 +131,10 @@ struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const
bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname);
const char *BKE_uv_map_vert_select_name_get(const char *uv_map_name, char *buffer);
const char *BKE_uv_map_edge_select_name_get(const char *uv_map_name, char *buffer);
const char *BKE_uv_map_pin_name_get(const char *uv_map_name, char *buffer);
#ifdef __cplusplus
}
#endif