UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
80 changed files with 2043 additions and 1586 deletions
Showing only changes of commit c2309356c6 - Show all commits

View File

@ -111,9 +111,13 @@ BVHEmbree::~BVHEmbree()
}
}
void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
void BVHEmbree::build(Progress &progress,
Stats *stats,
RTCDevice rtc_device_,
const bool rtc_device_is_sycl_)
{
rtc_device = rtc_device_;
rtc_device_is_sycl = rtc_device_is_sycl_;
assert(rtc_device);
rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
@ -266,15 +270,29 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
const int *triangles = mesh->get_triangles().data();
rtcSetSharedGeometryBuffer(geom_id,
RTC_BUFFER_TYPE_INDEX,
0,
RTC_FORMAT_UINT3,
triangles,
0,
sizeof(int) * 3,
num_triangles);
if (!rtc_device_is_sycl) {
rtcSetSharedGeometryBuffer(geom_id,
RTC_BUFFER_TYPE_INDEX,
0,
RTC_FORMAT_UINT3,
triangles,
0,
sizeof(int) * 3,
num_triangles);
}
else {
/* NOTE(sirgienko): If the Embree device is a SYCL device, then Embree execution will
* happen on GPU, and we cannot use standard host pointers at this point. So instead
* of making a shared geometry buffer - a new Embree buffer will be created and data
* will be copied. */
int *triangles_buffer = (int *)rtcSetNewGeometryBuffer(
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
assert(triangles_buffer);
if (triangles_buffer) {
static_assert(sizeof(int) == sizeof(uint));
std::memcpy(triangles_buffer, triangles, sizeof(int) * 3 * (num_triangles));
}
}
set_tri_vertex_buffer(geom_id, mesh, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
@ -323,14 +341,38 @@ void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, con
rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
}
else {
rtcSetSharedGeometryBuffer(geom_id,
RTC_BUFFER_TYPE_VERTEX,
t,
RTC_FORMAT_FLOAT3,
verts,
0,
sizeof(float3),
num_verts + 1);
if (!rtc_device_is_sycl) {
rtcSetSharedGeometryBuffer(geom_id,
RTC_BUFFER_TYPE_VERTEX,
t,
RTC_FORMAT_FLOAT3,
verts,
0,
sizeof(float3),
num_verts + 1);
}
else {
/* NOTE(sirgienko): If the Embree device is a SYCL device, then Embree execution will
* happen on GPU, and we cannot use standard host pointers at this point. So instead
* of making a shared geometry buffer - a new Embree buffer will be created and data
* will be copied. */
/* As float3 is packed on GPU side, we map it to packed_float3. */
packed_float3 *verts_buffer = (packed_float3 *)rtcSetNewGeometryBuffer(
geom_id,
RTC_BUFFER_TYPE_VERTEX,
t,
RTC_FORMAT_FLOAT3,
sizeof(packed_float3),
num_verts + 1);
assert(verts_buffer);
if (verts_buffer) {
for (size_t i = (size_t)0; i < num_verts + 1; ++i) {
verts_buffer[i].x = verts[i].x;
verts_buffer[i].y = verts[i].y;
verts_buffer[i].z = verts[i].z;
}
}
}
}
}
}

View File

@ -29,7 +29,10 @@ class PointCloud;
class BVHEmbree : public BVH {
public:
void build(Progress &progress, Stats *stats, RTCDevice rtc_device);
void build(Progress &progress,
Stats *stats,
RTCDevice rtc_device,
const bool isSyclEmbreeDevice = false);
void refit(Progress &progress);
RTCScene scene;
@ -55,6 +58,7 @@ class BVHEmbree : public BVH {
const bool update);
RTCDevice rtc_device;
bool rtc_device_is_sycl;
enum RTCBuildQuality build_quality;
};

View File

@ -143,7 +143,7 @@ void OneapiDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
bvh_embree->refit(progress);
}
else {
bvh_embree->build(progress, &stats, embree_device);
bvh_embree->build(progress, &stats, embree_device, true);
}
if (bvh->params.top_level) {
embree_scene = bvh_embree->scene;

View File

@ -778,8 +778,6 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
# Host execution won't use GPU binaries, no need to compile them.
if(WITH_CYCLES_ONEAPI_BINARIES AND NOT WITH_CYCLES_ONEAPI_HOST_TASK_EXECUTION)
# AoT binaries aren't currently reused when calling sycl::build.
list(APPEND sycl_compiler_flags -DWITH_CYCLES_ONEAPI_BINARIES)
# Iterate over all targest and their options
list(JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string)
list(APPEND sycl_compiler_flags -fsycl-targets=${targets_string})

View File

@ -289,6 +289,15 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
return false;
}
# ifdef __EMBREE__
IF_USING_EMBREE
{
if (kernel_data.device_bvh) {
return kernel_embree_intersect_volume(kg, ray, isect, visibility);
}
}
# endif
IF_NOT_USING_EMBREE
{
# ifdef __OBJECT_MOTION__

View File

@ -109,7 +109,9 @@ struct CCLVolumeContext
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
# ifdef __VOLUME_RECORD_ALL__
numhit_t max_hits;
# endif
numhit_t num_hits;
#endif
Intersection *vol_isect;
@ -505,8 +507,10 @@ ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func_impl(
#endif
const Ray *cray = ctx->ray;
#ifdef __VOLUME_RECORD_ALL__
/* Append the intersection to the end of the array. */
if (ctx->num_hits < ctx->max_hits) {
#endif
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
@ -523,10 +527,17 @@ ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func_impl(
int object_flag = kernel_data_fetch(object_flag, tri_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
#ifndef __VOLUME_RECORD_ALL__
/* Without __VOLUME_RECORD_ALL__ we need only a first counted hit, so we will
* continue tracing only if a current hit is not counted. */
*args->valid = 0;
#endif
}
#ifdef __VOLUME_RECORD_ALL__
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
#endif
}
#if EMBREE_MAJOR_VERSION < 4
@ -844,7 +855,9 @@ ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
ccl_private const Ray *ray,
ccl_private Intersection *isect,
# ifdef __VOLUME_RECORD_ALL__
const uint max_hits,
# endif
const uint visibility)
{
# if EMBREE_MAJOR_VERSION >= 4
@ -864,7 +877,9 @@ ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
rtcInitIntersectContext(&ctx);
# endif
ctx.vol_isect = isect;
# ifdef __VOLUME_RECORD_ALL__
ctx.max_hits = numhit_t(max_hits);
# endif
ctx.num_hits = numhit_t(0);
ctx.ray = ray;
RTCRay rtc_ray;

View File

@ -174,6 +174,14 @@ bool oneapi_kernel_is_required_for_features(const std::string &kernel_name,
return true;
}
bool oneapi_kernel_is_raytrace_or_mnee(const std::string &kernel_name)
{
return (kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE)) !=
std::string::npos) ||
(kernel_name.find(device_kernel_as_string(
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE)) != std::string::npos);
}
bool oneapi_kernel_is_using_embree(const std::string &kernel_name)
{
# ifdef WITH_EMBREE_GPU
@ -182,8 +190,7 @@ bool oneapi_kernel_is_using_embree(const std::string &kernel_name)
DeviceKernel kernel = (DeviceKernel)i;
if (device_kernel_has_intersection(kernel)) {
if (kernel_name.find(device_kernel_as_string(kernel)) != std::string::npos) {
return !(kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE);
return !oneapi_kernel_is_raytrace_or_mnee(kernel_name);
}
}
}
@ -241,10 +248,6 @@ bool oneapi_load_kernels(SyclQueue *queue_,
}
# endif
# ifdef WITH_CYCLES_ONEAPI_BINARIES
(void)queue_;
(void)kernel_features;
# else
try {
sycl::kernel_bundle<sycl::bundle_state::input> all_kernels_bundle =
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(),
@ -260,18 +263,22 @@ bool oneapi_load_kernels(SyclQueue *queue_,
continue;
}
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id});
# ifdef WITH_EMBREE_GPU
/* This is expected to be the default, we set it again to be sure. */
if (one_kernel_bundle_input
.has_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>()) {
# ifdef WITH_EMBREE_GPU
if (oneapi_kernel_is_using_embree(kernel_name) ||
oneapi_kernel_is_raytrace_or_mnee(kernel_name)) {
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id});
one_kernel_bundle_input
.set_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>(
RTC_FEATURE_FLAG_NONE);
sycl::build(one_kernel_bundle_input);
continue;
}
# endif
sycl::build(one_kernel_bundle_input);
# endif
/* This call will ensure that AoT or cached JIT binaries are available
* for execution. It will trigger compilation if it is not already the case. */
(void)sycl::get_kernel_bundle<sycl::bundle_state::executable>(queue->get_context(),
{kernel_id});
}
}
catch (sycl::exception const &e) {
@ -280,7 +287,6 @@ bool oneapi_load_kernels(SyclQueue *queue_,
}
return false;
}
# endif
return true;
}

View File

@ -15,8 +15,12 @@ set(SRC
camera.cpp
colorspace.cpp
constant_fold.cpp
devicescene.cpp
film.cpp
geometry.cpp
geometry_attributes.cpp
geometry_bvh.cpp
geometry_mesh.cpp
hair.cpp
image.cpp
image_oiio.cpp
@ -55,6 +59,7 @@ set(SRC_HEADERS
camera.h
colorspace.h
constant_fold.h
devicescene.h
film.h
geometry.h
hair.h

View File

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "scene/devicescene.h"
#include "device/device.h"
#include "device/memory.h"
CCL_NAMESPACE_BEGIN
DeviceScene::DeviceScene(Device *device)
: bvh_nodes(device, "bvh_nodes", MEM_GLOBAL),
bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL),
object_node(device, "object_node", MEM_GLOBAL),
prim_type(device, "prim_type", MEM_GLOBAL),
prim_visibility(device, "prim_visibility", MEM_GLOBAL),
prim_index(device, "prim_index", MEM_GLOBAL),
prim_object(device, "prim_object", MEM_GLOBAL),
prim_time(device, "prim_time", MEM_GLOBAL),
tri_verts(device, "tri_verts", MEM_GLOBAL),
tri_shader(device, "tri_shader", MEM_GLOBAL),
tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
tri_vindex(device, "tri_vindex", MEM_GLOBAL),
tri_patch(device, "tri_patch", MEM_GLOBAL),
tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL),
curves(device, "curves", MEM_GLOBAL),
curve_keys(device, "curve_keys", MEM_GLOBAL),
curve_segments(device, "curve_segments", MEM_GLOBAL),
patches(device, "patches", MEM_GLOBAL),
points(device, "points", MEM_GLOBAL),
points_shader(device, "points_shader", MEM_GLOBAL),
objects(device, "objects", MEM_GLOBAL),
object_motion_pass(device, "object_motion_pass", MEM_GLOBAL),
object_motion(device, "object_motion", MEM_GLOBAL),
object_flag(device, "object_flag", MEM_GLOBAL),
object_volume_step(device, "object_volume_step", MEM_GLOBAL),
object_prim_offset(device, "object_prim_offset", MEM_GLOBAL),
camera_motion(device, "camera_motion", MEM_GLOBAL),
attributes_map(device, "attributes_map", MEM_GLOBAL),
attributes_float(device, "attributes_float", MEM_GLOBAL),
attributes_float2(device, "attributes_float2", MEM_GLOBAL),
attributes_float3(device, "attributes_float3", MEM_GLOBAL),
attributes_float4(device, "attributes_float4", MEM_GLOBAL),
attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL),
light_distribution(device, "light_distribution", MEM_GLOBAL),
lights(device, "lights", MEM_GLOBAL),
light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL),
light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL),
light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL),
light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL),
light_to_tree(device, "light_to_tree", MEM_GLOBAL),
object_to_tree(device, "object_to_tree", MEM_GLOBAL),
object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL),
triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL),
particles(device, "particles", MEM_GLOBAL),
svm_nodes(device, "svm_nodes", MEM_GLOBAL),
shaders(device, "shaders", MEM_GLOBAL),
lookup_table(device, "lookup_table", MEM_GLOBAL),
sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL),
ies_lights(device, "ies", MEM_GLOBAL)
{
memset((void *)&data, 0, sizeof(data));
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,101 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#ifndef __DEVICESCENE_H__
#define __DEVICESCENE_H__
#include "device/device.h"
#include "device/memory.h"
#include "util/types.h"
#include "util/vector.h"
CCL_NAMESPACE_BEGIN
class DeviceScene {
public:
/* BVH */
device_vector<int4> bvh_nodes;
device_vector<int4> bvh_leaf_nodes;
device_vector<int> object_node;
device_vector<int> prim_type;
device_vector<uint> prim_visibility;
device_vector<int> prim_index;
device_vector<int> prim_object;
device_vector<float2> prim_time;
/* mesh */
device_vector<packed_float3> tri_verts;
device_vector<uint> tri_shader;
device_vector<packed_float3> tri_vnormal;
device_vector<packed_uint3> tri_vindex;
device_vector<uint> tri_patch;
device_vector<float2> tri_patch_uv;
device_vector<KernelCurve> curves;
device_vector<float4> curve_keys;
device_vector<KernelCurveSegment> curve_segments;
device_vector<uint> patches;
/* point-cloud */
device_vector<float4> points;
device_vector<uint> points_shader;
/* objects */
device_vector<KernelObject> objects;
device_vector<Transform> object_motion_pass;
device_vector<DecomposedTransform> object_motion;
device_vector<uint> object_flag;
device_vector<float> object_volume_step;
device_vector<uint> object_prim_offset;
/* cameras */
device_vector<DecomposedTransform> camera_motion;
/* attributes */
device_vector<AttributeMap> attributes_map;
device_vector<float> attributes_float;
device_vector<float2> attributes_float2;
device_vector<packed_float3> attributes_float3;
device_vector<float4> attributes_float4;
device_vector<uchar4> attributes_uchar4;
/* lights */
device_vector<KernelLightDistribution> light_distribution;
device_vector<KernelLight> lights;
device_vector<float2> light_background_marginal_cdf;
device_vector<float2> light_background_conditional_cdf;
/* light tree */
device_vector<KernelLightTreeNode> light_tree_nodes;
device_vector<KernelLightTreeEmitter> light_tree_emitters;
device_vector<uint> light_to_tree;
device_vector<uint> object_to_tree;
device_vector<uint> object_lookup_offset;
device_vector<uint> triangle_to_tree;
/* particles */
device_vector<KernelParticle> particles;
/* shaders */
device_vector<int4> svm_nodes;
device_vector<KernelShader> shaders;
/* lookup tables */
device_vector<float> lookup_table;
/* integrator */
device_vector<float> sample_pattern_lut;
/* IES lights */
device_vector<float> ies_lights;
KernelData data;
DeviceScene(Device *device);
};
CCL_NAMESPACE_END
#endif /* __DEVICESCENE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,38 @@ class Shader;
class Volume;
struct PackedBVH;
/* Set of flags used to help determining what data has been modified or needs reallocation, so we
* can decide which device data to free or update. */
enum {
DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
DEVICE_POINT_DATA_MODIFIED = (1 << 2),
ATTR_FLOAT_MODIFIED = (1 << 3),
ATTR_FLOAT2_MODIFIED = (1 << 4),
ATTR_FLOAT3_MODIFIED = (1 << 5),
ATTR_FLOAT4_MODIFIED = (1 << 6),
ATTR_UCHAR4_MODIFIED = (1 << 7),
CURVE_DATA_NEED_REALLOC = (1 << 8),
MESH_DATA_NEED_REALLOC = (1 << 9),
POINT_DATA_NEED_REALLOC = (1 << 10),
ATTR_FLOAT_NEEDS_REALLOC = (1 << 11),
ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12),
ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13),
ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14),
ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15),
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC |
ATTR_UCHAR4_NEEDS_REALLOC),
DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
};
/* Geometry
*
* Base class for geometric types like Mesh and Hair. */

View File

@ -0,0 +1,722 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "bvh/bvh.h"
#include "bvh/bvh2.h"
#include "device/device.h"
#include "scene/attribute.h"
#include "scene/camera.h"
#include "scene/geometry.h"
#include "scene/hair.h"
#include "scene/light.h"
#include "scene/mesh.h"
#include "scene/object.h"
#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "scene/shader.h"
#include "scene/shader_nodes.h"
#include "scene/stats.h"
#include "scene/volume.h"
#include "subd/patch_table.h"
#include "subd/split.h"
#include "kernel/osl/globals.h"
#include "util/foreach.h"
#include "util/log.h"
#include "util/progress.h"
#include "util/task.h"
CCL_NAMESPACE_BEGIN
bool Geometry::need_attribute(Scene *scene, AttributeStandard std)
{
if (std == ATTR_STD_NONE)
return false;
if (scene->need_global_attribute(std))
return true;
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
if (shader->attributes.find(std))
return true;
}
return false;
}
bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
{
if (name == ustring())
return false;
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
if (shader->attributes.find(name))
return true;
}
return false;
}
AttributeRequestSet Geometry::needed_attributes()
{
AttributeRequestSet result;
foreach (Node *node, used_shaders) {
Shader *shader = static_cast<Shader *>(node);
result.add(shader->attributes);
}
return result;
}
bool Geometry::has_voxel_attributes() const
{
foreach (const Attribute &attr, attributes.attributes) {
if (attr.element == ATTR_ELEMENT_VOXEL) {
return true;
}
}
return false;
}
/* Generate a normal attribute map entry from an attribute descriptor. */
static void emit_attribute_map_entry(AttributeMap *attr_map,
size_t index,
uint64_t id,
TypeDesc type,
const AttributeDescriptor &desc)
{
attr_map[index].id = id;
attr_map[index].element = desc.element;
attr_map[index].offset = as_uint(desc.offset);
if (type == TypeDesc::TypeFloat)
attr_map[index].type = NODE_ATTR_FLOAT;
else if (type == TypeDesc::TypeMatrix)
attr_map[index].type = NODE_ATTR_MATRIX;
else if (type == TypeFloat2)
attr_map[index].type = NODE_ATTR_FLOAT2;
else if (type == TypeFloat4)
attr_map[index].type = NODE_ATTR_FLOAT4;
else if (type == TypeRGBA)
attr_map[index].type = NODE_ATTR_RGBA;
else
attr_map[index].type = NODE_ATTR_FLOAT3;
attr_map[index].flags = desc.flags;
}
/* Generate an attribute map end marker, optionally including a link to another map.
* Links are used to connect object attribute maps to mesh attribute maps. */
static void emit_attribute_map_terminator(AttributeMap *attr_map,
size_t index,
bool chain,
uint chain_link)
{
for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
attr_map[index + j].id = ATTR_STD_NONE;
attr_map[index + j].element = chain; /* link is valid flag */
attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */
attr_map[index + j].type = 0;
attr_map[index + j].flags = 0;
}
}
/* Generate all necessary attribute map entries from the attribute request. */
static void emit_attribute_mapping(
AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom)
{
emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->get_num_subd_faces()) {
emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
}
}
}
void GeometryManager::update_svm_attributes(Device *,
DeviceScene *dscene,
Scene *scene,
vector<AttributeRequestSet> &geom_attributes,
vector<AttributeRequestSet> &object_attributes)
{
/* for SVM, the attributes_map table is used to lookup the offset of an
* attribute, based on a unique shader attribute id. */
/* compute array stride */
size_t attr_map_size = 0;
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
geom->attr_map_offset = attr_map_size;
#ifdef WITH_OSL
size_t attr_count = 0;
foreach (AttributeRequest &req, geom_attributes[i].requests) {
if (req.std != ATTR_STD_NONE &&
scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std)
attr_count += 2;
else
attr_count += 1;
}
#else
const size_t attr_count = geom_attributes[i].size();
#endif
attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES;
}
for (size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
/* only allocate a table for the object if it actually has attributes */
if (object_attributes[i].size() == 0) {
object->attr_map_offset = 0;
}
else {
object->attr_map_offset = attr_map_size;
attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
}
}
if (attr_map_size == 0)
return;
if (!dscene->attributes_map.need_realloc()) {
return;
}
/* create attribute map */
AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size);
memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map));
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
AttributeRequestSet &attributes = geom_attributes[i];
/* set geometry attributes */
size_t index = geom->attr_map_offset;
foreach (AttributeRequest &req, attributes.requests) {
uint64_t id;
if (req.std == ATTR_STD_NONE)
id = scene->shader_manager->get_attribute_id(req.name);
else
id = scene->shader_manager->get_attribute_id(req.std);
emit_attribute_mapping(attr_map, index, id, req, geom);
index += ATTR_PRIM_TYPES;
#ifdef WITH_OSL
/* Some standard attributes are explicitly referenced via their standard ID, so add those
* again in case they were added under a different attribute ID. */
if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) {
emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom);
index += ATTR_PRIM_TYPES;
}
#endif
}
emit_attribute_map_terminator(attr_map, index, false, 0);
}
for (size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
AttributeRequestSet &attributes = object_attributes[i];
/* set object attributes */
if (attributes.size() > 0) {
size_t index = object->attr_map_offset;
foreach (AttributeRequest &req, attributes.requests) {
uint64_t id;
if (req.std == ATTR_STD_NONE)
id = scene->shader_manager->get_attribute_id(req.name);
else
id = scene->shader_manager->get_attribute_id(req.std);
emit_attribute_mapping(attr_map, index, id, req, object->geometry);
index += ATTR_PRIM_TYPES;
}
emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
}
}
/* copy to device */
dscene->attributes_map.copy_to_device();
}
void GeometryManager::update_attribute_element_offset(Geometry *geom,
device_vector<float> &attr_float,
size_t &attr_float_offset,
device_vector<float2> &attr_float2,
size_t &attr_float2_offset,
device_vector<packed_float3> &attr_float3,
size_t &attr_float3_offset,
device_vector<float4> &attr_float4,
size_t &attr_float4_offset,
device_vector<uchar4> &attr_uchar4,
size_t &attr_uchar4_offset,
Attribute *mattr,
AttributePrimitive prim,
TypeDesc &type,
AttributeDescriptor &desc)
{
if (mattr) {
/* store element and type */
desc.element = mattr->element;
desc.flags = mattr->flags;
type = mattr->type;
/* store attribute data in arrays */
size_t size = mattr->element_size(geom, prim);
AttributeElement &element = desc.element;
int &offset = desc.offset;
if (mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
ImageHandle &handle = mattr->data_voxel();
offset = handle.svm_slot();
}
else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
uchar4 *data = mattr->data_uchar4();
offset = attr_uchar4_offset;
assert(attr_uchar4.size() >= offset + size);
if (mattr->modified) {
for (size_t k = 0; k < size; k++) {
attr_uchar4[offset + k] = data[k];
}
attr_uchar4.tag_modified();
}
attr_uchar4_offset += size;
}
else if (mattr->type == TypeDesc::TypeFloat) {
float *data = mattr->data_float();
offset = attr_float_offset;
assert(attr_float.size() >= offset + size);
if (mattr->modified) {
for (size_t k = 0; k < size; k++) {
attr_float[offset + k] = data[k];
}
attr_float.tag_modified();
}
attr_float_offset += size;
}
else if (mattr->type == TypeFloat2) {
float2 *data = mattr->data_float2();
offset = attr_float2_offset;
assert(attr_float2.size() >= offset + size);
if (mattr->modified) {
for (size_t k = 0; k < size; k++) {
attr_float2[offset + k] = data[k];
}
attr_float2.tag_modified();
}
attr_float2_offset += size;
}
else if (mattr->type == TypeDesc::TypeMatrix) {
Transform *tfm = mattr->data_transform();
offset = attr_float4_offset;
assert(attr_float4.size() >= offset + size * 3);
if (mattr->modified) {
for (size_t k = 0; k < size * 3; k++) {
attr_float4[offset + k] = (&tfm->x)[k];
}
attr_float4.tag_modified();
}
attr_float4_offset += size * 3;
}
else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
float4 *data = mattr->data_float4();
offset = attr_float4_offset;
assert(attr_float4.size() >= offset + size);
if (mattr->modified) {
for (size_t k = 0; k < size; k++) {
attr_float4[offset + k] = data[k];
}
attr_float4.tag_modified();
}
attr_float4_offset += size;
}
else {
float3 *data = mattr->data_float3();
offset = attr_float3_offset;
assert(attr_float3.size() >= offset + size);
if (mattr->modified) {
for (size_t k = 0; k < size; k++) {
attr_float3[offset + k] = data[k];
}
attr_float3.tag_modified();
}
attr_float3_offset += size;
}
/* mesh vertex/curve index is global, not per object, so we sneak
* a correction for that in here */
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK &&
desc.flags & ATTR_SUBDIVIDED) {
/* Indices for subdivided attributes are retrieved
* from patch table so no need for correction here. */
}
else if (element == ATTR_ELEMENT_VERTEX)
offset -= mesh->vert_offset;
else if (element == ATTR_ELEMENT_VERTEX_MOTION)
offset -= mesh->vert_offset;
else if (element == ATTR_ELEMENT_FACE) {
if (prim == ATTR_PRIM_GEOMETRY)
offset -= mesh->prim_offset;
else
offset -= mesh->face_offset;
}
else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) {
if (prim == ATTR_PRIM_GEOMETRY)
offset -= 3 * mesh->prim_offset;
else
offset -= mesh->corner_offset;
}
}
else if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
if (element == ATTR_ELEMENT_CURVE)
offset -= hair->prim_offset;
else if (element == ATTR_ELEMENT_CURVE_KEY)
offset -= hair->curve_key_offset;
else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
offset -= hair->curve_key_offset;
}
else if (geom->is_pointcloud()) {
if (element == ATTR_ELEMENT_VERTEX)
offset -= geom->prim_offset;
else if (element == ATTR_ELEMENT_VERTEX_MOTION)
offset -= geom->prim_offset;
}
}
else {
/* attribute not found */
desc.element = ATTR_ELEMENT_NONE;
desc.offset = 0;
}
}
static void update_attribute_element_size(Geometry *geom,
Attribute *mattr,
AttributePrimitive prim,
size_t *attr_float_size,
size_t *attr_float2_size,
size_t *attr_float3_size,
size_t *attr_float4_size,
size_t *attr_uchar4_size)
{
if (mattr) {
size_t size = mattr->element_size(geom, prim);
if (mattr->element == ATTR_ELEMENT_VOXEL) {
/* pass */
}
else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
*attr_uchar4_size += size;
}
else if (mattr->type == TypeDesc::TypeFloat) {
*attr_float_size += size;
}
else if (mattr->type == TypeFloat2) {
*attr_float2_size += size;
}
else if (mattr->type == TypeDesc::TypeMatrix) {
*attr_float4_size += size * 4;
}
else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
*attr_float4_size += size;
}
else {
*attr_float3_size += size;
}
}
}
void GeometryManager::device_update_attributes(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
{
progress.set_status("Updating Mesh", "Computing attributes");
/* gather per mesh requested attributes. as meshes may have multiple
* shaders assigned, this merges the requested attributes that have
* been set per shader by the shader manager */
vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
geom->index = i;
scene->need_global_attributes(geom_attributes[i]);
foreach (Node *node, geom->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(node);
geom_attributes[i].add(shader->attributes);
}
if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) {
geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
}
}
/* convert object attributes to use the same data structures as geometry ones */
vector<AttributeRequestSet> object_attributes(scene->objects.size());
vector<AttributeSet> object_attribute_values;
object_attribute_values.reserve(scene->objects.size());
for (size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
Geometry *geom = object->geometry;
size_t geom_idx = geom->index;
assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
AttributeRequestSet &attributes = object_attributes[i];
AttributeSet &values = object_attribute_values[i];
for (size_t j = 0; j < object->attributes.size(); j++) {
ParamValue &param = object->attributes[j];
/* add attributes that are requested and not already handled by the mesh */
if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) {
attributes.add(param.name());
Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT);
assert(param.datasize() == attr->buffer.size());
memcpy(attr->buffer.data(), param.data(), param.datasize());
}
}
}
/* mesh attribute are stored in a single array per data type. here we fill
* those arrays, and set the offset and element type to create attribute
* maps next */
/* Pre-allocate attributes to avoid arrays re-allocation which would
* take 2x of overall attribute memory usage.
*/
size_t attr_float_size = 0;
size_t attr_float2_size = 0;
size_t attr_float3_size = 0;
size_t attr_float4_size = 0;
size_t attr_uchar4_size = 0;
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
AttributeRequestSet &attributes = geom_attributes[i];
foreach (AttributeRequest &req, attributes.requests) {
Attribute *attr = geom->attributes.find(req);
update_attribute_element_size(geom,
attr,
ATTR_PRIM_GEOMETRY,
&attr_float_size,
&attr_float2_size,
&attr_float3_size,
&attr_float4_size,
&attr_uchar4_size);
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
Attribute *subd_attr = mesh->subd_attributes.find(req);
update_attribute_element_size(mesh,
subd_attr,
ATTR_PRIM_SUBD,
&attr_float_size,
&attr_float2_size,
&attr_float3_size,
&attr_float4_size,
&attr_uchar4_size);
}
}
}
for (size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
foreach (Attribute &attr, object_attribute_values[i].attributes) {
update_attribute_element_size(object->geometry,
&attr,
ATTR_PRIM_GEOMETRY,
&attr_float_size,
&attr_float2_size,
&attr_float3_size,
&attr_float4_size,
&attr_uchar4_size);
}
}
dscene->attributes_float.alloc(attr_float_size);
dscene->attributes_float2.alloc(attr_float2_size);
dscene->attributes_float3.alloc(attr_float3_size);
dscene->attributes_float4.alloc(attr_float4_size);
dscene->attributes_uchar4.alloc(attr_uchar4_size);
/* The order of those flags needs to match that of AttrKernelDataType. */
const bool attributes_need_realloc[AttrKernelDataType::NUM] = {
dscene->attributes_float.need_realloc(),
dscene->attributes_float2.need_realloc(),
dscene->attributes_float3.need_realloc(),
dscene->attributes_float4.need_realloc(),
dscene->attributes_uchar4.need_realloc(),
};
size_t attr_float_offset = 0;
size_t attr_float2_offset = 0;
size_t attr_float3_offset = 0;
size_t attr_float4_offset = 0;
size_t attr_uchar4_offset = 0;
/* Fill in attributes. */
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
AttributeRequestSet &attributes = geom_attributes[i];
/* todo: we now store std and name attributes from requests even if
* they actually refer to the same mesh attributes, optimize */
foreach (AttributeRequest &req, attributes.requests) {
Attribute *attr = geom->attributes.find(req);
if (attr) {
/* force a copy if we need to reallocate all the data */
attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
}
update_attribute_element_offset(geom,
dscene->attributes_float,
attr_float_offset,
dscene->attributes_float2,
attr_float2_offset,
dscene->attributes_float3,
attr_float3_offset,
dscene->attributes_float4,
attr_float4_offset,
dscene->attributes_uchar4,
attr_uchar4_offset,
attr,
ATTR_PRIM_GEOMETRY,
req.type,
req.desc);
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
Attribute *subd_attr = mesh->subd_attributes.find(req);
if (subd_attr) {
/* force a copy if we need to reallocate all the data */
subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)];
}
update_attribute_element_offset(mesh,
dscene->attributes_float,
attr_float_offset,
dscene->attributes_float2,
attr_float2_offset,
dscene->attributes_float3,
attr_float3_offset,
dscene->attributes_float4,
attr_float4_offset,
dscene->attributes_uchar4,
attr_uchar4_offset,
subd_attr,
ATTR_PRIM_SUBD,
req.subd_type,
req.subd_desc);
}
if (progress.get_cancel())
return;
}
}
for (size_t i = 0; i < scene->objects.size(); i++) {
Object *object = scene->objects[i];
AttributeRequestSet &attributes = object_attributes[i];
AttributeSet &values = object_attribute_values[i];
foreach (AttributeRequest &req, attributes.requests) {
Attribute *attr = values.find(req);
if (attr) {
attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
}
update_attribute_element_offset(object->geometry,
dscene->attributes_float,
attr_float_offset,
dscene->attributes_float2,
attr_float2_offset,
dscene->attributes_float3,
attr_float3_offset,
dscene->attributes_float4,
attr_float4_offset,
dscene->attributes_uchar4,
attr_uchar4_offset,
attr,
ATTR_PRIM_GEOMETRY,
req.type,
req.desc);
/* object attributes don't care about subdivision */
req.subd_type = req.type;
req.subd_desc = req.desc;
if (progress.get_cancel())
return;
}
}
/* create attribute lookup maps */
if (scene->shader_manager->use_osl())
update_osl_globals(device, scene);
update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
if (progress.get_cancel())
return;
/* copy to device */
progress.set_status("Updating Mesh", "Copying Attributes to device");
dscene->attributes_float.copy_to_device_if_modified();
dscene->attributes_float2.copy_to_device_if_modified();
dscene->attributes_float3.copy_to_device_if_modified();
dscene->attributes_float4.copy_to_device_if_modified();
dscene->attributes_uchar4.copy_to_device_if_modified();
if (progress.get_cancel())
return;
/* After mesh attributes and patch tables have been copied to device memory,
* we need to update offsets in the objects. */
scene->object_manager->device_update_geom_offsets(device, dscene, scene);
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,196 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "bvh/bvh.h"
#include "bvh/bvh2.h"
#include "device/device.h"
#include "scene/attribute.h"
#include "scene/camera.h"
#include "scene/geometry.h"
#include "scene/hair.h"
#include "scene/light.h"
#include "scene/mesh.h"
#include "scene/object.h"
#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "scene/shader.h"
#include "scene/shader_nodes.h"
#include "scene/stats.h"
#include "scene/volume.h"
#include "subd/patch_table.h"
#include "subd/split.h"
#include "kernel/osl/globals.h"
#include "util/foreach.h"
#include "util/log.h"
#include "util/progress.h"
#include "util/task.h"
CCL_NAMESPACE_BEGIN
void Geometry::compute_bvh(Device *device,
DeviceScene *dscene,
SceneParams *params,
Progress *progress,
size_t n,
size_t total)
{
if (progress->get_cancel())
return;
compute_bounds();
const BVHLayout bvh_layout = BVHParams::best_bvh_layout(
params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features));
if (need_build_bvh(bvh_layout)) {
string msg = "Updating Geometry BVH ";
if (name.empty())
msg += string_printf("%u/%u", (uint)(n + 1), (uint)total);
else
msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
Object object;
/* Ensure all visibility bits are set at the geometry level BVH. In
* the object level BVH is where actual visibility is tested. */
object.set_is_shadow_catcher(true);
object.set_visibility(~0);
object.set_geometry(this);
vector<Geometry *> geometry;
geometry.push_back(this);
vector<Object *> objects;
objects.push_back(&object);
if (bvh && !need_update_rebuild) {
progress->set_status(msg, "Refitting BVH");
bvh->replace_geometry(geometry, objects);
device->build_bvh(bvh, *progress, true);
}
else {
progress->set_status(msg, "Building BVH");
BVHParams bparams;
bparams.use_spatial_split = params->use_bvh_spatial_split;
bparams.use_compact_structure = params->use_bvh_compact_structure;
bparams.bvh_layout = bvh_layout;
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
params->use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
bparams.num_motion_curve_steps = params->num_bvh_time_steps;
bparams.num_motion_point_steps = params->num_bvh_time_steps;
bparams.bvh_type = params->bvh_type;
bparams.curve_subdivisions = params->curve_subdivisions();
delete bvh;
bvh = BVH::create(bparams, geometry, objects, device);
MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false);
}
}
need_update_rebuild = false;
need_update_bvh_for_offset = false;
}
void GeometryManager::device_update_bvh(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
{
/* bvh build */
progress.set_status("Updating Scene BVH", "Building");
BVHParams bparams;
bparams.top_level = true;
bparams.bvh_layout = BVHParams::best_bvh_layout(
scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features));
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
scene->params.use_bvh_unaligned_nodes;
bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
bparams.num_motion_point_steps = scene->params.num_bvh_time_steps;
bparams.bvh_type = scene->params.bvh_type;
bparams.curve_subdivisions = scene->params.curve_subdivisions();
VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
const bool can_refit = scene->bvh != nullptr &&
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX ||
bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL);
BVH *bvh = scene->bvh;
if (!scene->bvh) {
bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
}
device->build_bvh(bvh, progress, can_refit);
if (progress.get_cancel()) {
return;
}
const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
PackedBVH pack;
if (has_bvh2_layout) {
pack = std::move(static_cast<BVH2 *>(bvh)->pack);
}
else {
pack.root_index = -1;
}
/* copy to device */
progress.set_status("Updating Scene BVH", "Copying BVH to device");
/* When using BVH2, we always have to copy/update the data as its layout is dependent on the
* BVH's leaf nodes which may be different when the objects or vertices move. */
if (pack.nodes.size()) {
dscene->bvh_nodes.steal_data(pack.nodes);
dscene->bvh_nodes.copy_to_device();
}
if (pack.leaf_nodes.size()) {
dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes);
dscene->bvh_leaf_nodes.copy_to_device();
}
if (pack.object_node.size()) {
dscene->object_node.steal_data(pack.object_node);
dscene->object_node.copy_to_device();
}
if (pack.prim_type.size()) {
dscene->prim_type.steal_data(pack.prim_type);
dscene->prim_type.copy_to_device();
}
if (pack.prim_visibility.size()) {
dscene->prim_visibility.steal_data(pack.prim_visibility);
dscene->prim_visibility.copy_to_device();
}
if (pack.prim_index.size()) {
dscene->prim_index.steal_data(pack.prim_index);
dscene->prim_index.copy_to_device();
}
if (pack.prim_object.size()) {
dscene->prim_object.steal_data(pack.prim_object);
dscene->prim_object.copy_to_device();
}
if (pack.prim_time.size()) {
dscene->prim_time.steal_data(pack.prim_time);
dscene->prim_time.copy_to_device();
}
dscene->data.bvh.root = pack.root_index;
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
/* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
dscene->data.device_bvh = 0;
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,223 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "bvh/bvh.h"
#include "bvh/bvh2.h"
#include "device/device.h"
#include "scene/attribute.h"
#include "scene/camera.h"
#include "scene/geometry.h"
#include "scene/hair.h"
#include "scene/light.h"
#include "scene/mesh.h"
#include "scene/object.h"
#include "scene/osl.h"
#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "scene/shader.h"
#include "scene/shader_nodes.h"
#include "scene/stats.h"
#include "scene/volume.h"
#include "subd/patch_table.h"
#include "subd/split.h"
#ifdef WITH_OSL
# include "kernel/osl/globals.h"
#endif
#include "util/foreach.h"
#include "util/log.h"
#include "util/progress.h"
#include "util/task.h"
CCL_NAMESPACE_BEGIN
void GeometryManager::device_update_mesh(Device *,
DeviceScene *dscene,
Scene *scene,
Progress &progress)
{
/* Count. */
size_t vert_size = 0;
size_t tri_size = 0;
size_t curve_key_size = 0;
size_t curve_size = 0;
size_t curve_segment_size = 0;
size_t point_size = 0;
size_t patch_size = 0;
foreach (Geometry *geom, scene->geometry) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
vert_size += mesh->verts.size();
tri_size += mesh->num_triangles();
if (mesh->get_num_subd_faces()) {
Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
/* patch tables are stored in same array so include them in patch_size */
if (mesh->patch_table) {
mesh->patch_table_offset = patch_size;
patch_size += mesh->patch_table->total_size();
}
}
}
else if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
curve_key_size += hair->get_curve_keys().size();
curve_size += hair->num_curves();
curve_segment_size += hair->num_segments();
}
else if (geom->is_pointcloud()) {
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
point_size += pointcloud->num_points();
}
}
/* Fill in all the arrays. */
if (tri_size != 0) {
/* normals */
progress.set_status("Updating Mesh", "Computing normals");
packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size);
uint *tri_shader = dscene->tri_shader.alloc(tri_size);
packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size);
packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size);
uint *tri_patch = dscene->tri_patch.alloc(tri_size);
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
const bool copy_all_data = dscene->tri_shader.need_realloc() ||
dscene->tri_vindex.need_realloc() ||
dscene->tri_vnormal.need_realloc() ||
dscene->tri_patch.need_realloc() ||
dscene->tri_patch_uv.need_realloc();
foreach (Geometry *geom, scene->geometry) {
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
Mesh *mesh = static_cast<Mesh *>(geom);
if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
mesh->triangles_is_modified() || copy_all_data) {
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
}
if (mesh->verts_is_modified() || copy_all_data) {
mesh->pack_normals(&vnormal[mesh->vert_offset]);
}
if (mesh->verts_is_modified() || mesh->triangles_is_modified() ||
mesh->vert_patch_uv_is_modified() || copy_all_data) {
mesh->pack_verts(&tri_verts[mesh->vert_offset],
&tri_vindex[mesh->prim_offset],
&tri_patch[mesh->prim_offset],
&tri_patch_uv[mesh->vert_offset]);
}
if (progress.get_cancel())
return;
}
}
/* vertex coordinates */
progress.set_status("Updating Mesh", "Copying Mesh to device");
dscene->tri_verts.copy_to_device_if_modified();
dscene->tri_shader.copy_to_device_if_modified();
dscene->tri_vnormal.copy_to_device_if_modified();
dscene->tri_vindex.copy_to_device_if_modified();
dscene->tri_patch.copy_to_device_if_modified();
dscene->tri_patch_uv.copy_to_device_if_modified();
}
if (curve_segment_size != 0) {
progress.set_status("Updating Mesh", "Copying Curves to device");
float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
KernelCurve *curves = dscene->curves.alloc(curve_size);
KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size);
const bool copy_all_data = dscene->curve_keys.need_realloc() ||
dscene->curves.need_realloc() ||
dscene->curve_segments.need_realloc();
foreach (Geometry *geom, scene->geometry) {
if (geom->is_hair()) {
Hair *hair = static_cast<Hair *>(geom);
bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
hair->curve_keys_is_modified();
bool curve_data_modified = hair->curve_shader_is_modified() ||
hair->curve_first_key_is_modified();
if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
continue;
}
hair->pack_curves(scene,
&curve_keys[hair->curve_key_offset],
&curves[hair->prim_offset],
&curve_segments[hair->curve_segment_offset]);
if (progress.get_cancel())
return;
}
}
dscene->curve_keys.copy_to_device_if_modified();
dscene->curves.copy_to_device_if_modified();
dscene->curve_segments.copy_to_device_if_modified();
}
if (point_size != 0) {
progress.set_status("Updating Mesh", "Copying Point clouds to device");
float4 *points = dscene->points.alloc(point_size);
uint *points_shader = dscene->points_shader.alloc(point_size);
foreach (Geometry *geom, scene->geometry) {
if (geom->is_pointcloud()) {
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
pointcloud->pack(
scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]);
if (progress.get_cancel())
return;
}
}
dscene->points.copy_to_device();
dscene->points_shader.copy_to_device();
}
if (patch_size != 0 && dscene->patches.need_realloc()) {
progress.set_status("Updating Mesh", "Copying Patches to device");
uint *patch_data = dscene->patches.alloc(patch_size);
foreach (Geometry *geom, scene->geometry) {
if (geom->is_mesh()) {
Mesh *mesh = static_cast<Mesh *>(geom);
mesh->pack_patches(&patch_data[mesh->patch_offset]);
if (mesh->patch_table) {
mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset],
mesh->patch_table_offset);
}
if (progress.get_cancel())
return;
}
}
dscene->patches.copy_to_device();
}
}
CCL_NAMESPACE_END

View File

@ -24,6 +24,7 @@
#include "scene/svm.h"
#include "scene/tables.h"
#include "scene/volume.h"
#include "scene/devicescene.h"
#include "session/session.h"
#include "util/foreach.h"
@ -33,59 +34,7 @@
CCL_NAMESPACE_BEGIN
DeviceScene::DeviceScene(Device *device)
: bvh_nodes(device, "bvh_nodes", MEM_GLOBAL),
bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL),
object_node(device, "object_node", MEM_GLOBAL),
prim_type(device, "prim_type", MEM_GLOBAL),
prim_visibility(device, "prim_visibility", MEM_GLOBAL),
prim_index(device, "prim_index", MEM_GLOBAL),
prim_object(device, "prim_object", MEM_GLOBAL),
prim_time(device, "prim_time", MEM_GLOBAL),
tri_verts(device, "tri_verts", MEM_GLOBAL),
tri_shader(device, "tri_shader", MEM_GLOBAL),
tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
tri_vindex(device, "tri_vindex", MEM_GLOBAL),
tri_patch(device, "tri_patch", MEM_GLOBAL),
tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL),
curves(device, "curves", MEM_GLOBAL),
curve_keys(device, "curve_keys", MEM_GLOBAL),
curve_segments(device, "curve_segments", MEM_GLOBAL),
patches(device, "patches", MEM_GLOBAL),
points(device, "points", MEM_GLOBAL),
points_shader(device, "points_shader", MEM_GLOBAL),
objects(device, "objects", MEM_GLOBAL),
object_motion_pass(device, "object_motion_pass", MEM_GLOBAL),
object_motion(device, "object_motion", MEM_GLOBAL),
object_flag(device, "object_flag", MEM_GLOBAL),
object_volume_step(device, "object_volume_step", MEM_GLOBAL),
object_prim_offset(device, "object_prim_offset", MEM_GLOBAL),
camera_motion(device, "camera_motion", MEM_GLOBAL),
attributes_map(device, "attributes_map", MEM_GLOBAL),
attributes_float(device, "attributes_float", MEM_GLOBAL),
attributes_float2(device, "attributes_float2", MEM_GLOBAL),
attributes_float3(device, "attributes_float3", MEM_GLOBAL),
attributes_float4(device, "attributes_float4", MEM_GLOBAL),
attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL),
light_distribution(device, "light_distribution", MEM_GLOBAL),
lights(device, "lights", MEM_GLOBAL),
light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL),
light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL),
light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL),
light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL),
light_to_tree(device, "light_to_tree", MEM_GLOBAL),
object_to_tree(device, "object_to_tree", MEM_GLOBAL),
object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL),
triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL),
particles(device, "particles", MEM_GLOBAL),
svm_nodes(device, "svm_nodes", MEM_GLOBAL),
shaders(device, "shaders", MEM_GLOBAL),
lookup_table(device, "lookup_table", MEM_GLOBAL),
sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL),
ies_lights(device, "ies", MEM_GLOBAL)
{
memset((void *)&data, 0, sizeof(data));
}
Scene::Scene(const SceneParams &params_, Device *device)
: name("Scene"),

View File

@ -6,20 +6,16 @@
#include "bvh/params.h"
#include "scene/devicescene.h"
#include "scene/film.h"
#include "scene/image.h"
#include "scene/shader.h"
#include "device/device.h"
#include "device/memory.h"
#include "util/param.h"
#include "util/string.h"
#include "util/system.h"
#include "util/texture.h"
#include "util/thread.h"
#include "util/types.h"
#include "util/vector.h"
CCL_NAMESPACE_BEGIN
@ -54,92 +50,6 @@ class RenderStats;
class SceneUpdateStats;
class Volume;
/* Scene Device Data */
class DeviceScene {
public:
/* BVH */
device_vector<int4> bvh_nodes;
device_vector<int4> bvh_leaf_nodes;
device_vector<int> object_node;
device_vector<int> prim_type;
device_vector<uint> prim_visibility;
device_vector<int> prim_index;
device_vector<int> prim_object;
device_vector<float2> prim_time;
/* mesh */
device_vector<packed_float3> tri_verts;
device_vector<uint> tri_shader;
device_vector<packed_float3> tri_vnormal;
device_vector<packed_uint3> tri_vindex;
device_vector<uint> tri_patch;
device_vector<float2> tri_patch_uv;
device_vector<KernelCurve> curves;
device_vector<float4> curve_keys;
device_vector<KernelCurveSegment> curve_segments;
device_vector<uint> patches;
/* point-cloud */
device_vector<float4> points;
device_vector<uint> points_shader;
/* objects */
device_vector<KernelObject> objects;
device_vector<Transform> object_motion_pass;
device_vector<DecomposedTransform> object_motion;
device_vector<uint> object_flag;
device_vector<float> object_volume_step;
device_vector<uint> object_prim_offset;
/* cameras */
device_vector<DecomposedTransform> camera_motion;
/* attributes */
device_vector<AttributeMap> attributes_map;
device_vector<float> attributes_float;
device_vector<float2> attributes_float2;
device_vector<packed_float3> attributes_float3;
device_vector<float4> attributes_float4;
device_vector<uchar4> attributes_uchar4;
/* lights */
device_vector<KernelLightDistribution> light_distribution;
device_vector<KernelLight> lights;
device_vector<float2> light_background_marginal_cdf;
device_vector<float2> light_background_conditional_cdf;
/* light tree */
device_vector<KernelLightTreeNode> light_tree_nodes;
device_vector<KernelLightTreeEmitter> light_tree_emitters;
device_vector<uint> light_to_tree;
device_vector<uint> object_to_tree;
device_vector<uint> object_lookup_offset;
device_vector<uint> triangle_to_tree;
/* particles */
device_vector<KernelParticle> particles;
/* shaders */
device_vector<int4> svm_nodes;
device_vector<KernelShader> shaders;
/* lookup tables */
device_vector<float> lookup_table;
/* integrator */
device_vector<float> sample_pattern_lut;
/* IES lights */
device_vector<float> ies_lights;
KernelData data;
DeviceScene(Device *device);
};
/* Scene Parameters */
class SceneParams {

View File

@ -72,7 +72,7 @@ class GHOST_ISystemPaths {
/**
* Add the file to the operating system most recently used files
*/
virtual void addToSystemRecentFiles(const char *filename) const = 0;
virtual void addToSystemRecentFiles(const char *filepath) const = 0;
private:
/** The one and only system paths. */

View File

@ -10,6 +10,9 @@
#include "GHOST_Context.hh"
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <epoxy/wgl.h>
# include <tchar.h>
#
@ -18,6 +21,8 @@
# endif
#endif
#include <epoxy/gl.h>
#include <cstdio>
#include <cstring>

View File

@ -11,8 +11,6 @@
#include "GHOST_IContext.hh"
#include "GHOST_Types.h"
#include <epoxy/gl.h>
#include <cstdlib> // for NULL
class GHOST_Context : public GHOST_IContext {

View File

@ -19,6 +19,8 @@
#include <Metal/Metal.h>
#include <QuartzCore/QuartzCore.h>
#include <epoxy/gl.h>
#include <cassert>
#include <vector>

View File

@ -47,5 +47,5 @@ class GHOST_SystemPaths : public GHOST_ISystemPaths {
/**
* Add the file to the operating system most recently used files
*/
virtual void addToSystemRecentFiles(const char *filename) const = 0;
virtual void addToSystemRecentFiles(const char *filepath) const = 0;
};

View File

@ -54,5 +54,5 @@ class GHOST_SystemPathsCocoa : public GHOST_SystemPaths {
/**
* Add the file to the operating system most recently used files
*/
void addToSystemRecentFiles(const char *filename) const;
void addToSystemRecentFiles(const char *filepath) const;
};

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2010 Blender Foundation */
#import <AppKit/NSDocumentController.h>
#import <Foundation/Foundation.h>
#include "GHOST_Debug.hh"
@ -112,7 +113,10 @@ const char *GHOST_SystemPathsCocoa::getBinaryDir() const
return tempPath;
}
void GHOST_SystemPathsCocoa::addToSystemRecentFiles(const char *filename) const
void GHOST_SystemPathsCocoa::addToSystemRecentFiles(const char *filepath) const
{
/* TODO: implement for macOS */
@autoreleasepool {
NSURL *const file_url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:filepath]];
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:file_url];
}
}

View File

@ -52,5 +52,5 @@ class GHOST_SystemPathsUnix : public GHOST_SystemPaths {
/**
* Add the file to the operating system most recently used files
*/
void addToSystemRecentFiles(const char *filename) const;
void addToSystemRecentFiles(const char *filepath) const;
};

View File

@ -117,10 +117,10 @@ const char *GHOST_SystemPathsWin32::getBinaryDir() const
return NULL;
}
void GHOST_SystemPathsWin32::addToSystemRecentFiles(const char *filename) const
void GHOST_SystemPathsWin32::addToSystemRecentFiles(const char *filepath) const
{
/* SHARD_PATH resolves to SHARD_PATHA for non-UNICODE build */
UTF16_ENCODE(filename);
SHAddToRecentDocs(SHARD_PATHW, filename_16);
UTF16_UN_ENCODE(filename);
UTF16_ENCODE(filepath);
SHAddToRecentDocs(SHARD_PATHW, filepath_16);
UTF16_UN_ENCODE(filepath);
}

View File

@ -61,5 +61,5 @@ class GHOST_SystemPathsWin32 : public GHOST_SystemPaths {
/**
* Add the file to the operating system most recently used files
*/
void addToSystemRecentFiles(const char *filename) const;
void addToSystemRecentFiles(const char *filepath) const;
};

View File

@ -99,7 +99,12 @@ static bool use_xwayland_hack = false;
using namespace std;
GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_start_time(0)
GHOST_SystemX11::GHOST_SystemX11()
: GHOST_System(),
m_xkb_descr(nullptr),
m_start_time(0),
m_keyboard_vector{0},
m_keycode_last_repeat_key(uint(-1))
{
XInitThreads();
m_display = XOpenDisplay(nullptr);
@ -897,7 +902,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
#endif /* WITH_X11_XINPUT */
switch (xe->type) {
case Expose: {
XExposeEvent &xee = xe->xexpose;
const XExposeEvent &xee = xe->xexpose;
if (xee.count == 0) {
/* Only generate a single expose event
@ -909,7 +914,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
}
case MotionNotify: {
XMotionEvent &xme = xe->xmotion;
const XMotionEvent &xme = xe->xmotion;
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
@ -1235,7 +1240,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case ButtonPress:
case ButtonRelease: {
XButtonEvent &xbe = xe->xbutton;
const XButtonEvent &xbe = xe->xbutton;
GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp;
@ -1290,14 +1295,14 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* change of size, border, layer etc. */
case ConfigureNotify: {
// XConfigureEvent & xce = xe->xconfigure;
// const XConfigureEvent & xce = xe->xconfigure;
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
break;
}
case FocusIn:
case FocusOut: {
XFocusChangeEvent &xfe = xe->xfocus;
const XFocusChangeEvent &xfe = xe->xfocus;
/* TODO: make sure this is the correct place for activate/deactivate */
// printf("X: focus %s for window %d\n",
@ -1385,7 +1390,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* (really crossing between windows) since some window-managers
* also send grab/un-grab crossings for mouse-wheel events.
*/
XCrossingEvent &xce = xe->xcrossing;
const XCrossingEvent &xce = xe->xcrossing;
if (xce.mode == NotifyNormal) {
g_event = new GHOST_EventCursor(getMilliSeconds(),
GHOST_kEventCursorMove,
@ -2376,7 +2381,7 @@ class DialogData {
}
/* Is the mouse inside the given button */
bool isInsideButton(XEvent &e, uint button_num)
bool isInsideButton(const XEvent &e, uint button_num)
{
return (
(e.xmotion.y > int(height - padding_y - button_height)) &&

View File

@ -21,22 +21,21 @@ GHOST_Window::GHOST_Window(uint32_t width,
const bool wantStereoVisual,
const bool /*exclusive*/)
: m_drawingContextType(GHOST_kDrawingContextTypeNone),
m_userData(nullptr),
m_cursorVisible(true),
m_cursorGrab(GHOST_kGrabDisable),
m_cursorGrabAxis(GHOST_kAxisNone),
m_cursorGrabInitPos{0, 0},
m_cursorGrabAccumPos{0, 0},
m_cursorShape(GHOST_kStandardCursorDefault),
m_progressBarVisible(false),
m_canAcceptDragOperation(false),
m_isUnsavedChanges(false),
m_wantStereoVisual(wantStereoVisual),
m_nativePixelSize(1.0f),
m_context(new GHOST_ContextNone(false))
{
m_isUnsavedChanges = false;
m_canAcceptDragOperation = false;
m_progressBarVisible = false;
m_cursorGrabAccumPos[0] = 0;
m_cursorGrabAccumPos[1] = 0;
m_nativePixelSize = 1.0f;
m_fullScreen = state == GHOST_kWindowStateFullScreen;
if (m_fullScreen) {

View File

@ -55,7 +55,7 @@ struct BasisCache {
class CurvesGeometryRuntime {
public:
/** Implicit sharing user count for #CurvesGeometry::curve_offsets. */
ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
const ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
/**
* The cached number of curves with each type. Unlike other caches here, this is not computed

View File

@ -98,7 +98,7 @@ struct MeshRuntime {
std::mutex render_mutex;
/** Implicit sharing user count for #Mesh::poly_offset_indices. */
ImplicitSharingInfoHandle *poly_offsets_sharing_info;
const ImplicitSharingInfoHandle *poly_offsets_sharing_info;
/**
* A cache of bounds shared between data-blocks with unchanged positions. When changing positions

View File

@ -569,6 +569,27 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
return mesh_output;
}
static void set_rest_position(Mesh &mesh)
{
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh.attributes_for_write();
const AttributeReader positions = attributes.lookup<float3>("position");
attributes.remove("rest_position");
if (positions) {
if (positions.sharing_info && positions.varray.is_span()) {
attributes.add<float3>("rest_position",
ATTR_DOMAIN_POINT,
AttributeInitShared(positions.varray.get_internal_span().data(),
*positions.sharing_info));
}
else {
attributes.add<float3>(
"rest_position", ATTR_DOMAIN_POINT, AttributeInitVArray(positions.varray));
}
}
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
@ -657,20 +678,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
}
MutableAttributeAccessor attributes = mesh_final->attributes_for_write();
const AttributeReader positions = attributes.lookup<float3>("position");
if (positions) {
if (positions.sharing_info && positions.varray.is_span()) {
attributes.add<float3>("rest_position",
ATTR_DOMAIN_POINT,
AttributeInitShared(positions.varray.get_internal_span().data(),
*positions.sharing_info));
}
else {
attributes.add<float3>(
"rest_position", ATTR_DOMAIN_POINT, AttributeInitVArray(positions.varray));
}
}
set_rest_position(*mesh_final);
}
/* Apply all leading deform modifiers. */
@ -1194,6 +1202,14 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Clear errors before evaluation. */
BKE_modifiers_clear_errors(ob);
if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
if (mesh_final == nullptr) {
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, nullptr, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
}
set_rest_position(*mesh_final);
}
for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);

View File

@ -2376,9 +2376,9 @@ class CustomDataLayerImplicitSharing : public ImplicitSharingInfo {
};
/** Create a #ImplicitSharingInfo that takes ownership of the data. */
static ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
const void *data,
const int totelem)
static const ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
const void *data,
const int totelem)
{
return MEM_new<CustomDataLayerImplicitSharing>(__func__, data, totelem, type);
}

View File

@ -431,7 +431,9 @@ CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t
/* expand array */
newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
if (cdf->totlayer > 0) {
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
}
cdf->layer = newlayer;
cdf->totlayer++;

View File

@ -63,20 +63,10 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
MLoopTri *mlt_a = mlt++;
create_tri(0, 2, 3);
MLoopTri *mlt_b = mlt;
if (UNLIKELY(face_normal ? is_quad_flip_v3_first_third_fast_with_normal(
/* Simpler calculation (using the normal). */
positions[corner_verts[mlt_a->tri[0]]],
positions[corner_verts[mlt_a->tri[1]]],
positions[corner_verts[mlt_a->tri[2]]],
positions[corner_verts[mlt_b->tri[2]]],
normal_precalc) :
is_quad_flip_v3_first_third_fast(
/* Expensive calculation (no normal). */
positions[corner_verts[mlt_a->tri[0]]],
positions[corner_verts[mlt_a->tri[1]]],
positions[corner_verts[mlt_a->tri[2]]],
positions[corner_verts[mlt_b->tri[2]]]))) {
if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[mlt_a->tri[0]]],
positions[corner_verts[mlt_a->tri[1]]],
positions[corner_verts[mlt_a->tri[2]]],
positions[corner_verts[mlt_b->tri[2]]]))) {
/* Flip out of degenerate 0-2 state. */
mlt_a->tri[2] = mlt_b->tri[2];
mlt_b->tri[0] = mlt_a->tri[1];

View File

@ -110,11 +110,11 @@ void *resize_trivial_array_impl(void *old_data,
int64_t old_size,
int64_t new_size,
int64_t alignment,
ImplicitSharingInfo **sharing_info);
const ImplicitSharingInfo **sharing_info);
void *make_trivial_data_mutable_impl(void *old_data,
int64_t size,
int64_t alignment,
ImplicitSharingInfo **sharing_info);
const ImplicitSharingInfo **sharing_info);
} // namespace detail
@ -124,9 +124,9 @@ void *make_trivial_data_mutable_impl(void *old_data,
*/
template<typename T>
void copy_shared_pointer(T *src_ptr,
ImplicitSharingInfo *src_sharing_info,
const ImplicitSharingInfo *src_sharing_info,
T **r_dst_ptr,
ImplicitSharingInfo **r_dst_sharing_info)
const ImplicitSharingInfo **r_dst_sharing_info)
{
*r_dst_ptr = src_ptr;
*r_dst_sharing_info = src_sharing_info;
@ -139,7 +139,7 @@ void copy_shared_pointer(T *src_ptr,
/**
* Remove this reference to the shared data and remove dangling pointers.
*/
template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **sharing_info)
template<typename T> void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
{
if (*sharing_info) {
BLI_assert(*data != nullptr);
@ -153,13 +153,15 @@ template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **shari
* Create an implicit sharing object that takes ownership of the data, allowing it to be shared.
* When it is no longer used, the data is freed with #MEM_freeN, so it must be a trivial type.
*/
ImplicitSharingInfo *info_for_mem_free(void *data);
const ImplicitSharingInfo *info_for_mem_free(void *data);
/**
* Make data mutable (single-user) if it is shared. For trivially-copyable data only.
*/
template<typename T>
void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, const int64_t size)
void make_trivial_data_mutable(T **data,
const ImplicitSharingInfo **sharing_info,
const int64_t size)
{
*data = static_cast<T *>(
detail::make_trivial_data_mutable_impl(*data, sizeof(T) * size, alignof(T), sharing_info));
@ -171,7 +173,7 @@ void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, con
*/
template<typename T>
void resize_trivial_array(T **data,
ImplicitSharingInfo **sharing_info,
const ImplicitSharingInfo **sharing_info,
int64_t old_size,
int64_t new_size)
{

View File

@ -145,11 +145,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3]);
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
const float normal[3]);
/** \} */

View File

@ -26,7 +26,7 @@ class MEMFreeImplicitSharing : public ImplicitSharingInfo {
}
};
ImplicitSharingInfo *info_for_mem_free(void *data)
const ImplicitSharingInfo *info_for_mem_free(void *data)
{
return MEM_new<MEMFreeImplicitSharing>(__func__, data);
}
@ -36,7 +36,7 @@ namespace detail {
void *make_trivial_data_mutable_impl(void *old_data,
const int64_t size,
const int64_t alignment,
ImplicitSharingInfo **sharing_info)
const ImplicitSharingInfo **sharing_info)
{
if (!old_data) {
BLI_assert(size == 0);
@ -59,7 +59,7 @@ void *resize_trivial_array_impl(void *old_data,
const int64_t old_size,
const int64_t new_size,
const int64_t alignment,
ImplicitSharingInfo **sharing_info)
const ImplicitSharingInfo **sharing_info)
{
if (new_size == 0) {
if (*sharing_info) {
@ -79,7 +79,8 @@ void *resize_trivial_array_impl(void *old_data,
BLI_assert(old_size != 0);
if ((*sharing_info)->is_mutable()) {
if (auto *info = dynamic_cast<MEMFreeImplicitSharing *>(*sharing_info)) {
if (auto *info = const_cast<MEMFreeImplicitSharing *>(
dynamic_cast<const MEMFreeImplicitSharing *>(*sharing_info))) {
/* If the array was allocated with the MEM allocator, we can use realloc directly, which
* could theoretically give better performance if the data can be reused in place. */
void *new_data = static_cast<int *>(MEM_reallocN(old_data, new_size));

View File

@ -5889,6 +5889,9 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
const float v3[3],
const float v4[3])
{
/* NOTE: if the faces normal has been calculated it's possible to simplify the following checks,
* however this means the solution may be different depending on the existence of normals
* causing tessellation to be "unstable" depending on the existence of normals, see #106469. */
float d_12[3], d_13[3], d_14[3];
float cross_a[3], cross_b[3];
sub_v3_v3v3(d_12, v2, v1);
@ -5899,19 +5902,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
return dot_v3v3(cross_a, cross_b) > 0.0f;
}
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
const float v2[3],
const float v3[3],
const float v4[3],
const float normal[3])
{
float dir_v3v1[3], tangent[3];
sub_v3_v3v3(dir_v3v1, v3, v1);
cross_v3_v3v3(tangent, dir_v3v1, normal);
const float dot = dot_v3v3(v1, tangent);
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
}
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
{
BLI_ASSERT_UNIT_V3(tan_l);

View File

@ -2728,7 +2728,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
e[k + 1] += 1.0f;
}
e[k] = -e[k];
if ((k + 1 < m) & (e[k] != 0.0f)) {
if ((k + 1 < m) && (e[k] != 0.0f)) {
float invek1;
/* Apply the transformation. */
@ -2812,7 +2812,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
/* If required, generate V. */
for (k = n - 1; k >= 0; k--) {
if ((k < nrt) & (e[k] != 0.0f)) {
if ((k < nrt) && (e[k] != 0.0f)) {
for (j = k + 1; j < nu; j++) {
float t = 0;
for (i = k + 1; i < n; i++) {

View File

@ -1962,17 +1962,19 @@ static Face *cdt_tri_as_imesh_face(
return facep;
}
/* Like BLI_math's is_quad_flip_v3_first_third_fast_with_normal, with const double3's. */
/* Like BLI_math's is_quad_flip_v3_first_third_fast, with const double3's. */
static bool is_quad_flip_first_third(const double3 &v1,
const double3 &v2,
const double3 &v3,
const double3 &v4,
const double3 &normal)
const double3 &v4)
{
double3 dir_v3v1 = v3 - v1;
double3 tangent = math::cross(dir_v3v1, normal);
double dot = math::dot(v1, tangent);
return (math::dot(v4, tangent) >= dot) || (math::dot(v2, tangent) <= dot);
const double3 d_12 = v2 - v1;
const double3 d_13 = v3 - v1;
const double3 d_14 = v4 - v1;
const double3 cross_a = math::cross(d_12, d_13);
const double3 cross_b = math::cross(d_14, d_13);
return math::dot(cross_a, cross_b) > 0.0f;
}
/**
@ -2008,7 +2010,7 @@ static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
int eo_23 = f->edge_orig[2];
int eo_30 = f->edge_orig[3];
Face *f0, *f1;
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co, f->plane->norm))) {
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co))) {
f0 = arena->add_face({v0, v1, v3}, f->orig, {eo_01, -1, eo_30}, {false, false, false});
f1 = arena->add_face({v1, v2, v3}, f->orig, {eo_12, eo_23, -1}, {false, false, false});
}

View File

@ -37,22 +37,16 @@
#include "MEM_guardedalloc.h"
/* Declarations */
/* Declarations. */
static int BLI_path_unc_prefix_len(const char *path);
#ifdef WIN32
/**
* Return true if the path is absolute ie starts with a drive specifier
* (eg A:\) or is a UNC path.
*/
static bool BLI_path_is_abs(const char *name);
static bool BLI_path_is_abs_win32(const char *name);
#endif /* WIN32 */
// #define DEBUG_STRSIZE
/* implementation */
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_digits_len)
{
uint nums = 0, nume = 0;
@ -102,9 +96,8 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
strcpy(tail, string + name_end);
}
if (head) {
/* name_end points to last character of head,
* make it +1 so null-terminator is nicely placed
*/
/* Name_end points to last character of head,
* make it +1 so null-terminator is nicely placed. */
BLI_strncpy(head, string, name_end + 1);
}
if (r_digits_len) {
@ -119,8 +112,6 @@ void BLI_path_sequence_encode(
BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
@ -131,19 +122,18 @@ void BLI_path_normalize(const char *relabase, char *path)
else {
if (path[0] == '/' && path[1] == '/') {
if (path[2] == '\0') {
return; /* path is "//" - can't clean it */
return; /* Path is `//` - can't clean it. */
}
path = path + 2; /* leave the initial "//" untouched */
path = path + 2; /* Leave the initial `//` untouched. */
}
}
/* Note
* memmove(start, eind, strlen(eind) + 1);
/* NOTE(@ideasman42):
* `memmove(start, eind, strlen(eind) + 1);`
* is the same as
* strcpy(start, eind);
* except strcpy should not be used because there is overlap,
* so use memmove's slightly more obscure syntax - Campbell
*/
* `strcpy(start, eind);`
* except `strcpy` should not be used because there is overlap,
* so use `memmove` 's slightly more obscure syntax. */
#ifdef WIN32
@ -152,8 +142,8 @@ void BLI_path_normalize(const char *relabase, char *path)
memmove(start, eind, strlen(eind) + 1);
}
/* remove two consecutive backslashes, but skip the UNC prefix,
* which needs to be preserved */
/* Remove two consecutive backslashes, but skip the UNC prefix,
* which needs to be preserved. */
while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) {
eind = start + strlen("\\\\") - 1;
memmove(start, eind, strlen(eind) + 1);
@ -179,21 +169,21 @@ void BLI_path_normalize(const char *relabase, char *path)
#else
while ((start = strstr(path, "/./"))) {
eind = start + (3 - 1) /* strlen("/./") - 1 */;
eind = start + (3 - 1) /* `strlen("/./") - 1` */;
memmove(start, eind, strlen(eind) + 1);
}
while ((start = strstr(path, "//"))) {
eind = start + (2 - 1) /* strlen("//") - 1 */;
eind = start + (2 - 1) /* `strlen("//") - 1` */;
memmove(start, eind, strlen(eind) + 1);
}
while ((start = strstr(path, "/../"))) {
a = start - path - 1;
if (a > 0) {
/* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
while (a > 0 && path[a] != '/') { /* find start of <parent> */
/* `<prefix>/<parent>/../<postfix> => <prefix>/<postfix>`. */
eind = start + (4 - 1) /* `strlen("/../") - 1` */; /* Strip "/.." and keep last "/". */
while (a > 0 && path[a] != '/') { /* Find start of `<parent>`. */
a--;
}
memmove(path + a, eind, strlen(eind) + 1);
@ -253,7 +243,7 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
/* Forbid only dots. */
for (fn = fname; *fn == '.'; fn++) {
/* pass */
/* Pass. */
}
if (*fn == '\0') {
*fname = '_';
@ -279,15 +269,14 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
/* Check for forbidden names - not we have to check all combination
* of upper and lower cases, hence the usage of lower_fname
* (more efficient than using BLI_strcasestr repeatedly). */
* (more efficient than using #BLI_strcasestr repeatedly). */
BLI_str_tolower_ascii(lower_fname, len);
for (iname = invalid_names; *iname; iname++) {
if (strstr(lower_fname, *iname) == lower_fname) {
const size_t iname_len = strlen(*iname);
/* Only invalid if the whole name is made of the invalid chunk, or it has an
* (assumed extension) dot just after. This means it will also catch 'valid'
* names like 'aux.foo.bar', but should be
* good enough for us! */
* (assumed extension) dot just after. This means it will also catch *valid*
* names like `aux.foo.bar`, but should be good enough for us! */
if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
*fname = '_';
changed = true;
@ -311,14 +300,14 @@ bool BLI_filename_make_safe(char *fname)
bool BLI_path_make_safe(char *path)
{
/* Simply apply #BLI_filename_make_safe() over each component of the path.
* Luckily enough, same 'safe' rules applies to file & directory names. */
* Luckily enough, same *safe* rules applies to file & directory names. */
char *curr_slash, *curr_path = path;
bool changed = false;
bool skip_first = false;
#ifdef WIN32
if (BLI_path_is_abs(path)) {
/* Do not make safe 'C:' in 'C:\foo\bar'... */
if (BLI_path_is_abs_win32(path)) {
/* Do not make safe `C:` in `C:\foo\bar`. */
skip_first = true;
}
#endif
@ -361,7 +350,7 @@ static int BLI_path_unc_prefix_len(const char *path)
{
if (BLI_path_is_unc(path)) {
if ((path[2] == '?') && (path[3] == '\\')) {
/* we assume long UNC path like \\?\server\share\folder etc... */
/* We assume long UNC path like `\\?\server\share\folder` etc. */
return 4;
}
@ -374,10 +363,14 @@ static int BLI_path_unc_prefix_len(const char *path)
#if defined(WIN32)
/**
* Return true if the path is absolute ie starts with a drive specifier
* (eg A:\) or is a UNC path.
* Return true if the path is an absolute path on a WIN32 file-system, it either:
* - Starts with a drive specifier* (eg `A:\`).
* - Is a UNC path.
*
* \note Not to be confused with the opposite of #BLI_path_is_rel which checks for the
* Blender specific convention of using `//` prefix for blend-file relative paths.
*/
static bool BLI_path_is_abs(const char *name)
static bool BLI_path_is_abs_win32(const char *name)
{
return (name[1] == ':' && ELEM(name[2], '\\', '/')) || BLI_path_is_unc(name);
}
@ -409,9 +402,10 @@ static void BLI_path_unc_to_short(wchar_t *unc)
wchar_t tmp[PATH_MAX];
int len = wcslen(unc);
/* convert:
* \\?\UNC\server\share\folder\... to \\server\share\folder\...
* \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
/* Convert:
* - `\\?\UNC\server\share\folder\...` to `\\server\share\folder\...`
* - `\\?\C:\` to `C:\`
* - `\\?\C:\folder\...` to `C:\folder\...`
*/
if ((len > 3) && (unc[0] == L'\\') && (unc[1] == L'\\') && (unc[2] == L'?') &&
ELEM(unc[3], L'\\', L'/')) {
@ -450,18 +444,18 @@ void BLI_path_rel(char *file, const char *relfile)
char temp[FILE_MAX];
char res[FILE_MAX];
/* if file is already relative, bail out */
/* If file is already relative, bail out. */
if (BLI_path_is_rel(file)) {
return;
}
/* also bail out if relative path is not set */
/* Also bail out if relative path is not set. */
if (relfile[0] == '\0') {
return;
}
#ifdef WIN32
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs_win32(relfile)) {
char *ptemp;
/* Fix missing volume name in relative base,
* can happen with old `recent-files.txt` files. */
@ -479,12 +473,12 @@ void BLI_path_rel(char *file, const char *relfile)
if (BLI_strnlen(file, 3) > 2) {
bool is_unc = BLI_path_is_unc(file);
/* Ensure paths are both UNC paths or are both drives */
/* Ensure paths are both UNC paths or are both drives. */
if (BLI_path_is_unc(temp) != is_unc) {
return;
}
/* Ensure both UNC paths are on the same share */
/* Ensure both UNC paths are on the same share. */
if (is_unc) {
int off;
int slash = 0;
@ -509,16 +503,16 @@ void BLI_path_rel(char *file, const char *relfile)
BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
/* remove /./ which confuse the following slash counting... */
/* Remove `/./` which confuse the following slash counting. */
BLI_path_normalize(NULL, file);
BLI_path_normalize(NULL, temp);
/* the last slash in the file indicates where the path part ends */
/* The last slash in the file indicates where the path part ends. */
lslash = BLI_path_slash_rfind(temp);
if (lslash) {
/* find the prefix of the filename that is equal for both filenames.
* This is replaced by the two slashes at the beginning */
/* Find the prefix of the filename that is equal for both filenames.
* This is replaced by the two slashes at the beginning. */
const char *p = temp;
const char *q = file;
char *r = res;
@ -532,16 +526,14 @@ void BLI_path_rel(char *file, const char *relfile)
p++;
q++;
/* don't search beyond the end of the string
* in the rare case they match */
/* Don't search beyond the end of the string in the rare case they match. */
if ((*p == '\0') || (*q == '\0')) {
break;
}
}
/* we might have passed the slash when the beginning of a dir matches
* so we rewind. Only check on the actual filename
*/
/* We might have passed the slash when the beginning of a dir matches
* so we rewind. Only check on the actual filename. */
if (*q != '/') {
while ((q >= file) && (*q != '/')) {
q--;
@ -557,11 +549,10 @@ void BLI_path_rel(char *file, const char *relfile)
r += BLI_strcpy_rlen(r, "//");
/* p now points to the slash that is at the beginning of the part
/* `p` now points to the slash that is at the beginning of the part
* where the path is different from the relative path.
* We count the number of directories we need to go up in the
* hierarchy to arrive at the common 'prefix' of the path
*/
* hierarchy to arrive at the common prefix of the path. */
if (p < temp) {
p = temp;
}
@ -572,7 +563,7 @@ void BLI_path_rel(char *file, const char *relfile)
p++;
}
/* don't copy the slash at the beginning */
/* Don't copy the slash at the beginning. */
r += BLI_strncpy_rlen(r, q + 1, FILE_MAX - (r - res));
#ifdef WIN32
@ -627,7 +618,7 @@ bool BLI_path_parent_dir(char *path)
return false;
}
if (tail_len == 1) {
/* Last path is ".", as normalize should remove this, it's safe to assume failure.
/* Last path is `.`, as normalize should remove this, it's safe to assume failure.
* This happens when the input a single period (possibly with slashes before or after). */
if (path[tail_ofs] == '.') {
return false;
@ -646,7 +637,7 @@ bool BLI_path_parent_dir_until_exists(char *dir)
/* Loop as long as cur path is not a dir, and we can get a parent path. */
while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_path_parent_dir(dir))) {
/* pass */
/* Pass. */
}
return (valid_path && dir[0]);
}
@ -659,11 +650,11 @@ bool BLI_path_parent_dir_until_exists(char *dir)
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
{
uint ch_sta, ch_end, i;
/* Insert current frame: file### -> file001 */
/* Insert current frame: `file###` -> `file001`. */
ch_sta = ch_end = 0;
for (i = 0; path[i] != '\0'; i++) {
if (ELEM(path[i], '\\', '/')) {
ch_end = 0; /* this is a directory name, don't use any hashes we found */
ch_end = 0; /* This is a directory name, don't use any hashes we found. */
}
else if (path[i] == '#') {
ch_sta = i;
@ -671,9 +662,9 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end)
while (path[ch_end] == '#') {
ch_end++;
}
i = ch_end - 1; /* keep searching */
i = ch_end - 1; /* Keep searching. */
/* don't break, there may be a slash after this that invalidates the previous #'s */
/* Don't break, there may be a slash after this that invalidates the previous #'s. */
}
}
@ -718,7 +709,7 @@ bool BLI_path_frame(char *path, int frame, int digits)
ensure_digits(path, digits);
}
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
char tmp[FILE_MAX];
BLI_snprintf(
tmp, sizeof(tmp), "%.*s%.*d%s", ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
@ -736,7 +727,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
ensure_digits(path, digits);
}
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
char tmp[FILE_MAX];
BLI_snprintf(tmp,
sizeof(tmp),
@ -812,8 +803,8 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen)
bool BLI_path_frame_check_chars(const char *path)
{
int ch_sta, ch_end; /* dummy args */
return stringframe_chars(path, &ch_sta, &ch_end);
int ch_sta_dummy, ch_end_dummy;
return stringframe_chars(path, &ch_sta_dummy, &ch_end_dummy);
}
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
@ -860,16 +851,14 @@ bool BLI_path_abs(char *path, const char *basepath)
char base[FILE_MAX];
#ifdef WIN32
/* without this: "" --> "C:\" */
/* Without this, an empty string converts to: `C:\` */
if (*path == '\0') {
return wasrelative;
}
/* we are checking here if we have an absolute path that is not in the current
* blend file as a lib main - we are basically checking for the case that a
* UNIX root '/' is passed.
*/
if (!wasrelative && !BLI_path_is_abs(path)) {
/* We are checking here if we have an absolute path that is not in the current `.blend` file
* as a lib main - we are basically checking for the case that a UNIX root `/` is passed. */
if (!wasrelative && !BLI_path_is_abs_win32(path)) {
char *p = path;
BLI_windows_get_default_root_dir(tmp);
/* Get rid of the slashes at the beginning of the path. */
@ -892,7 +881,7 @@ bool BLI_path_abs(char *path, const char *basepath)
* `C:\foo.JPG` -> `/c/foo.JPG` */
if (isalpha(tmp[0]) && (tmp[1] == ':') && ELEM(tmp[2], '\\', '/')) {
tmp[1] = tolower(tmp[0]); /* Replace ':' with drive-letter. */
tmp[1] = tolower(tmp[0]); /* Replace `:` with drive-letter. */
tmp[0] = '/';
/* `\` the slash will be converted later. */
}
@ -916,28 +905,28 @@ bool BLI_path_abs(char *path, const char *basepath)
const char *lslash;
BLI_strncpy(base, basepath, sizeof(base));
/* file component is ignored, so don't bother with the trailing slash */
/* File component is ignored, so don't bother with the trailing slash. */
BLI_path_normalize(NULL, base);
lslash = BLI_path_slash_rfind(base);
BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
if (lslash) {
/* length up to and including last "/" */
/* Length up to and including last `/`. */
const int baselen = (int)(lslash - base) + 1;
/* use path for temp storage here, we copy back over it right away */
BLI_strncpy(path, tmp + 2, FILE_MAX); /* strip "//" */
/* Use path for temp storage here, we copy back over it right away. */
BLI_strncpy(path, tmp + 2, FILE_MAX); /* Strip `//` prefix. */
memcpy(tmp, base, baselen); /* prefix with base up to last "/" */
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* append path after "//" */
BLI_strncpy(path, tmp, FILE_MAX); /* return as result */
memcpy(tmp, base, baselen); /* Prefix with base up to last `/`. */
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* Append path after `//`. */
BLI_strncpy(path, tmp, FILE_MAX); /* Return as result. */
}
else {
/* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
/* Base doesn't seem to be a directory, ignore it and just strip `//` prefix on path. */
BLI_strncpy(path, tmp + 2, FILE_MAX);
}
}
else {
/* base ignored */
/* Base ignored. */
BLI_strncpy(path, tmp, FILE_MAX);
}
@ -948,7 +937,7 @@ bool BLI_path_abs(char *path, const char *basepath)
BLI_str_replace_char(path + 2, '/', '\\');
#endif
/* ensure this is after correcting for path switch */
/* Ensure this is after correcting for path switch. */
BLI_path_normalize(NULL, path);
return wasrelative;
@ -960,7 +949,7 @@ bool BLI_path_is_abs_from_cwd(const char *path)
const int path_len_clamp = BLI_strnlen(path, 3);
#ifdef WIN32
if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
if ((path_len_clamp >= 3 && BLI_path_is_abs_win32(path)) || BLI_path_is_unc(path)) {
is_abs = true;
}
#else
@ -979,7 +968,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
if (!BLI_path_is_abs_from_cwd(path)) {
char cwd[FILE_MAX];
/* in case the full path to the blend isn't used */
/* In case the full path to the blend isn't used. */
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
char origpath[FILE_MAX];
BLI_strncpy(origpath, path, FILE_MAX);
@ -996,7 +985,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
#ifdef _WIN32
/**
* Tries appending each of the semicolon-separated extensions in the PATHEXT
* Tries appending each of the semicolon-separated extensions in the `PATHEXT`
* environment variable (Windows-only) onto `name` in turn until such a file is found.
* Returns success/failure.
*/
@ -1007,7 +996,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
type = BLI_exists(name);
if ((type == 0) || S_ISDIR(type)) {
/* typically 3-5, ".EXE", ".BAT"... etc */
/* Typically 3-5, ".EXE", ".BAT"... etc. */
const int ext_max = 12;
const char *ext = BLI_getenv("PATHEXT");
if (ext) {
@ -1016,7 +1005,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
char *filename_ext;
const char *ext_next;
/* null terminated in the loop */
/* Null terminated in the loop. */
memcpy(filename, name, name_len);
filename_ext = filename + name_len;
@ -1101,11 +1090,9 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
void BLI_setenv(const char *env, const char *val)
{
/* free windows */
#if (defined(_WIN32) || defined(_WIN64))
/* MS-Windows. */
uputenv(env, val);
#else
/* Linux/macOS/BSD */
if (val) {
@ -1158,7 +1145,7 @@ bool BLI_make_existing_file(const char *name)
char di[FILE_MAX];
BLI_split_dir_part(name, di, sizeof(di));
/* make if the dir doesn't exist */
/* Make if the dir doesn't exist. */
return BLI_dir_create_recursive(di);
}
@ -1260,7 +1247,7 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
/* Non-wildcard char, we can break here and consider the pattern valid. */
return false;
}
/* So far, only wildcards in last group of the pattern... */
/* So far, only wildcards in last group of the pattern. */
only_wildcards = true;
}
/* Only one group in the pattern, so even if its only made of wildcard(s),
@ -1352,7 +1339,7 @@ void BLI_split_dirfile(
if (dir) {
if (lslash) {
/* +1 to include the slash and the last char */
/* +1 to include the slash and the last char. */
BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1));
}
else {
@ -1429,7 +1416,7 @@ size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__
}
if (dirlen >= maxlen) {
return dirlen; /* fills the path */
return dirlen; /* Fills the path. */
}
return dirlen + BLI_strncpy_rlen(dst + dirlen, file, maxlen - dirlen);
@ -1470,7 +1457,7 @@ size_t BLI_path_join_array(char *__restrict dst,
}
#ifdef WIN32
/* Special case "//" for relative paths, don't use separator #SEP
/* Special case `//` for relative paths, don't use separator #SEP
* as this has a special meaning on both WIN32 & UNIX.
* Without this check joining `"//", "path"`. results in `"//\path"`. */
if (ofs != 0) {
@ -1519,7 +1506,7 @@ size_t BLI_path_join_array(char *__restrict dst,
}
if (len != 0) {
/* the very first path may have a slash at the end */
/* The very first path may have a slash at the end. */
if (ofs && !BLI_path_slash_is_native_compat(dst[ofs - 1])) {
dst[ofs++] = SEP;
if (ofs == dst_last) {
@ -1574,7 +1561,7 @@ static bool path_name_at_index_forward(const char *__restrict path,
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
if (prev + 1 != i) {
prev += 1;
/* Skip '/./' (behave as if they don't exist). */
/* Skip `/./` (behave as if they don't exist). */
if (!((i - prev == 1) && (prev != 0) && (path[prev] == '.'))) {
if (index_step == index) {
*r_offset = prev;
@ -1609,7 +1596,7 @@ static bool path_name_at_index_backward(const char *__restrict path,
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
if (prev - 1 != i) {
i += 1;
/* Skip '/./' (behave as if they don't exist). */
/* Skip `/./` (behave as if they don't exist). */
if (!((prev - i == 1) && (i != 0) && (path[i] == '.'))) {
if (index_step == index) {
*r_offset = i;
@ -1644,7 +1631,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
char containee_native[PATH_MAX];
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
* longer than PATH_MAX and the result is ill-defined. */
* longer than #PATH_MAX and the result is ill-defined. */
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
BLI_strncpy(containee_native, containee_path, PATH_MAX);

View File

@ -81,11 +81,8 @@ BLI_INLINE void bmesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3],
efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
}
if (UNLIKELY(is_quad_flip_v3_first_third_fast_with_normal(l_ptr_a[0]->v->co,
l_ptr_a[1]->v->co,
l_ptr_a[2]->v->co,
l_ptr_b[2]->v->co,
efa->no))) {
if (UNLIKELY(is_quad_flip_v3_first_third_fast(
l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
/* Flip out of degenerate 0-2 state. */
l_ptr_a[2] = l_ptr_b[2];
l_ptr_b[0] = l_ptr_a[1];

View File

@ -166,7 +166,8 @@ void DepthOfField::sync()
/* Now that we know the maximum render resolution of every view, using depth of field, allocate
* the reduced buffers. Color needs to be signed format here. See note in shader for
* explanation. Do not use texture pool because of needs mipmaps. */
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
reduced_color_tx_.ensure_2d(GPU_RGBA16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
reduced_coc_tx_.ensure_2d(GPU_R16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
reduced_color_tx_.ensure_mip_views();

View File

@ -24,7 +24,8 @@ void HiZBuffer::sync()
int2 hiz_extent = math::ceil_to_multiple(render_extent, int2(1u << (HIZ_MIP_COUNT - 1)));
int2 dispatch_size = math::divide_ceil(hiz_extent, int2(HIZ_GROUP_SIZE));
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
hiz_tx_.ensure_2d(GPU_R32F, hiz_extent, usage, nullptr, HIZ_MIP_COUNT);
hiz_tx_.ensure_mip_views();
GPU_texture_mipmap_mode(hiz_tx_, true, false);

View File

@ -628,7 +628,7 @@ struct LightData {
float radius_squared;
/** NOTE: It is ok to use float3 here. A float is declared right after it.
* float3 is also aligned to 16 bytes. */
float3 color;
packed_float3 color;
/** Light Type. */
eLightType type;
/** Spot size. Aligned to size of float2. */

View File

@ -257,7 +257,8 @@ class ShadowModule {
/** Tile to physical page mapping. This is an array texture with one layer per view. */
Texture render_map_tx_ = {"ShadowRenderMap",
GPU_R32UI,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
int2(SHADOW_TILEMAP_RES),
64,
nullptr,

View File

@ -12,7 +12,7 @@ void main()
/* Display backfacing surfels with a transparent checkerboard grid. */
if (!gl_FrontFacing) {
ivec2 grid_uv = ivec2(gl_FragCoord) / 5;
ivec2 grid_uv = ivec2(gl_FragCoord.xy) / 5;
if ((grid_uv.x + grid_uv.y) % 2 == 0) {
discard;
return;

View File

@ -45,7 +45,8 @@ void main()
case LIGHT_RECT:
case LIGHT_ELLIPSE:
case LIGHT_POINT:
sphere = Sphere(light._position, light.influence_radius_max);
sphere.center = light._position;
sphere.radius = light.influence_radius_max;
break;
}

View File

@ -110,7 +110,7 @@ bool debug_tilemaps(vec3 P, LightData light)
out_color_add = vec4(debug_tile_state_color(tile), 0.0);
out_color_mul = vec4(0.0);
if (ivec2(gl_FragCoord.xy) == ivec2(0)) {
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
drw_print(light.object_mat);
}
return true;

View File

@ -25,7 +25,9 @@
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
/* TODO(@fclem): Implement. */
#define assert(check)
#ifndef GPU_METAL
# define assert(check)
#endif
/* Remove page ownership from the tile and append it to the cache. */
void shadow_page_free(inout ShadowTileData tile)

View File

@ -45,7 +45,7 @@ float pixel_size_at(float linear_depth)
if (is_persp) {
pixel_size *= max(0.01, linear_depth);
}
return pixel_size * exp2(fb_lod);
return pixel_size * exp2(float(fb_lod));
}
void step_bounding_sphere(vec3 vs_near_plane,
@ -117,6 +117,7 @@ void main()
step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
vec3 vP = point_world_to_view(P);
shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod));
shadow_tag_usage(
vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(float(fb_lod)));
}
}

View File

@ -17,7 +17,7 @@ void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP)
{
vec3 vP = point_world_to_view(P);
float inflate_scale = pixel_world_radius * exp2(fb_lod);
float inflate_scale = pixel_world_radius * exp2(float(fb_lod));
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
if (is_persp) {
inflate_scale *= -vP.z;

View File

@ -45,6 +45,8 @@ void write_depth(ivec2 texel_co, const int lod, ivec2 tile_co, float depth)
/* Quantization bias. Equivalent to nextafter in C without all the safety. 1 is not enough. */
u_depth += 2;
/* TOOD(Metal): For Metal, textures will need to be viewed as buffers to workaround missing image
* atomics support. */
imageAtomicMin(shadow_atlas_img, out_texel, u_depth);
}

View File

@ -8,6 +8,11 @@
/** \name Shadow pipeline
* \{ */
/* NOTE(Metal): As this is implemented using a fundamental data type, this needs to be specified
* explicitly as uint for code generation, as the MSLShaderGenerator needs to be able to
* distinguish between classes and fundamental types during code generation. */
#define SHADOW_TILE_DATA_PACKED "uint"
GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear)
.do_static_compilation(true)
.local_group_size(SHADOW_CLIPMAP_GROUP_SIZE)
@ -34,7 +39,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_init)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
.additional_info("eevee_shared")
@ -44,7 +49,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_update)
.do_static_compilation(true)
.local_group_size(1, 1, 1)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(5, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
.storage_buf(6, Qualifier::READ, "uint", "resource_ids_buf[]")
.additional_info("eevee_shared", "draw_view", "draw_view_culling")
@ -55,7 +60,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
.local_group_size(SHADOW_DEPTH_SCAN_GROUP_SIZE, SHADOW_DEPTH_SCAN_GROUP_SIZE)
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
.additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data")
.compute_source("eevee_shadow_tag_usage_comp.glsl");
@ -71,7 +76,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
.vertex_in(0, Type::VEC3, "pos")
.storage_buf(4, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
.push_constant(Type::FLOAT, "pixel_world_radius")
.push_constant(Type::IVEC2, "fb_resolution")
@ -91,7 +96,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_mask)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.storage_buf(0, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.additional_info("eevee_shared")
.compute_source("eevee_shadow_page_mask_comp.glsl");
@ -99,7 +104,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_free)
.do_static_compilation(true)
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
@ -110,7 +115,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_defrag)
.do_static_compilation(true)
.local_group_size(1)
.typedef_source("draw_shader_shared.h")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
@ -124,7 +129,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_allocate)
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
.typedef_source("draw_shader_shared.h")
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
@ -137,7 +142,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
.typedef_source("draw_shader_shared.h")
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
.storage_buf(3, Qualifier::WRITE, "ViewMatrices", "view_infos_buf[64]")
.storage_buf(4, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
@ -183,11 +188,12 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_debug)
.do_static_compilation(true)
.additional_info("eevee_shared")
.storage_buf(5, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ, "ShadowTileDataPacked", "tiles_buf[]")
.storage_buf(6, Qualifier::READ, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.fragment_out(0, Type::VEC4, "out_color_add", DualBlend::SRC_0)
.fragment_out(0, Type::VEC4, "out_color_mul", DualBlend::SRC_1)
.push_constant(Type::INT, "debug_mode")
.push_constant(Type::INT, "debug_tilemap_index")
.depth_write(DepthWrite::ANY)
.fragment_source("eevee_shadow_debug_frag.glsl")
.additional_info(
"draw_fullscreen", "draw_view", "eevee_hiz_data", "eevee_light_data", "eevee_shadow_data");

View File

@ -350,6 +350,16 @@ struct DRWDebugVert {
};
BLI_STATIC_ASSERT_ALIGN(DRWDebugVert, 16)
inline DRWDebugVert debug_vert_make(uint in_pos0, uint in_pos1, uint in_pos2, uint in_vert_color)
{
DRWDebugVert debug_vert;
debug_vert.pos0 = in_pos0;
debug_vert.pos1 = in_pos1;
debug_vert.pos2 = in_pos2;
debug_vert.vert_color = in_vert_color;
return debug_vert;
}
/* Take the header (DrawCommand) into account. */
#define DRW_DEBUG_DRAW_VERT_MAX (64 * 8192) - 1

View File

@ -34,9 +34,9 @@ uint drw_debug_color_pack(vec4 v_color)
void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color)
{
drw_debug_verts_buf[vertid++] = DRWDebugVert(
drw_debug_verts_buf[vertid++] = debug_vert_make(
floatBitsToUint(v1.x), floatBitsToUint(v1.y), floatBitsToUint(v1.z), v_color);
drw_debug_verts_buf[vertid++] = DRWDebugVert(
drw_debug_verts_buf[vertid++] = debug_vert_make(
floatBitsToUint(v2.x), floatBitsToUint(v2.y), floatBitsToUint(v2.z), v_color);
}

View File

@ -154,7 +154,7 @@ struct SculptUndoNodeGeometry {
CustomData ldata;
CustomData pdata;
int *poly_offset_indices;
blender::ImplicitSharingInfo *poly_offsets_sharing_info;
const blender::ImplicitSharingInfo *poly_offsets_sharing_info;
int totvert;
int totedge;
int totloop;

View File

@ -118,7 +118,6 @@ static void tracking_segment_knot_cb(void *userdata,
float val)
{
TrackMotionCurveUserData *data = (TrackMotionCurveUserData *)userdata;
int sel = 0, sel_flag;
if (track != data->act_track) {
return;
@ -127,8 +126,9 @@ static void tracking_segment_knot_cb(void *userdata,
return;
}
sel_flag = value_source == CLIP_VALUE_SOURCE_SPEED_X ? MARKER_GRAPH_SEL_X : MARKER_GRAPH_SEL_Y;
sel = (marker->flag & sel_flag) ? 1 : 0;
const int sel_flag = value_source == CLIP_VALUE_SOURCE_SPEED_X ? MARKER_GRAPH_SEL_X :
MARKER_GRAPH_SEL_Y;
const bool sel = (marker->flag & sel_flag) != 0;
if (sel == data->sel) {
immUniformThemeColor(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX);

View File

@ -510,28 +510,23 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
}
}
else {
if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval);
if (mesh == nullptr) {
return geometry_set;
if (BLI_listbase_is_single(&sspreadsheet->viewer_path.path)) {
if (const GeometrySet *geometry_eval = object_eval->runtime.geometry_set_eval) {
geometry_set = *geometry_eval;
}
if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
if (Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval)) {
BKE_mesh_wrapper_ensure_mdata(mesh);
geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly);
}
}
BKE_mesh_wrapper_ensure_mdata(mesh);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
}
else {
if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) {
/* Use final evaluated object. */
if (object_eval->runtime.geometry_set_eval != nullptr) {
geometry_set = *object_eval->runtime.geometry_set_eval;
}
}
else {
if (const ViewerNodeLog *viewer_log =
nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path(
sspreadsheet->viewer_path)) {
geometry_set = viewer_log->geometry;
}
if (const ViewerNodeLog *viewer_log =
nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path(
sspreadsheet->viewer_path)) {
geometry_set = viewer_log->geometry;
}
}
}

View File

@ -580,6 +580,33 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat);
}
static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3])
{
bPoseChannel *active_pchan = BKE_pose_channel_active(ob, false);
/* Check if target bone is a child. */
if (active_pchan->parent) {
/* For child, show parent local regardless if "local location" is set for parent bone. */
transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat));
return;
}
/* For root, use local transform of armature object. */
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world));
}
static void handle_object_parent_orientation(Object *ob, float r_mat[3][3])
{
/* If object has parent, then orient to parent. */
if (ob->parent) {
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->parent->object_to_world));
}
else {
/* If object doesn't have parent, then orient to world. */
unit_m3(r_mat);
}
}
short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
ViewLayer *view_layer,
const View3D *v3d,
@ -609,6 +636,20 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
/* If not gimbal, fall through to normal. */
ATTR_FALLTHROUGH;
}
case V3D_ORIENT_PARENT: {
if (ob) {
if (ob->mode & OB_MODE_POSE) {
handle_armature_parent_orientation(ob, r_mat);
break;
}
else {
handle_object_parent_orientation(ob, r_mat);
break;
}
}
/* No break; we define 'parent' as 'normal' otherwise. */
ATTR_FALLTHROUGH;
}
case V3D_ORIENT_NORMAL: {
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
@ -621,7 +662,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
if (ob) {
if (ob->mode & OB_MODE_POSE) {
/* Each bone moves on its own local axis, but to avoid confusion,
* use the active pones axis for display #33575, this works as expected on a single
* use the active bone's axis for display #33575, this works as expected on a single
* bone and users who select many bones will understand what's going on and what local
* means when they start transforming. */
ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
@ -741,6 +782,8 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien
return TIP_("view");
case V3D_ORIENT_CURSOR:
return TIP_("cursor");
case V3D_ORIENT_PARENT:
return TIP_("parent");
case V3D_ORIENT_CUSTOM_MATRIX:
return TIP_("custom");
case V3D_ORIENT_CUSTOM:

View File

@ -3181,7 +3181,7 @@ static float uv_sphere_project(const Scene *scene,
const float branch_init)
{
float max_u = 0.0f;
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
return max_u;
}
@ -3358,7 +3358,7 @@ static float uv_cylinder_project(const Scene *scene,
const float branch_init)
{
float max_u = 0.0f;
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
return max_u;
}

View File

@ -458,6 +458,9 @@ GPUTexture *GPU_texture_create_view(const char *name,
{
BLI_assert(mip_len > 0);
BLI_assert(layer_len > 0);
BLI_assert_msg(
GPU_texture_usage(src) & GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
"Source texture of TextureView must have GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW usage flag.");
Texture *view = GPUBackend::get()->texture_alloc(name);
view->init_view(src,
format,

View File

@ -189,6 +189,16 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
[this->queue retain];
[this->device retain];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-method-access"
/* Enable increased concurrent shader compiler limit.
* Note: Disable warning for missing method when building on older OS's, as compiled code will
* still work correctly when run on a system with the API available. */
if (@available(macOS 13.3, *)) {
[this->device setShouldMaximizeConcurrentCompilation:YES];
}
#pragma clang diagnostic pop
/* Register present callback. */
this->ghost_context_->metalRegisterPresentCallback(&present);

View File

@ -83,9 +83,7 @@ struct constexp_uvec3 {
uint3 xyz;
};
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z)
{
}
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z) {}
constexpr uint operator[](int i)
{
/* Note: Need to switch on each elem value as array accessor triggers
@ -294,6 +292,8 @@ struct SStruct {
#define textureGather3(__tex, __uv, __comp) _texture_gather_internal(__tex, __uv, __comp)
#define textureGatherOffset(__tex, __offset, __uv, __comp) \
_texture_gather_internal(__tex, __uv, __comp, __offset)
#define textureGrad(__tex, __uv, __dpdx, __dpdy) \
_texture_grad_internal(__tex, __uv, __dpdx, __dpdy)
#define TEXURE_MACRO(_1, _2, _3, TEXNAME, ...) TEXNAME
#define texture(...) TEXURE_MACRO(__VA_ARGS__, texture3, texture2)(__VA_ARGS__)
@ -849,6 +849,34 @@ inline vec<T, 4> _texture_gather_internal(
return tex.texture->gather(*tex.samp, uva.xy, uint(uva.z), offset);
}
/* Texture Grad. */
inline float4 _texture_grad_internal(
thread _mtl_combined_image_sampler_2d<float, access::sample> tex,
float2 uv,
float2 dpdx,
float2 dpdy)
{
return tex.texture->sample(*tex.samp, uv, gradient2d(dpdx, dpdy));
}
inline float4 _texture_grad_internal(
thread _mtl_combined_image_sampler_2d_array<float, access::sample> tex,
float3 uva,
float2 dpdx,
float2 dpdy)
{
return tex.texture->sample(*tex.samp, uva.xy, uint(uva.z), gradient2d(dpdx, dpdy));
}
inline float4 _texture_grad_internal(
thread _mtl_combined_image_sampler_3d<float, access::sample> tex,
float3 uvw,
float3 dpdx,
float3 dpdy)
{
return tex.texture->sample(*tex.samp, uvw, gradient3d(dpdx, dpdy));
}
/* Texture write support. */
template<typename S, typename T, access A>
inline void _texture_write_internal(thread _mtl_combined_image_sampler_1d<S, A> tex,

View File

@ -230,7 +230,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
const uint8_t *data_end = data + data_size;
for (uint i = 0; i < levels; i++) {
for (uint level = 0; level < levels; level++) {
uint blocks_per_row = (mip_width + 3) / 4;
uint blocks_per_col = (mip_height + 3) / 4;
uint blocks = blocks_per_row * blocks_per_col;
@ -238,7 +238,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
if (data + block_bytes * blocks > data_end) {
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
* on a malformed files. */
*num_valid_levels = i;
*num_valid_levels = level;
break;
}

View File

@ -4,11 +4,14 @@
#include <memory>
/* Include our own math header first to avoid warnings about M_PI
* redefinition between OpenImageIO and Windows headers. */
#include "BLI_math_base.h"
#include "BLI_sys_types.h"
#include <OpenImageIO/filesystem.h>
#include <OpenImageIO/imageio.h>
#include "BLI_sys_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"

View File

@ -560,6 +560,12 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
return false;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
delete file_stream;
printf("OpenEXR-save: UNKNOWN ERROR\n");
return false;
}
delete file_stream;
return true;
@ -636,6 +642,11 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag
delete file_stream;
return false;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
printf("OpenEXR-save: UNKNOWN ERROR\n");
delete file_stream;
return false;
}
delete file_stream;
return true;
@ -939,6 +950,15 @@ bool IMB_exr_begin_write(void *handle,
data->ofile = nullptr;
data->ofile_stream = nullptr;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
std::cerr << "IMB_exr_begin_write: UNKNOWN ERROR" << std::endl;
delete data->ofile;
delete data->ofile_stream;
data->ofile = nullptr;
data->ofile_stream = nullptr;
}
return (data->ofile != nullptr);
}
@ -999,7 +1019,7 @@ void IMB_exrtile_begin_write(
data->ofile_stream = new OFileStream(filepath);
data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
}
catch (const std::exception &) {
catch (...) { /* Catch-all for edge cases or compiler bugs. */
delete data->mpofile;
delete data->ofile_stream;
@ -1024,7 +1044,7 @@ bool IMB_exr_begin_read(
data->ifile_stream = new IFileStream(filepath);
data->ifile = new MultiPartInputFile(*(data->ifile_stream));
}
catch (const std::exception &) {
catch (...) { /* Catch-all for edge cases or compiler bugs. */
delete data->ifile;
delete data->ifile_stream;
@ -1199,6 +1219,9 @@ void IMB_exr_write_channels(void *handle)
catch (const std::exception &exc) {
std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
std::cerr << "OpenEXR-writePixels: UNKNOWN ERROR" << std::endl;
}
/* Free temporary buffers. */
if (rect_half != nullptr) {
MEM_freeN(rect_half);
@ -1258,6 +1281,9 @@ void IMB_exrtile_write_channels(
catch (const std::exception &exc) {
std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
std::cerr << "OpenEXR-writeTile: UNKNOWN ERROR" << std::endl;
}
}
void IMB_exr_read_channels(void *handle)
@ -1336,6 +1362,10 @@ void IMB_exr_read_channels(void *handle)
std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
break;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
std::cerr << "OpenEXR-readPixels: UNKNOWN ERROR: " << std::endl;
break;
}
}
}
@ -2150,6 +2180,16 @@ struct ImBuf *imb_load_openexr(const uchar *mem,
delete file;
delete membuf;
return nullptr;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
std::cerr << "OpenEXR-Load: UNKNOWN ERROR" << std::endl;
if (ibuf) {
IMB_freeImBuf(ibuf);
}
delete file;
delete membuf;
return nullptr;
}
}
@ -2254,6 +2294,12 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
delete stream;
return nullptr;
}
catch (...) { /* Catch-all for edge cases or compiler bugs. */
std::cerr << "OpenEXR-Thumbnail: UNKNOWN ERROR" << std::endl;
delete file;
delete stream;
return nullptr;
}
return nullptr;
}

View File

@ -632,6 +632,7 @@ enum {
V3D_ORIENT_VIEW = 3,
V3D_ORIENT_GIMBAL = 4,
V3D_ORIENT_CURSOR = 5,
V3D_ORIENT_PARENT = 6,
V3D_ORIENT_CUSTOM = 1024,
/** Runtime only, never saved to DNA. */
V3D_ORIENT_CUSTOM_MATRIX = (V3D_ORIENT_CUSTOM - 1),

View File

@ -753,6 +753,7 @@ static void rna_def_attribute_float(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -785,6 +786,7 @@ static void rna_def_attribute_float_vector(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -823,6 +825,7 @@ static void rna_def_attribute_float_color(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FloatColorAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -870,6 +873,7 @@ static void rna_def_attribute_byte_color(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ByteColorAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -918,6 +922,7 @@ static void rna_def_attribute_int(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "IntAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -947,6 +952,7 @@ static void rna_def_attribute_string(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "StringAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -976,6 +982,7 @@ static void rna_def_attribute_bool(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -1005,6 +1012,7 @@ static void rna_def_attribute_int8(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ByteIntAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -1036,6 +1044,7 @@ static void rna_def_attribute_int2(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Int2AttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
@ -1071,6 +1080,7 @@ static void rna_def_attribute_float2(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Float2AttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",

View File

@ -345,6 +345,7 @@ static void rna_def_curves_curve(BlenderRNA *brna)
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "CurvePoint");
RNA_def_property_ui_text(prop, "Points", "Control points of the curve");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_CurveSlice_points_begin",
"rna_iterator_array_next",
@ -384,6 +385,7 @@ static void rna_def_curves(BlenderRNA *brna)
/* Point and Curve RNA API helpers. */
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_curves_begin",
"rna_iterator_array_next",
@ -398,6 +400,7 @@ static void rna_def_curves(BlenderRNA *brna)
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "CurvePoint");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_position_data_begin",
"rna_iterator_array_next",
@ -412,6 +415,7 @@ static void rna_def_curves(BlenderRNA *brna)
/* Direct access to built-in attributes. */
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_position_data_begin",
"rna_iterator_array_next",
@ -426,6 +430,7 @@ static void rna_def_curves(BlenderRNA *brna)
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "IntAttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Curves_curve_offset_data_begin",
"rna_iterator_array_next",
@ -440,6 +445,7 @@ static void rna_def_curves(BlenderRNA *brna)
rna_def_read_only_float_vector(brna);
prop = RNA_def_property(srna, "normals", PROP_COLLECTION, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_struct_type(prop, "FloatVectorValueReadOnly");
/* `lookup_int` isn't provided since the entire normals array is allocated and calculated when
* it's accessed. */

View File

@ -3107,6 +3107,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop,
"MeshUVLoop (Deprecated)",
"Deprecated, use 'uv', 'vertex_select', 'edge_select' or 'pin' properties instead");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_data_begin",
"rna_iterator_array_next",
@ -3147,6 +3148,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop = RNA_def_property(srna, "uv", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Float2AttributeValue");
RNA_def_property_ui_text(prop, "UV", "UV coordinates on face corners");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_uv_begin",
"rna_iterator_array_next",
@ -3161,6 +3163,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(
prop, "UV Vertex Selection", "Selection state of the face corner the UV editor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_vert_select_begin",
"rna_iterator_array_next",
@ -3175,6 +3178,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(
prop, "UV Edge Selection", "Selection state of the edge in the UV editor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_edge_select_begin",
"rna_iterator_array_next",
@ -3188,6 +3192,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
prop = RNA_def_property(srna, "pin", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "BoolAttributeValue");
RNA_def_property_ui_text(prop, "UV Pin", "UV pinned state in the UV editor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshUVLoopLayer_pin_begin",
"rna_iterator_array_next",
@ -3256,6 +3261,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshLoopColor");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshLoopColorLayer_data_begin",
"rna_iterator_array_next",
@ -3317,6 +3323,7 @@ static void rna_def_MPropCol(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertColor");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshVertColorLayer_data_begin",
"rna_iterator_array_next",
@ -3362,6 +3369,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "FloatProperty"); \
RNA_def_property_ui_text(prop, "Data", ""); \
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
RNA_def_property_collection_funcs(prop, \
"rna_Mesh" elemname "FloatPropertyLayer_data_begin", \
"rna_iterator_array_next", \
@ -3405,6 +3413,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "IntProperty"); \
RNA_def_property_ui_text(prop, "Data", ""); \
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
RNA_def_property_collection_funcs(prop, \
"rna_Mesh" elemname "IntPropertyLayer_data_begin", \
"rna_iterator_array_next", \
@ -3447,6 +3456,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
RNA_def_property_struct_type(prop, "Mesh" elemname "StringProperty"); \
RNA_def_property_ui_text(prop, "Data", ""); \
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
RNA_def_property_collection_funcs(prop, \
"rna_Mesh" elemname "StringPropertyLayer_data_begin", \
"rna_iterator_array_next", \
@ -3955,6 +3965,7 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshSkinVertex");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshSkinVertexLayer_data_begin",
"rna_iterator_array_next",
@ -4008,6 +4019,7 @@ static void rna_def_vertex_creases(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshVertexCrease");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshVertexCreaseLayer_data_begin",
"rna_iterator_array_next",
@ -4042,6 +4054,7 @@ static void rna_def_edge_creases(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshEdgeCrease");
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_MeshEdgeCreaseLayer_data_begin",
"rna_iterator_array_next",

View File

@ -177,6 +177,7 @@ static void rna_def_pointcloud(BlenderRNA *brna)
/* geometry */
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Point");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_PointCloud_points_begin",
"rna_iterator_array_next",

View File

@ -628,6 +628,11 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
ICON_ORIENTATION_CURSOR,
"Cursor",
"Align the transformation axes to the 3D cursor"},
{V3D_ORIENT_PARENT,
"PARENT",
ICON_BLANK1,
"Parent",
"Align the transformation axes to the object's parent space"},
// {V3D_ORIENT_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"},
{0, NULL, 0, NULL, NULL},
};

View File

@ -158,6 +158,12 @@ class StringBuilder : public SocketDeclarationBuilder<String> {
class IDSocketDeclaration : public SocketDeclaration {
public:
const char *idname;
/**
* Get the default ID pointer for this socket. This is a function to avoid dangling pointers,
* since bNode::id pointers are remapped as ID pointers change, but pointers in socket
* declarations are not managed the same way.
*/
std::function<ID *(const bNode &node)> default_value_fn;
public:
IDSocketDeclaration(const char *idname);

View File

@ -7,6 +7,7 @@
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
#include "BKE_mesh.hh"
#include "BKE_pointcloud.h"
#include "UI_interface.h"

View File

@ -124,7 +124,41 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
namespace blender::nodes {
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket)
static std::function<ID *(const bNode &node)> get_default_id_getter(const bNodeTree &ntree,
const bNodeSocket &io_socket)
{
const int socket_index = io_socket.in_out == SOCK_IN ? BLI_findindex(&ntree.inputs, &io_socket) :
BLI_findindex(&ntree.outputs, &io_socket);
/* Avoid capturing pointers that can become dangling. */
return [in_out = io_socket.in_out, socket_index](const bNode &node) -> ID * {
if (node.id == nullptr) {
return nullptr;
}
if (GS(node.id->name) != ID_NT) {
return nullptr;
}
const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
const bNodeSocket *io_socket;
if (in_out == SOCK_IN) {
/* Better be safe than sorry when the underlying node group changed. */
if (socket_index < ntree.interface_inputs().size()) {
io_socket = ntree.interface_inputs()[socket_index];
}
}
else {
if (socket_index < ntree.interface_outputs().size()) {
io_socket = ntree.interface_outputs()[socket_index];
}
}
if (io_socket == nullptr) {
return nullptr;
}
return *static_cast<ID **>(io_socket->default_value);
};
}
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree,
const bNodeSocket &io_socket)
{
SocketDeclarationPtr dst;
switch (io_socket.type) {
@ -184,24 +218,39 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &
dst = std::move(decl);
break;
}
case SOCK_OBJECT:
dst = std::make_unique<decl::Object>();
case SOCK_OBJECT: {
auto value = std::make_unique<decl::Object>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
case SOCK_IMAGE:
dst = std::make_unique<decl::Image>();
}
case SOCK_IMAGE: {
auto value = std::make_unique<decl::Image>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
}
case SOCK_GEOMETRY:
dst = std::make_unique<decl::Geometry>();
break;
case SOCK_COLLECTION:
dst = std::make_unique<decl::Collection>();
case SOCK_COLLECTION: {
auto value = std::make_unique<decl::Collection>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
case SOCK_TEXTURE:
dst = std::make_unique<decl::Texture>();
}
case SOCK_TEXTURE: {
auto value = std::make_unique<decl::Texture>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
case SOCK_MATERIAL:
dst = std::make_unique<decl::Material>();
}
case SOCK_MATERIAL: {
auto value = std::make_unique<decl::Material>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
}
case SOCK_CUSTOM:
std::unique_ptr<decl::Custom> decl = std::make_unique<decl::Custom>();
decl->idname_ = io_socket.idname;
@ -232,10 +281,10 @@ void node_group_declare_dynamic(const bNodeTree & /*node_tree*/,
r_declaration.skip_updating_sockets = false;
LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) {
r_declaration.inputs.append(declaration_for_interface_socket(*input));
r_declaration.inputs.append(declaration_for_interface_socket(*group, *input));
}
LISTBASE_FOREACH (const bNodeSocket *, output, &group->outputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*output));
r_declaration.outputs.append(declaration_for_interface_socket(*group, *output));
}
}
@ -450,7 +499,7 @@ static void group_input_declare_dynamic(const bNodeTree &node_tree,
NodeDeclaration &r_declaration)
{
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.inputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*input));
r_declaration.outputs.append(declaration_for_interface_socket(node_tree, *input));
r_declaration.outputs.last()->in_out = SOCK_OUT;
}
r_declaration.outputs.append(extend_declaration(SOCK_OUT));
@ -461,7 +510,7 @@ static void group_output_declare_dynamic(const bNodeTree &node_tree,
NodeDeclaration &r_declaration)
{
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.outputs) {
r_declaration.inputs.append(declaration_for_interface_socket(*input));
r_declaration.inputs.append(declaration_for_interface_socket(node_tree, *input));
r_declaration.inputs.last()->in_out = SOCK_IN;
}
r_declaration.inputs.append(extend_declaration(SOCK_IN));

View File

@ -3,6 +3,7 @@
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "BKE_node_runtime.hh"
@ -435,6 +436,13 @@ bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
&ntree, &node, this->in_out, this->idname, this->identifier.c_str(), this->name.c_str());
if (this->default_value_fn) {
ID *id = this->default_value_fn(node);
/* Assumes that all ID sockets like #bNodeSocketValueObject and #bNodeSocketValueImage have the
* ID pointer at the start of the struct. */
*static_cast<ID **>(socket.default_value) = id;
id_us_plus(id);
}
this->set_common_flags(socket);
return socket;
}

View File

@ -785,11 +785,11 @@ static PyObject *bpy_bmlayercollection_subscript_slice(BPy_BMLayerCollection *se
BPY_BM_CHECK_OBJ(self);
if (start >= len) {
start = len - 1;
if (start > len) {
start = len;
}
if (stop >= len) {
stop = len - 1;
if (stop > len) {
stop = len;
}
tuple = PyTuple_New(stop - start);
@ -915,7 +915,7 @@ static PyObject *bpy_bmlayercollection_iter(BPy_BMLayerCollection *self)
BPY_BM_CHECK_OBJ(self);
ret = bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MIN);
ret = bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MAX);
if (ret) {
iter = PyObject_GetIter(ret);

View File

@ -467,8 +467,6 @@ static void wm_init_userdef(Main *bmain)
/* Not versioning, just avoid errors. */
#ifndef WITH_CYCLES
BKE_addon_remove_safe(&U.addons, "cycles");
#else
UNUSED_VARS(BKE_addon_remove_safe);
#endif
UI_init_userdef();
@ -1584,7 +1582,7 @@ static void wm_history_file_update(void)
/* Write current file to #BLENDER_HISTORY_FILE. */
wm_history_file_write();
/* also update most recent files on System */
/* Also update most recent files on system. */
GHOST_addToSystemRecentFiles(blendfile_path);
}
}