Freestyle render removes texture image user #74417

Closed
opened 2020-03-04 06:10:55 +01:00 by Gurpreet Singh · 15 comments

System Information
Operating system: Windows-10-10.0.18362-SP0 64 Bits
Graphics card: GeForce GTX 1660 Ti/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 441.41

Blender Version
Broken: version: 2.82 (sub 7), branch: master, commit date: 2020-02-12 16:20, hash: 77d23b0bd7
Worked: (optional)

Short description of error
Freestyle linestyle texture goes missing every time I open the file.

Exact steps for others to reproduce the error

  1. PFA zip file. It has 2 files .blend and png for linestyle.
  2. When you open the file you will notice that there's no texture called in image texture node.
  3. Call the texture image in zip file.
  4. Render and it should render freestyle lines.
  5. Save and close the file.
  6. Open the saved file again and you will notice texture goes missing in image texture node.

freestyle.zip

**System Information** Operating system: Windows-10-10.0.18362-SP0 64 Bits Graphics card: GeForce GTX 1660 Ti/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 441.41 **Blender Version** Broken: version: 2.82 (sub 7), branch: master, commit date: 2020-02-12 16:20, hash: `77d23b0bd7` Worked: (optional) **Short description of error** Freestyle linestyle texture goes missing every time I open the file. **Exact steps for others to reproduce the error** 1. PFA zip file. It has 2 files .blend and png for linestyle. 2. When you open the file you will notice that there's no texture called in image texture node. 3. Call the texture image in zip file. 4. Render and it should render freestyle lines. 5. Save and close the file. 6. Open the saved file again and you will notice texture goes missing in image texture node. [freestyle.zip](https://archive.blender.org/developer/F8389259/freestyle.zip)
Author

Added subscriber: @Oye_LKY

Added subscriber: @Oye_LKY

Added subscriber: @brecht

Added subscriber: @brecht

Changed status from 'Needs Triage' to: 'Needs User Info'

Changed status from 'Needs Triage' to: 'Needs User Info'

It seems no file got attached?

It seems no file got attached?
Ankit Meel changed title from Freestyle texture Bug to Freestyle texture not getting saved despite getting rendered 2020-03-04 14:40:31 +01:00
Author

freestyle.zip

There you go. I think this should work.

[freestyle.zip](https://archive.blender.org/developer/F8389257/freestyle.zip) There you go. I think this should work.

Changed status from 'Needs User Info' to: 'Confirmed'

Changed status from 'Needs User Info' to: 'Confirmed'
Brecht Van Lommel changed title from Freestyle texture not getting saved despite getting rendered to Freestyle render removes texture image user 2020-03-05 11:32:32 +01:00
Sybren A. Stüvel self-assigned this 2020-03-17 17:55:20 +01:00

I think I found the culprit.

When rendering starts:

  • In BlenderStrokeRenderer::RenderStrokeRepBasic(…) there is a call to GetStrokeShader(…, do_id_user=false).
  • That function reduces the user count of the "stroke_shader" material to zero.
  • Because of do_id_user=false, the ntreeCopyTree_ex() does not increase the user count for the copied node tree.

When rendering stops:

  • All copied materials are looped over and freed.
  • Freeing the material recursively frees everything it uses.
  • This leaves the texture node's image with a user count that's one too little.

Now the image datablock has no users, and will not be saved. Rendering twice shows an error on the console about a negative user count.

The simplest fix is just to remove the freeing of all the materials. This works, and when Blender quits it doesn't complain of any memory leaks. I'll do some more tests with ASAN to check whether this is really the right way to go.

diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index c88d5f24b5d..22718c29745 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -200,15 +200,6 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
     }
   }
 
-  // release materials
-  Link *lnk = (Link *)freestyle_bmain->materials.first;
-
-  while (lnk) {
-    Material *ma = (Material *)lnk;
-    lnk = lnk->next;
-    BKE_id_free(freestyle_bmain, ma);
-  }
-
   BLI_ghash_free(_nodetree_hash, NULL, NULL);
 
   DEG_graph_free(freestyle_depsgraph);
I think I found the culprit. When rendering starts: - In `BlenderStrokeRenderer::RenderStrokeRepBasic(…)` there is a call to `GetStrokeShader(…, do_id_user=false)`. - That function reduces the user count of the "stroke_shader" material to zero. - Because of `do_id_user=false`, the `ntreeCopyTree_ex()` does *not* increase the user count for the copied node tree. When rendering stops: - All copied materials are looped over and freed. - Freeing the material recursively frees everything it uses. - This leaves the texture node's image with a user count that's one too little. Now the image datablock has no users, and will not be saved. Rendering twice shows an error on the console about a negative user count. The simplest fix is just to remove the freeing of all the materials. This works, and when Blender quits it doesn't complain of any memory leaks. I'll do some more tests with ASAN to check whether this is really the right way to go. ``` diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index c88d5f24b5d..22718c29745 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -200,15 +200,6 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer() } } - // release materials - Link *lnk = (Link *)freestyle_bmain->materials.first; - - while (lnk) { - Material *ma = (Material *)lnk; - lnk = lnk->next; - BKE_id_free(freestyle_bmain, ma); - } - BLI_ghash_free(_nodetree_hash, NULL, NULL); DEG_graph_free(freestyle_depsgraph); ```
Author

So I tried it again. I found a trick for this.
This time I turned on the fake user. When I reopened the file, the image was present.

Don't know if this will really help. But I think I'll just inform.

So I tried it again. I found a trick for this. This time I turned on the fake user. When I reopened the file, the image was present. Don't know if this will really help. But I think I'll just inform.

Added subscribers: @IRIEShinsuke, @kjym3

Added subscribers: @IRIEShinsuke, @kjym3

@kjym3 @IRIEShinsuke what do you think about the fix I described in my previous comment? From what I can see it works well (I also tested on https://download.blender.org/demo/test/AtvBuggy.zip) and causes no crashes or warnings about memory leaks.

I did some more testing, and with or without my code, there are the same number of calls to material_free_data() and ntree_free_data(), strengthening my hypothesis that the removed code is unnecessary.

@kjym3 @IRIEShinsuke what do you think about the fix I described in my previous comment? From what I can see it works well (I also tested on https://download.blender.org/demo/test/AtvBuggy.zip) and causes no crashes or warnings about memory leaks. I did some more testing, and with or without my code, there are the same number of calls to `material_free_data()` and `ntree_free_data()`, strengthening my hypothesis that the removed code is unnecessary.

@Oye_LKY Thanks for the problem report. Using fake users fully makes sense as a workaround, because the reported bug is caused by a wrong decrement of image data block user counts.

@dr.sybren Many thanks for looking into the issue. I confirmed that your proposed fix indeed resolved the problem and no side-effect was seen.

The code segment you proposed to remove was intended to release a material auto-generated by BlenderStrokeRenderer::GetStrokeShader() every time a Freestyle rendering process takes place.

Removing the code seems inappropriate because of a risk of memory leaks. I have no idea why no such leak is seen though.

I tried to address the reported issue by properly incrementing the user counts of image data blocks referenced from texture nodes in Freestyle line style node trees.

diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index c88d5f24b5d..00898f2b5c4 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -252,6 +252,13 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
     // make a copy of linestyle->nodetree
     ntree = ntreeCopyTree_ex(iNodeTree, bmain, do_id_user);

+    // loop over nodes to increment the user count of image data blocks
+    for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) {
+      if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) {
+        id_us_plus(node->id);
+      }
+    }
+
     // find the active Output Line Style node
     for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) {
       if (node->type == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) {

I have a few questions with respect to my solution:

  • Is maintaining ID reference counts in this way the right thing to do? Is there a better way to achieve the same effect?
  • Are there any other ID data blocks referenced from material nodes?

If you or some other main developers could answer these questions, I would be greatly appreciate it.

@Oye_LKY Thanks for the problem report. Using fake users fully makes sense as a workaround, because the reported bug is caused by a wrong decrement of image data block user counts. @dr.sybren Many thanks for looking into the issue. I confirmed that your proposed fix indeed resolved the problem and no side-effect was seen. The code segment you proposed to remove was intended to release a material auto-generated by BlenderStrokeRenderer::GetStrokeShader() every time a Freestyle rendering process takes place. Removing the code seems inappropriate because of a risk of memory leaks. I have no idea why no such leak is seen though. I tried to address the reported issue by properly incrementing the user counts of image data blocks referenced from texture nodes in Freestyle line style node trees. ``` diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index c88d5f24b5d..00898f2b5c4 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -252,6 +252,13 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, // make a copy of linestyle->nodetree ntree = ntreeCopyTree_ex(iNodeTree, bmain, do_id_user); + // loop over nodes to increment the user count of image data blocks + for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) { + if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) { + id_us_plus(node->id); + } + } + // find the active Output Line Style node for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) { if (node->type == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) { ``` I have a few questions with respect to my solution: * Is maintaining ID reference counts in this way the right thing to do? Is there a better way to achieve the same effect? * Are there any other ID data blocks referenced from material nodes? If you or some other main developers could answer these questions, I would be greatly appreciate it.

This issue was referenced by ba8d819c9b

This issue was referenced by ba8d819c9b1ccb7dae50167755167dc3e54bd657

Temporary datablocks used for rendering should not increase user counts on datablocks that are actually part of the .blend file, or modify them in any way that might be visible in the user interface or Python API.

This is all more complicated than it should be though. There is no reason for the freestyle_bmain to exist beyond the lifetime of BlenderStrokeRenderer, that's a leftover from Blender Internal. We can just free the entire thing and not bother trying to manually free particular datablocks.

Temporary datablocks used for rendering should not increase user counts on datablocks that are actually part of the .blend file, or modify them in any way that might be visible in the user interface or Python API. This is all more complicated than it should be though. There is no reason for the `freestyle_bmain` to exist beyond the lifetime of `BlenderStrokeRenderer`, that's a leftover from Blender Internal. We can just free the entire thing and not bother trying to manually free particular datablocks.

Changed status from 'Confirmed' to: 'Resolved'

Changed status from 'Confirmed' to: 'Resolved'
Author

Awesome. You guys are the best.

Awesome. You guys are the best.
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#74417
No description provided.