GSoC 2019: Undo Improvements

Notice: I have pivoted the idea to one of improving UNDO speed and efficiency. Please read the replies below. :slight_smile:

Hi all. In the latest build of Blender 2.8, Undo follows the global order in which actions were done. This means that if I am working on an object having previously worked on another object, but wish to undo an action done on the previous object, I have to undo all the actions done to the current object too. I have done some research on Right Click Select and UI Papercut, and noticed that this is a pain point for some Blender users too. https://blender.community/c/rightclickselect/VLcbbc/

I wish to propose a refactor of the Undo system so that it retains the ability to perform traditional undo as well as my proposed per data-block undo. This involves storing actions at data-block level. If user clicks on a mesh data-block in the outliner, Ctrl-Z will perform traditional undo (following global order) while Ctrl-Alt-Z will perform per data-block undo (for the selected mesh). In addition, I intend to create a new Undo panel for undo management.

Example

  • If our active editor is 3D view port and we are in edit mode, upon translating a vertex of object A, this action will be recorded under object A’s mesh data-block.
  • If our active editor is 3D view port and we are in object mode, upon translating object A, this action will be recorded under object A’s data-block.
  • If our active editor is Properties and we are in material panel, upon modify the diffused color, this action will be recorded under object A’s material data-block.

Concerns

  • If an action on one data-block strictly requires that an action on another data-block has been completed, then my proposed Undo mechanism may not be viable because if we were to undo the dependent action, the other action will become invalid.

Thoughts

  • If all Blender actions are unrestricted and have its own inverse (i.e. translate (0, 0, 1) and translate (0, 0, -1)), then my concern is unfounded. But if there are actions in Blender that maybe active/ inactive based on some conditions (restricted action), then my concern is valid.

Thank you for looking through my gSOC project ideation. I would love to receive some feedback regarding the meaningfulness of this project, viability of this project, general ideas and suggestions. Is it a pain point for many users? Could this be a good gSOC project on its own?

5 Likes

I’m afraid the situation is really quite complicated and there are dependencies between datablocks in many situations that make per-datablock undo problematic. Bugs and unexpected behavior due to this is exactly why we moved away from it, even if it can be useful in some cases.

In the right click select request, note also that the request is to decouple undo of layers and drawing, which are both edits to the same datablock.

Thank you for your feedback. It helps a lot to narrow down potential ideas.

I don’t want to interfere… but the main UNDO problem is speed in medium to large scenes, just moving an object and doing an UNDO of that movement can take several seconds, even minutes!

Just in case this helps you out to your ideas for the GSOC, IMHO try to do something useful, “small” but important and then it could probably even be included in master after GSOC (it depends on you and the devs… but if it’s simple, useful and stable… why not?)

It’s great to see a dev or potential dev interested in improving the UNDO system.

Cheers!

6 Likes

Right, optimizing undo could be a project. It touches quite some core code so needs to be done very carefully, but if enough time is taking to test well it would work. Some ideas for that are here:
https://developer.blender.org/T60695

3 Likes

Thank you for your advise. I think so too, to have my work included in master would be icing on the cake.

I don’t deal with complex scene in Blender often enough, so thanks for sharing a potential project idea! It reminds me of my not so good experience creating fur using particle system for the first time.

1 Like

Thank you for sharing additional resources. I have a number of questions but I will focus on a few first.

  1. What is Main fields? How does it relate to the task?
  2. I read up on dependency graph from https://wiki.blender.org/wiki/Source/Depsgraph and I think understood the relevant parts. But what is “dependency graph update tags” and how it works?
  3. If I would like to explore codes relevant to this project, do you have any suggestion on where to start?
1 Like

We could provide some scenes for testing purposes :slight_smile: and we could work some hours with a test build to check if it works correctly and with the spected performance once you have some build to share :slight_smile:

2 Likes

There is some info here. It’s basically the data structure that contains the entire .blend file contents.
https://archive.blender.org/wiki/index.php/Dev:Source/Architecture/Overview/

When a datablock changes, it is tagged for updated in the dependency graph. The dependency graph will then do things like evaluation modifiers or animation for that datablock and any datablocks depending on it.

I suggest to start from blenkernel/intern/blender_undo.c and follow the function calls. That file contains the two functions that perform the global undo push and load.

A suggestion: this might seem obvious, but it might be a good idea to download the demo files. https://www.blender.org/download/demo-files/ Some of these are pretty slow to undo/redo. You could use them as a standard benchmark for your improvements (as they are already used to benchmark CPU/GPU performance in Open Data).

3 Likes

That is totally true! I did not think about that :slight_smile:

Hi Brecht, I am in the process of writing my project proposal and would like to clarify my understanding of the relevant Blender’s code.

At the high level, in blenkernel/intern/blender_undo.c, BKE_memfile_undo_decode calls BKE_blendfile_read_from_memfile, which does the actual reading from MemFile (undo buffer) and updates bContext. I presume bContext contains all the states for a Blender program. Hence, having updated bContext, the UNDO operation has completed.

Is this correct in so far as this project is concerned?

undo on big scene freeze my computers, and i have 32gig of ram + threadripper 16cores 4Ghz

1 Like

Mostly right yes.

For info on what the context is, see:
https://archive.blender.org/wiki/index.php/Dev:2.5/Source/Architecture/Context/

Main is owned by by Global G from BKE_global. The context doesn’t really own any data, just points to it to defined which data or part of the user interface the current code is working on.

Thank you! I would like to clarify my understanding of the relevant Blender’s code further and seek feedback for my analysis of the UNDO task.

Following the function calls, BKE_blendfile_read_from_memfile calls BLO_read_from_memfile and setup_app_data.

BLO_read_from_memfile in turn calls the following functions:

  1. blo_filedata_from_memfile: Creates a catalog of DNA-structures documentation and returns FileData.
  2. blo_clear_proxy_pointers_from_lib: ?
  3. blo_split_main: ?
  4. blo_add_library_pointer_map: ?
  5. blo_make_image_pointer_map & related calls: ? I presume this is the reason render results remains after UNDO.
  6. blo_read_file_internal: Reads from MemFile and returns BlendFileData.
  7. blo_end_scene_pointer_map: ?

setup_app_data updates Main through bContext and pushes updates to the UI.

		/* Even though directly used libs have been already moved to new main, indirect ones have not.
		 * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused
		 * data may remain in memory, but think we'll have to live with it. */

Question: What do directly and indirectly used library refer to? Am I right thus far? (": ?" can be ignored unless it is important)

Referring to the bullet point “Read only changed datablocks” of this task that you shared, I presume that BLO_read_from_memfile needs to be modified so that all datablocks remains as it is from old Main. blo_read_file_internal function needs to be modified so that changed datablocks are read from MemFile. We will also need to deal with added/ removed datablocks. Idea is to start off from the current state, find datablocks that has changed, read those datablocks from MemFile into BlendFileData.

setup_app_data should not need much modification if any at all.

blo_read_file_internal is used for loading of .blend files as well and therefore needs extra care.

Question: Where in the code are links between datablocks reestablished? Is my analysis of the UNDO task reasonably correct? Could I have misunderstood the task or the code?

blo_clear_proxy_pointers_from_lib
blo_add_library_pointer_map
blo_end_scene_pointer_map

Don’t worry about those, not important for overall design.

blo_split_main

This splits the main database into multiple databases, one the current .blend file and one for each linked library.

blo_make_image_pointer_map

You’re correct about this.

Question : What do directly and indirectly used library refer to?

Indirect means a linked datablock or library that comes in through another linked datablock or library.

Question : Where in the code are links between datablocks reestablished?

lib_link_* functions set pointers that link to other datablocks. Due to the way things work out, datablocks that were already loaded never need to have any of their pointers updated.

Is my analysis of the UNDO task reasonably correct? Could I have misunderstood the task or the code?

It seems fine.

I don’t want to muddy this discussion with non-relevant posts, but improving undo speed on complex scenes would be absolutely amazing. These types of unglamorous, utilitarian changes often go untouched, but know that you will make a lot users very happy if the speed improves.

14 Likes

Sorry guys… was not selected for GSoC. Thank you for everything!

4 Likes

NOOOOOOOOOOOOOOOOOOOOOO :frowning:
i wish we can trade
every time i hit ctrl z its slow af

Thanks for trying lywah, it’s a big pity!

Undo REALLY needs fixing.

Cheers!

4 Likes