Undo: support implicit-sharing in memfile undo step #106903

Merged
Jacques Lucke merged 78 commits from JacquesLucke/blender:implicit-sharing-undo into main 2024-02-29 17:15:09 +01:00
5 changed files with 146 additions and 66 deletions
Showing only changes of commit 90ca20d7c9 - Show all commits

View File

@ -931,7 +931,8 @@ static void export_hair_curves_motion(Hair *hair,
}
/* Export motion keys. */
const int num_keys = hair->get_curve_keys().size();
const size_t num_keys = hair->num_keys();
const size_t num_curves = hair->num_curves();
float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
bool have_motion = false;
int num_motion_keys = 0;
@ -944,6 +945,9 @@ static void export_hair_curves_motion(Hair *hair,
for (const int i : points_by_curve.index_range()) {
const blender::IndexRange points = points_by_curve[i];
if (curve_index >= num_curves) {
break;
}
Hair::Curve curve = hair->get_curve(curve_index);
curve_index++;

View File

@ -661,9 +661,7 @@ void HIPDevice::tex_alloc(device_texture &mem)
address_mode = hipAddressModeClamp;
break;
case EXTENSION_CLIP:
/* TODO(@arya): setting this to Mode Clamp instead of Mode Border
* because it's unsupported in HIP. */
address_mode = hipAddressModeClamp;
address_mode = hipAddressModeBorder;
break;
case EXTENSION_MIRROR:
address_mode = hipAddressModeMirror;
@ -855,7 +853,11 @@ void HIPDevice::tex_alloc(device_texture &mem)
thread_scoped_lock lock(device_mem_map_mutex);
cmem = &device_mem_map[&mem];
hip_assert(hipTexObjectCreate(&cmem->texobject, &resDesc, &texDesc, NULL));
if (hipTexObjectCreate(&cmem->texobject, &resDesc, &texDesc, NULL) != hipSuccess) {
set_error(
"Failed to create texture. Maximum GPU texture size or available GPU memory was likely "
"exceeded.");
}
texture_info[slot].data = (uint64_t)cmem->texobject;
}

View File

@ -5319,6 +5319,45 @@ static void write_grid_paint_mask(BlendWriter *writer,
}
}
static void blend_write_layer_data(BlendWriter *writer,
const CustomDataLayer &layer,
const int count)
{
switch (layer.type) {
case CD_MDEFORMVERT:
BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer.data));
break;
case CD_MDISPS:
write_mdisps(
writer, count, static_cast<const MDisps *>(layer.data), layer.flag & CD_FLAG_EXTERNAL);
break;
case CD_PAINT_MASK:
BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
break;
case CD_GRID_PAINT_MASK:
write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
break;
case CD_PROP_BOOL:
BLO_write_raw(writer, sizeof(bool) * count, static_cast<const bool *>(layer.data));
break;
default: {
const char *structname;
int structnum;
CustomData_file_write_info(eCustomDataType(layer.type), &structname, &structnum);
if (structnum) {
int datasize = structnum * count;
BLO_write_struct_array_by_name(writer, structname, datasize, layer.data);
}
else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
printf("%s error: layer '%s':%d - can't be written to file\n",
__func__,
structname,
layer.type);
}
}
}
}
void CustomData_blend_write(BlendWriter *writer,
CustomData *data,
Span<CustomDataLayer> layers_to_write,
@ -5337,41 +5376,7 @@ void CustomData_blend_write(BlendWriter *writer,
for (const CustomDataLayer &layer : layers_to_write) {
const size_t size_in_bytes = CustomData_sizeof(eCustomDataType(layer.type)) * count;
BLO_write_shared(writer, layer.data, size_in_bytes, layer.sharing_info, [&]() {
switch (layer.type) {
case CD_MDEFORMVERT:
BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer.data));
break;
case CD_MDISPS:
write_mdisps(writer,
count,
static_cast<const MDisps *>(layer.data),
layer.flag & CD_FLAG_EXTERNAL);
break;
case CD_PAINT_MASK:
BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
break;
case CD_GRID_PAINT_MASK:
write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
break;
case CD_PROP_BOOL:
BLO_write_raw(writer, sizeof(bool) * count, static_cast<const bool *>(layer.data));
break;
default: {
const char *structname;
int structnum;
CustomData_file_write_info(eCustomDataType(layer.type), &structname, &structnum);
if (structnum) {
int datasize = structnum * count;
BLO_write_struct_array_by_name(writer, structname, datasize, layer.data);
}
else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
printf("%s error: layer '%s':%d - can't be written to file\n",
__func__,
structname,
layer.type);
}
}
}
blend_write_layer_data(writer, layer, count);
});
}

View File

@ -44,7 +44,7 @@ static void add_values_to_text_cache(const GVArray &values,
const float3 position = math::transform_point(object_to_world, positions[i]);
const T &value = values_typed[i];
char numstr[32];
char numstr[64];
size_t numstr_len = 0;
if constexpr (std::is_same_v<T, bool>) {
numstr_len = SNPRINTF_RLEN(numstr, "%s", value ? "True" : "False");
@ -77,7 +77,8 @@ static void add_values_to_text_cache(const GVArray &values,
numstr, "(%.3f, %.3f, %.3f, %.3f)", value.r, value.g, value.b, value.a);
}
else if constexpr (std::is_same_v<T, math::Quaternion>) {
numstr_len = SNPRINTF_RLEN(numstr, "(%g, %g, %g, %g)", value.w, value.x, value.y, value.z);
numstr_len = SNPRINTF_RLEN(
numstr, "(%.3f, %.3f, %.3f, %.3f)", value.w, value.x, value.y, value.z);
}
else {
BLI_assert_unreachable();

View File

@ -1429,13 +1429,33 @@ static int imb_exr_split_token(const char *str, const char *end, const char **to
return int(end - *token);
}
static void imb_exr_pass_name_from_channel(char *passname,
const ExrChannel *echan,
const char *channelname,
const bool has_xyz_channels)
{
const int passname_maxncpy = EXR_TOT_MAXNAME;
if (echan->chan_id == 'Z' && (!has_xyz_channels || BLI_strcaseeq(channelname, "depth"))) {
BLI_strncpy(passname, "Depth", passname_maxncpy);
}
else if (echan->chan_id == 'Y' && !has_xyz_channels) {
BLI_strncpy(passname, channelname, passname_maxncpy);
}
else if (ELEM(echan->chan_id, 'R', 'G', 'B', 'A', 'V', 'X', 'Y', 'Z')) {
BLI_strncpy(passname, "Combined", passname_maxncpy);
}
else {
BLI_strncpy(passname, channelname, passname_maxncpy);
}
}
static int imb_exr_split_channel_name(ExrChannel *echan,
char *layname,
char *passname,
bool has_xyz_channels)
{
const int layname_maxncpy = EXR_TOT_MAXNAME;
const int passname_maxncpy = EXR_TOT_MAXNAME;
const char *name = echan->m->name.c_str();
const char *end = name + strlen(name);
const char *token;
@ -1450,20 +1470,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan,
* versions of the listed channels. */
echan->chan_id = BLI_toupper_ascii(name[0]);
layname[0] = '\0';
if (echan->chan_id == 'Z' && !has_xyz_channels) {
BLI_strncpy(passname, "Depth", passname_maxncpy);
}
else if (echan->chan_id == 'Y' && !has_xyz_channels) {
BLI_strncpy(passname, name, passname_maxncpy);
}
else if (ELEM(echan->chan_id, 'R', 'G', 'B', 'A', 'V', 'X', 'Y', 'Z')) {
BLI_strncpy(passname, "Combined", passname_maxncpy);
}
else {
BLI_strncpy(passname, name, passname_maxncpy);
}
imb_exr_pass_name_from_channel(passname, echan, name, has_xyz_channels);
return 1;
}
@ -1519,14 +1526,20 @@ static int imb_exr_split_channel_name(ExrChannel *echan,
}
end -= len + 1; /* +1 to skip '.' separator */
/* second token is pass name */
len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
if (end > name) {
/* second token is pass name */
len = imb_exr_split_token(name, end, &token);
if (len == 0) {
printf("multilayer read: bad channel name: %s\n", name);
return 0;
}
BLI_strncpy(passname, token, len + 1);
end -= len + 1; /* +1 to skip '.' separator */
}
else {
/* Single token, determine pass name from channel name. */
imb_exr_pass_name_from_channel(passname, echan, channelname, has_xyz_channels);
}
BLI_strncpy(passname, token, len + 1);
end -= len + 1; /* +1 to skip '.' separator */
/* all preceding tokens combined as layer name */
if (end > name) {
@ -1592,10 +1605,65 @@ static bool exr_has_xyz_channels(ExrHandle *exr_handle)
return x_found && y_found && z_found;
}
static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data)
/* Replacement for OpenEXR GetChannelsInMultiPartFile, that also handles the
* case where parts are used for passes instead of multiview. */
static std::vector<MultiViewChannelName> exr_channels_in_multi_part_file(
const MultiPartInputFile &file)
{
std::vector<MultiViewChannelName> channels;
GetChannelsInMultiPartFile(*data->ifile, channels);
/* Detect if file has multiview. */
StringVector multiview;
bool has_multiview = false;
if (file.parts() == 1) {
if (hasMultiView(file.header(0))) {
multiview = multiView(file.header(0));
has_multiview = true;
}
}
/* Get channels from each part. */
for (int p = 0; p < file.parts(); p++) {
const ChannelList &c = file.header(p).channels();
std::string part_view = "";
if (file.header(p).hasView()) {
part_view = file.header(p).view();
}
std::string part_name = "";
if (file.header(p).hasName()) {
part_name = file.header(p).name();
}
for (ChannelList::ConstIterator i = c.begin(); i != c.end(); i++) {
MultiViewChannelName m;
m.name = std::string(i.name());
m.internal_name = m.name;
if (has_multiview) {
m.view = viewFromChannelName(m.name, multiview);
m.name = removeViewName(m.internal_name, m.view);
}
else {
m.view = part_view;
}
/* Prepend part name as potential layer or pass name. */
if (!part_name.empty()) {
m.name = part_name + "." + m.name;
}
m.part_number = p;
channels.push_back(m);
}
}
return channels;
}
static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data)
{
std::vector<MultiViewChannelName> channels = exr_channels_in_multi_part_file(*data->ifile);
imb_exr_get_views(*data->ifile, *data->multiView);