midora Posted January 10, 2013 Posted January 10, 2013 I'm fighting with this issue, maybe someone can provide a hint. In an effect plugin I created a class and four instances of the class. The class contains as a member an array of matrices. OnSetRenderInfo() calls a member function of the instances to setup these arrays of matrices. OnRender() uses the instances and the matrices to transform points. Now quite often I'm getting the above exception. OnRender() does not modify the matrices. They are just used to do the transformation job. So I would say the matrices are used read only. But for sure it may happen that two WorkerThreads are accessing the same matrix at the same time. It just happens with the matrix member not with other member variables of the instances. Quote
midora Posted January 11, 2013 Author Posted January 11, 2013 BTW: I'm using the following code snippet to avoid the exeption. But for sure it slows down the rendering. So I'm still looking for a better solution. Matrix m; lock (model.matrices[iFace]) { m = model.matrices[iFace].Clone(); } Quote
Rick Brewster Posted January 14, 2013 Posted January 14, 2013 If you're using GDI+ classes like Matrix, you can't use them on multiple threads at the same time. Locking or cloning are the two solutions. Or, don't use GDI+. There are some better ways to do what you need, but the ones I'm thinking of all requires .NET 4.0. Since Paint.NET v3.5.10 operates on .NET 3.5 SP1, you'd have to hand-roll an object pool instead of using System.Collections.Concurrent.ConcurrentBag. It wouldn't be too hard though ... a Dictionary<TKey, Stack<TValue>> with locking around all accesses to it would probably work. (GDI+ == System.Drawing) Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
midora Posted January 14, 2013 Author Posted January 14, 2013 Even cloning failed in OnRender() and this should be a readonly action. And it is not possible to clone in SetRenderInfo because the number of WorkerThreads is unknown ;-) In the meantime I started to replace the Matrix class with my own one. Not because of this issue but Matrix.TransformPoints is really slow. Just replacing this function call improved the rendering speed of the animation in kaleidocycles from 10s to 1.1s... I'm still dreaming that 4.0 would provide a warping methode for polygons on source and dest surface so that I can get rid of this: /*---------------------------------------------------------------------------*\ Function GetBilinearPolygonSamples Purpose Copies an polygonal area from <src> to <dst> respecting a matrix transformation and a clipping rectangle. Remarks The final method of src should not use g and src as parameters. \*---------------------------------------------------------------------------*/ private void GetBilinearPolygonSamples(Graphics g, Surface src, Surface dst, PointF[] polygonDst, Rectangle clipRectDst, Matrix mDstToSrc) { GraphicsPath gpDst = new GraphicsPath(); gpDst.AddPolygon(polygonDst); // Now get for all points in the dst triangle the bilinear samples of src Region region = new Region(gpDst); region.Intersect(clipRectDst); if (region.IsEmpty(g)) return; float[] m = mDstToSrc.Elements; //! mDstToSrc.TransformPoints(point) is more than 10 times slower than to get the elements and do the multiplication yourself RectangleF[] rects = region.GetRegionScans(new Matrix()); for (int ri = 0; ri < rects.Length; ri++) { RectangleF rect = rects[ri]; for (int y = (int)rect.Top; y < rect.Bottom; y++) { for (int x = (int)rect.Left; x < rect.Right; x++) { float pointX = x * m[0] + y * m[2] + m[4]; float pointY = x * m[1] + y * m[3] + m[5]; dst[(int)x, (int)y] = src.GetBilinearSample(pointX, pointY); } } } } /* GetBilinearPolygonSamples */ Any idea for an improvement in the moment? Quote
Rick Brewster Posted January 15, 2013 Posted January 15, 2013 What? Paint.NET 4.0 won't be providing anything of the sort ... I have no idea where you got that idea from. If you want speed, don't use the GDI+ classes. Whether that's Matrix, Region, GraphicsPath, etc. Don't use them. They're slow. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
midora Posted January 23, 2013 Author Posted January 23, 2013 I'm not talking about any gdi extension. I'm just using GDI in the moment to get the region scans. I'm looking for a transformation function from a source to a destination surface which works on a polygon (or maybe just a triangle). You are providing GetBilinearPixel() already to make it easier for a plugin to get an interpolated pixel. A simular funtion for an area would allow plugins to profit from any speed enhancement in Paint.NET. I would expect that there is already such a funtion used in the layer rotate/zoom function. Quote
Rick Brewster Posted January 24, 2013 Posted January 24, 2013 GetBilinearPixel() is there because it's used by built-in effects and of obvious utility to many plugins. Rotate/Zoom doesn't work the way you are thinking it does. Like I said, I'm not going to be implementing a bitmap perspective/polygon transformation gizmo for you. That's your job! I don't know why you'd expect it to already be provided for you. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.