Crash when running plugin on complex scene
-
On 21/05/2016 at 10:25, xxxxxxxx wrote:
Hello everybody,
I made a preview plugin, which is basically a GeDialog with an UserArea.
To render the document or the preview, I use a C4DThread.
It is working perfect when I have a simple scene (e.g only a cube, some lights)
But as soon as I try to use my plugin with a bigger scene, more mesh etc.
Cinema 4D just crashes. There is a popup that says: "Application Error!" and then a path to the bugreport.
My problem now is, 1. I don't know why Cinema is crashing and second I don't reall understand the Bugreport.This is the complete code that I use.
import c4d from c4d import gui, plugins, utils, bitmaps, storage from c4d.threading import C4DThread import os PLUGIN_ID = 1037431 b_calculate = 1000 quality = 1010 scale = 1020 antislider = 10016 Render_Image = bitmaps.BaseBitmap() calculating = False dis_width = 0 dis_height = 0 ww = 0 hh = 0 new_rd = None redraw = False class RenderDisplay(gui.GeUserArea) : def GetMinSize(self) : self.width = 250 self.height = 250 return (self.width, self.height) def __init__(self, bmp) : global dis_width global dis_height super(RenderDisplay, self).__init__() self.bmp = Render_Image dis_width = self.GetWidth()/100 dis_height = self.GetHeight()/100 def DrawMsg(self, x1, y1, x2, y2, msg_ref) : self.OffScreenOn() self.SetClippingRegion(x1, y1, x2, y2) Color = self.GetColorRGB(c4d.COLOR_BG) back_color = c4d.Vector(Color['r'] / 255.0, Color['g'] / 255.0, Color['b'] / 255.0) self.DrawSetPen(back_color) self.DrawRectangle(x1, y1, x2, y2) if self.bmp: ww = self.bmp.GetBw() hh = self.bmp.GetBh() if ww > 0 and hh > 0: self.DrawBitmap(self.bmp, 0, 0, self.GetWidth(), self.GetHeight(), 0, 0, ww, hh, c4d.BMP_NORMAL) self.Redraw(True) class Render_Thread(c4d.threading.C4DThread) : def Main(self) : thread = self.Get() doc=c4d.documents.GetActiveDocument() Render_Image.Init(int(ww),int(hh),24) rend = c4d.documents.RenderDocument(doc ,new_rd, Render_Image, c4d.RENDERFLAGS_EXTERNAL|c4d.RENDERFLAGS_NODOCUMENTCLONE, thread) class DiffRender(c4d.gui.GeDialog) : thumbnail = RenderDisplay(None) thread = Render_Thread() def CreateLayout(self) : self.SetTitle("Owl View V2.3") self.AddUserArea(100000, c4d.BFH_CENTER | c4d.BFV_CENTER | c4d.BFH_SCALEFIT |c4d.BFV_SCALEFIT, 3, 3) self.AttachUserArea(self.thumbnail, 100000) self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, title="", rows=4, cols=4,) self.AddEditSlider(id=quality, flags=c4d.BFH_SCALEFIT, initw=50, inith=12) self.AddStaticText(id=scale, flags=c4d.BFH_SCALEFIT | c4d.BFH_CENTER | c4d.BFV_CENTER, initw=120, inith=12, name="--- x ---") self.antislider = self.AddSlider(antislider, c4d.BFH_SCALEFIT, 1, 3) self.AddButton(b_calculate, c4d.BFH_SCALEFIT | c4d.BFH_CENTER | c4d.BFV_CENTER, initw=0, inith=0, name="Render") self.GroupEnd() return True def InitValues(self) : self.SetPercent(quality, 1, min=0.0, max=100.0, step=1.0, tristate=False) doc = c4d.documents.GetActiveDocument() rd = doc.GetActiveRenderData() ww = rd[c4d.RDATA_XRES_VIRTUAL] hh = rd[c4d.RDATA_YRES_VIRTUAL] qual = self.GetReal(quality) self.SetString(id=scale, value="( " + str(int(ww * qual)) + " x " + str(int(hh * qual)) + " )") calculating = True return True def Command(self, id, msg) : global calculating global anti global new_rd global ww global hh doc = c4d.documents.GetActiveDocument() self.qualsli = self.GetReal(quality) self.SetReal(quality, self.qualsli, min=0.01, max=1.0, step=0.01, format=c4d.FORMAT_PERCENT, min2=0.01, max2=1.0, tristate=False) self.antsli = self.GetReal(antislider) self.SetReal(antislider, self.antsli, min=0.0, max=2.0, step=1.0, min2=0.0, max2=2.0, tristate=False) if id == quality: rd = doc.GetActiveRenderData() ww = rd[c4d.RDATA_XRES_VIRTUAL] hh = rd[c4d.RDATA_YRES_VIRTUAL] qual = self.GetReal(quality) self.SetString(id=scale, value="( " + str(int(ww * qual)) + " x " + str(int(hh * qual)) + " )") if id == b_calculate: calculating = True self.thread.Start(mode=c4d.THREADMODE_ASYNC, priority=c4d.THREADPRIORITY_NORMAL) anti = long(self.antsli) rd=doc.GetActiveRenderData() o_ww=rd[c4d.RDATA_XRES] o_hh=rd[c4d.RDATA_YRES] ww=int(o_ww*self.GetReal(quality)) hh=int(o_hh*self.GetReal(quality)) new_rd=doc.GetActiveRenderData().GetData() new_rd[c4d.RDATA_XRES]=ww new_rd[c4d.RDATA_YRES]=hh if anti == 0: new_rd[c4d.RDATA_ANTIALIASING] = 0 if anti == 1: new_rd[c4d.RDATA_ANTIALIASING] = 1 if anti == 2: new_rd[c4d.RDATA_ANTIALIASING] = 2 return True class SimpleCC_CMD(c4d.plugins.CommandData) : dialog = None def Execute(self, doc) : if self.dialog is None: self.dialog = DiffRender() return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaulth=270, defaultw=195) def RestoreLayout(self, sec_ref) : if self.dialog is None: self.dialog = DiffRender() return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref) if __name__ == "__main__": bmp = bitmaps.BaseBitmap() dir, f = os.path.split(__file__) fn = os.path.join(dir, "res", "icon.tif") bmp.InitWith(fn) c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="Owl View", help="A simple plugin to preview your scene", info=0, dat=SimpleCC_CMD(), icon=bmp)
This code works similar to Nitromans Magic Preview, with the squares that shows you the render process, but since I implemented this feature, I get the crashes.
Hopefully someone can help me
greetings,
neon -
On 23/05/2016 at 08:44, xxxxxxxx wrote:
Hi neon,
it looks like you have some severe threading issue. At least when I tried it here in a debugger, I found some evidence of trashed memory.
I hope you don't mind, we can't debug this for you.Some stuff you are doing definitely looks fishy. Not saying any one is the reason for your problem, nor do I think my list is complete. This is just the stuff, that occurred to me immediately:
You store global RenderData in new_rd. You modify this after you have started the thread, which is using it. Most likely a bad idea and in best case your thread is only working on inconsistent RenderData.
Similar with the BaseBitmap you are rendering into. One thread renders into the bitmap, while another reads it in order to display it in the dialog. I would have said, this might work out, if you only changed the bitmap, but you are re-initializing the BaseBitmap from your thread, which has some chance of relocating the image in memory...
I'm also not sure it's a good idea to call Redraw() from DrawMsg(). I'd rather do it the other way round and trigger the redraw from your render thread, like it's done int the Py-MemoryViewer example.
I know, this is probably not the answer you have waited for, but perhaps it still helps.
-
On 23/05/2016 at 10:05, xxxxxxxx wrote:
Hello Andreas,
Thanks for your reply!
Your reply did help me alot, I changed some things like the Redraw call and the RenderData (I really feel kinda dumb about that, should have seen this myself).
And It is not crashing anylonger. I have not started in debugging my code for memory leaks, but as far as I can tell, it doesn't seem to have big issues.But I am very greatfull for your help and your time you invested!
I am now trying to debug it myself and see if I can do something about the trashed memory you mentioned (if there is still any, changed almost all my code ^^)greetings,
neon