Cycles: Avoid overhead from RNA when extracting mesh data #106275

Merged
Hans Goudey merged 14 commits from HooglyBoogly/blender:cycles-mesh-cleanup into main 2023-04-03 17:05:10 +02:00
2 changed files with 129 additions and 85 deletions
Showing only changes of commit d7ee9cca52 - Show all commits

View File

@ -412,43 +412,46 @@ static void attr_create_generic(Scene *scene,
switch (b_data_type) {
case BL::Attribute::data_type_FLOAT: {
BL::FloatAttribute b_float_attribute{b_attribute};
const float *b_data = static_cast<const float *>(b_float_attribute.data[0].ptr.data);
HooglyBoogly marked this conversation as resolved Outdated

Is this safe when the number of elements is 0? It seems fragile regardless, seems better to use:

if (b_float_attribute.data.length()) {
  const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data);
  fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) { return src[i]; });
}
Is this safe when the number of elements is 0? It seems fragile regardless, seems better to use: ``` if (b_float_attribute.data.length()) { const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data); fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) { return src[i]; }); } ```
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return b_float_attribute.data[i].value();
});
fill_generic_attribute(
b_mesh, data, b_domain, subdivision, [&](int i) { return b_data[i]; });
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
const bool *b_data = static_cast<const bool *>(b_bool_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return (float)b_bool_attribute.data[i].value();
});
fill_generic_attribute(
b_mesh, data, b_domain, subdivision, [&](int i) { return (float)b_data[i]; });
break;
}
case BL::Attribute::data_type_INT: {
BL::IntAttribute b_int_attribute{b_attribute};
const int *b_data = static_cast<const int *>(b_int_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return (float)b_int_attribute.data[i].value();
});
fill_generic_attribute(
b_mesh, data, b_domain, subdivision, [&](int i) { return (float)b_data[i]; });
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
const float(*b_data)[3] = static_cast<const float(*)[3]>(
b_vector_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
return make_float3(v[0], v[1], v[2]);
return make_float3(b_data[i][0], b_data[i][1], b_data[i][2]);
});
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
const uchar(*b_data)[4] = static_cast<const uchar(*)[4]>(
b_color_attribute.data[0].ptr.data);
if (element == ATTR_ELEMENT_CORNER) {
element = ATTR_ELEMENT_CORNER_BYTE;
@ -462,21 +465,24 @@ static void attr_create_generic(Scene *scene,
uchar4 *data = attr->data_uchar4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
/* Compress/encode vertex color using the sRGB curve. */
const float4 c = get_float4(b_color_attribute.data[i].color());
return color_float4_to_uchar4(color_linear_to_srgb_v4(c));
return make_uchar4(b_data[i][0], b_data[i][1], b_data[i][2], b_data[i][3]);
});
}
else {
float4 *data = attr->data_float4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
return make_float4(color_srgb_to_linear(byte_to_float(b_data[i][0])),
color_srgb_to_linear(byte_to_float(b_data[i][1])),
color_srgb_to_linear(byte_to_float(b_data[i][2])),
color_srgb_to_linear(byte_to_float(b_data[i][3])));
});
}
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
const float(*b_data)[4] = static_cast<const float(*)[4]>(
b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
if (is_render_color) {
@ -485,18 +491,18 @@ static void attr_create_generic(Scene *scene,
float4 *data = attr->data_float4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
return make_float4(b_data[i][0], b_data[i][1], b_data[i][2], b_data[i][3]);
});
break;
}
case BL::Attribute::data_type_FLOAT2: {
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*b_data)[2] = static_cast<const float(*)[2]>(
b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
return make_float2(b_data[i][0], b_data[i][1]);
});
break;
}
@ -818,7 +824,7 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
}
}
static std::optional<BL::IntAttribute> find_corner_vert_attribute(BL::Mesh b_mesh)
static const int *find_corner_vert_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_CORNER) {
@ -830,9 +836,9 @@ static std::optional<BL::IntAttribute> find_corner_vert_attribute(BL::Mesh b_mes
if (b_attribute.name() != ".corner_vert") {
continue;
}
return BL::IntAttribute{b_attribute};
return static_cast<const int *>(BL::IntAttribute(b_attribute).data[0].ptr.data);
}
return std::nullopt;
return nullptr;
}
/* The Random Per Island attribute is a random float associated with each
@ -881,10 +887,10 @@ static void attr_create_random_per_island(Scene *scene,
else {
if (polys_num != 0) {
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
BL::IntAttribute corner_verts = *find_corner_vert_attribute(b_mesh);
const int *corner_verts = find_corner_vert_attribute(b_mesh);
for (int i = 0; i < polys_num; i++) {
const MPoly &b_poly = polys[i];
const int vert = corner_verts.data[b_poly.loopstart].value();
const int vert = corner_verts[b_poly.loopstart];
data[i] = hash_uint_to_float(vertices_sets.find(vert));
}
}
@ -893,7 +899,7 @@ static void attr_create_random_per_island(Scene *scene,
/* Create Mesh */
static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_mesh)
static const int *find_material_index_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
@ -905,12 +911,12 @@ static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_
if (b_attribute.name() != "material_index") {
continue;
}
return BL::IntAttribute{b_attribute};
return static_cast<const int *>(BL::IntAttribute{b_attribute}.data[0].ptr.data);
}
return std::nullopt;
return nullptr;
}
static std::optional<BL::BoolAttribute> find_sharp_face_attribute(BL::Mesh b_mesh)
static const bool *find_sharp_face_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
@ -922,9 +928,9 @@ static std::optional<BL::BoolAttribute> find_sharp_face_attribute(BL::Mesh b_mes
if (b_attribute.name() != "sharp_face") {
continue;
}
return BL::BoolAttribute{b_attribute};
return static_cast<const bool *>(BL::BoolAttribute{b_attribute}.data[0].ptr.data);
}
return std::nullopt;
return nullptr;
}
static void create_mesh(Scene *scene,
@ -936,13 +942,12 @@ static void create_mesh(Scene *scene,
const bool subdivision = false,
const bool subdivide_uvs = true)
{
/* count vertices and faces */
int numverts = b_mesh.vertices.length();
scoped_timer timer;
const int numverts = b_mesh.vertices.length();
const int polys_num = b_mesh.polygons.length();
int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length();
int numtris = 0;
int numcorners = 0;
int numngons = 0;
const int numcorners = b_mesh.loops.length();
bool use_loop_normals = b_mesh.use_auto_smooth() &&
(mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
@ -952,7 +957,13 @@ static void create_mesh(Scene *scene,
}
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data);
const int *corner_verts = find_corner_vert_attribute(b_mesh);
const int *material_indices = find_material_index_attribute(b_mesh);
const bool *sharp_faces = find_sharp_face_attribute(b_mesh);
const float(*corner_normals)[3] = static_cast<const float(*)[3]>(b_mesh.loops[0].ptr.data);
int numngons = 0;
int numtris = 0;
if (!subdivision) {
numtris = numfaces;
}
@ -961,20 +972,23 @@ static void create_mesh(Scene *scene,
for (int i = 0; i < polys_num; i++) {
const MPoly &b_poly = polys[i];
numngons += (b_poly.totloop == 4) ? 0 : 1;
numcorners += b_poly.totloop;
}
}
/* allocate memory */
mesh->get_verts().resize(numverts);
if (subdivision) {
mesh->reserve_subd_faces(numfaces, numngons, numcorners);
mesh->resize_subd_faces(numfaces, numngons, numcorners);
}
else {
mesh->get_triangles().resize(numtris * 3);
mesh->get_shader().resize(numtris);
mesh->get_smooth().resize(numtris);
}
mesh->reserve_mesh(numverts, numtris);
/* create vertex coordinates and normals */
float3 *verts = mesh->get_verts().data();
for (int i = 0; i < numverts; i++) {
mesh->add_vertex(make_float3(positions[i][0], positions[i][1], positions[i][2]));
verts[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
}
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
@ -1009,66 +1023,89 @@ static void create_mesh(Scene *scene,
}
}
std::optional<BL::IntAttribute> material_indices = find_material_index_attribute(b_mesh);
auto get_material_index = [&](const int poly_index) -> int {
if (material_indices) {
return clamp(material_indices->data[poly_index].value(), 0, used_shaders.size() - 1);
}
return 0;
};
std::optional<BL::BoolAttribute> sharp_faces = find_sharp_face_attribute(b_mesh);
auto get_face_sharp = [&](const int poly_index) -> bool {
if (sharp_faces) {
return sharp_faces->data[poly_index].value();
}
return false;
auto clamp_material_index = [&](const int material_index) -> int {
return clamp(material_index, 0, used_shaders.size() - 1);
};
/* create faces */
if (!subdivision) {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
const int poly_index = t.polygon_index();
int3 vi = get_int3(t.vertices());
int *triangles = mesh->get_triangles().data();
bool *smooth = mesh->get_smooth().data();
int *shader = mesh->get_shader().data();
int shader = get_material_index(poly_index);
bool smooth = !get_face_sharp(poly_index) || use_loop_normals;
const MLoopTri *looptris = static_cast<const MLoopTri *>(b_mesh.loop_triangles[0].ptr.data);
for (int i = 0; i < numtris; i++) {
const MLoopTri &tri = looptris[i];
triangles[i * 3 + 0] = corner_verts[tri.tri[0]];
triangles[i * 3 + 1] = corner_verts[tri.tri[1]];
triangles[i * 3 + 2] = corner_verts[tri.tri[2]];
}
if (use_loop_normals) {
BL::Array<float, 9> loop_normals = t.split_normals();
if (material_indices) {
for (int i = 0; i < numtris; i++) {
const int poly_index = looptris[i].poly;
shader[i] = clamp_material_index(material_indices[poly_index]);
}
}
else {
std::fill(shader, shader + numtris, 0);
}
if (sharp_faces && !use_loop_normals) {
for (int i = 0; i < numtris; i++) {
const int poly_index = looptris[i].poly;
smooth[i] = !sharp_faces[poly_index];
}
}
else {
std::fill(smooth, smooth + numtris, true);
}
if (use_loop_normals && corner_normals) {
for (int i = 0; i < numtris; i++) {
const MLoopTri &tri = looptris[i];
for (int i = 0; i < 3; i++) {
N[vi[i]] = make_float3(
loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
const int corner = tri.tri[i];
const int vert = corner_verts[corner];
const float *normal = corner_normals[corner];
N[vert] = make_float3(normal[0], normal[1], normal[2]);
}
}
/* Create triangles.
*
* NOTE: Autosmooth is already taken care about.
*/
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
}
}
else {
vector<int> vi;
int *subd_start_corner = mesh->get_subd_start_corner().data();
int *subd_num_corners = mesh->get_subd_num_corners().data();
int *subd_shader = mesh->get_subd_shader().data();
bool *subd_smooth = mesh->get_subd_smooth().data();
int *subd_ptex_offset = mesh->get_subd_ptex_offset().data();
if (sharp_faces) {
for (int i = 0; i < numfaces; i++) {
subd_smooth[i] = !sharp_faces[i];
}
}
else {
std::fill(subd_smooth, subd_smooth + numfaces, true);
}
if (material_indices) {
for (int i = 0; i < numfaces; i++) {
subd_shader[i] = clamp_material_index(material_indices[i]);
}
}
else {
std::fill(subd_shader, subd_shader + numfaces, 0);
}
int ptex_offset = 0;
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
std::optional<BL::IntAttribute> corner_verts = find_corner_vert_attribute(b_mesh);
for (int i = 0; i < numfaces; i++) {
const MPoly &b_poly = polys[i];
int n = b_poly.totloop;
int shader = get_material_index(i);
bool smooth = !get_face_sharp(i) || use_loop_normals;
vi.resize(n);
for (int i = 0; i < n; i++) {
/* NOTE: Autosmooth is already taken care about. */
vi[i] = corner_verts->data[b_poly.loopstart + i].value();
}
/* create subd faces */
mesh->add_subd_face(&vi[0], n, shader, smooth);
subd_start_corner[i] = b_poly.loopstart;
subd_num_corners[i] = b_poly.totloop;
subd_ptex_offset[i] = ptex_offset;
ptex_offset += b_poly.totloop == 4 ? 1 : b_poly.totloop;
}
}
@ -1098,6 +1135,8 @@ static void create_mesh(Scene *scene,
*tfm = transform_translate(-loc) * transform_scale(size);
}
std::cout << time_human_readable_from_seconds(timer.get_time()) << '\n';
}
static void create_subd_mesh(Scene *scene,

View File

@ -19,6 +19,11 @@ ccl_device uchar float_to_byte(float val)
((val > (1.0f - 0.5f / 255.0f)) ? 255 : (uchar)((255.0f * val) + 0.5f)));
}
ccl_device float byte_to_float(uchar val)
{
return val * (1.0f / 255.0f);
}
ccl_device uchar4 color_float_to_byte(float3 c)
{
uchar r, g, b;