These are chat archives for AvaloniaUI/Avalonia

6th
Feb 2017
Weston
@ronnyek
Feb 06 2017 16:29
@kekekeks saw the .net core progress stuff
good job and you the man
Matthijs ter Woord
@mterwoord
Feb 06 2017 16:49
avalonia doesn't have any kind of automation api, rght?
i know i asked before. don't remember the answer...
Jeremy Koritzinsky
@jkoritzinsky
Feb 06 2017 17:08
Not yet. I think that's on our roadmap? not quite sure
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:33
@grokys I was looking at your serialize-all-the-calls drawing context and realized that it would have awful memory footprint in some cases
For views like this one:
https://i.imgur.com/e1mjKIL.png
It makes tons of drawing calls
It might be worth to allow to either draw some of the controls directly from UI thread
Which will have the same issues as immediate renderer
or
allow to pass custom a rendering callback to retained mode renderer
That will have no thread safety guarantees
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:38
And will be called from render thread
Steven Kirk
@grokys
Feb 06 2017 17:41
yeah, it would be good to be able to have immediate drawing contexts for things like graphs
WPF has the same problem
at least in avalonia you'll be able to switch to using ImmediateRenderer should you wish
we'll also probably want to use an object pool for scene graph nodes at some point
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:46
So they won't be immutable anymore, right?
Steven Kirk
@grokys
Feb 06 2017 17:47
well they'll be immutable for their "lifetime"
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:48
BTW, what are your plans about controls that are using RenderTargetBitmap?
Rasterize, tile, rasterize, tile, flush, repeat
Something like that
Steven Kirk
@grokys
Feb 06 2017 17:49
RTB uses ImmediateRenderer
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:49
Yep, but what if the same RTB is used multiple times?
Steven Kirk
@grokys
Feb 06 2017 17:50
you mean rendering mutliple times to the same RTB?
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:50
yep
Steven Kirk
@grokys
Feb 06 2017 17:50
yeah, you can just render, clear, render again
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:53
void Render(DrawingContext ctx)
{
      var rtb = new RenderT9argetBitmap(100,100);
      using(ctx.PushOpacity(0.01);
      for(int c = 0; c<10000; c++)
      {
              using(var rctx = rtb.CreateDrawingContext())
              {
                  rctx.Clear(Colors.White);
                  rctx.DrawString(c.ToString());
             }
             ctx.DrawBitmap(rtb, c%100, c%100);
      }
}
Something like this
Steven Kirk
@grokys
Feb 06 2017 17:56
yeah, i think that should work
not something i've thought about though tbh
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:57
What are you doing with RTB in DrawBitmap call?
clone or just reference
Steven Kirk
@grokys
Feb 06 2017 17:57
ah i understand. just reference for the moment
we probably need a copy on write thingy there
Nikita Tsukanov
@kekekeks
Feb 06 2017 17:59
The problem is that if you do cloning/copy-on-write
The code above will run out of memory
Since you'll need a clone of the bitmap for each iteration of the cycle
Which is 100x100x4x10000=400MB
Steven Kirk
@grokys
Feb 06 2017 18:00
yeah, so we'd either need to use GC.AddMemoryPressure on the bitmap, or use locking
locking in a render loop isn't good though
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:01
Both won't help
The issue is that you need to serialize 400MB of data
And pass it from UI thread to retained renderer
Steven Kirk
@grokys
Feb 06 2017 18:05
not sure then... maybe "don't do that"?
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:08
Ahahah
Yeah, that's a synthetic example created by the "what could go wrong" train of thought
Render callback might help then
Steven Kirk
@grokys
Feb 06 2017 18:13
heh yeah it's good to explore "what could go wrong"s ;)
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:13
@grokys I have a strong suspicion that we are working in retained mode already
with Direct2D
                public override void Render(DrawingContext ctx)
                {
                    var rtb = new RenderTargetBitmap(100, 100);
                    for (int c = 0; c < 1000; c++)
                    {
                        using (var rctx = rtb.CreateDrawingContext())
                        {
                            rctx.FillRectangle(Brushes.White, new Rect(0, 0, 100, 100));
                            rctx.DrawText(Brushes.Black, new Point(), new FormattedText(c.ToString(),
                                "Arial", 20));
                        }
                        ctx.DrawImage(rtb, 0.1, new Rect(0, 0, 100, 100),
                            new Rect((c % 100) * (c % 4 + 1), (c % 400), 100, 100));
                    }
                }
Direct2D
So basically, what happens here, is that Direct2D makes a snapshot once and then reuses it
Steven Kirk
@grokys
Feb 06 2017 18:17
is this on maser?
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:17
yep
Steven Kirk
@grokys
Feb 06 2017 18:17
i seem to remember there's a Clear call somewhere on master that i had to delete. would that explain it?
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:18
Nope
It seems that's how WicTargetBitmap works in Direct2D
You aren't supposed to reuse it in the same frame
Well, not reuse
Not supposed to update it's contents once it was referenced somewhere
Steven Kirk
@grokys
Feb 06 2017 18:19
strange
it certainly updates the WIC bitmap's contents in scenegraph
as we use them for render layers (bad bad bad)
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:21
You are using them on one-per-layer basis
So it's ok
And contents of the bitmap are being updated
It just rendering pipeline that uses an old snapshot taken previously for the current frame
Steven Kirk
@grokys
Feb 06 2017 18:22
ah ok
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:24
If I change the code to
                public override void Render(DrawingContext ctx)
                {

                    for (int c = 0; c < 1000; c++)
                    {
                        using (var rtb = new RenderTargetBitmap(100, 100))
                        {
                            using (var rctx = rtb.CreateDrawingContext())
                            {
                                rctx.FillRectangle(Brushes.White, new Rect(0, 0, 100, 100));
                                rctx.DrawText(Brushes.Black, new Point(), new FormattedText(c.ToString(),
                                    "Arial", 20));
                            }
                            ctx.DrawImage(rtb, 0.1, new Rect(0, 0, 100, 100),
                                new Rect((c % 100) * (c % 4 + 1), (c % 400), 100, 100));
                        }
                    }
                }
And use a new bitmap each time
Render outputs match
But memory usage skyrockets
                public override void Render(DrawingContext ctx)
                {

                    for (int c = 0; c < 10000; c++)
                    {
                        using (var rtb = new RenderTargetBitmap(100, 100))
                        {
                            using (var rctx = rtb.CreateDrawingContext())
                            {
                                rctx.FillRectangle(Brushes.White, new Rect(0, 0, 100, 100));
                                rctx.DrawText(Brushes.Black, new Point(), new FormattedText(c.ToString(),
                                    "Arial", 20));
                            }
                            ctx.DrawImage(rtb, 0.1, new Rect(0, 0, 100, 100),
                                new Rect((c % 100) * (c % 4 + 1), (c % 400), 100, 100));
                        }
                    }
                    InvalidateVisual();
                }
827MB RAM is used by this code
With Direct2D
17MB RAM with Skia
Quite a difference, huh?
Steven Kirk
@grokys
Feb 06 2017 18:27
yeah, though it doesn't exactly seem like a common use-case
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:28
Also, InvalidateVisual inside Render does nothing
So, what I recommend to do here
Is to mark bitmap as "consumed" on the first usage
And throw exception if someone tries to create a new drawing context
Steven Kirk
@grokys
Feb 06 2017 18:30
so make RTB one-use only?
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:31
Not exactly
Use can use render results multiple times
But once you've used them at least once, you can't render on it anymore
That will allow you to safely pass said bitmap to render thread
Steven Kirk
@grokys
Feb 06 2017 18:32
yeah, that's what i meant by "one-use only". should maybe have said "one render only"
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:33
Yeah, something like that
BTW, what RenderTargetBitmap is currently used for?
VisualBrush?
Steven Kirk
@grokys
Feb 06 2017 18:44
mainly for tests
and for layers, but as i say that needs to change
Nikita Tsukanov
@kekekeks
Feb 06 2017 18:57
I'm thinking about hiding it from user
Because of those shoot-yourself-in-the-foot scenarios
Steven Kirk
@grokys
Feb 06 2017 19:04
no, i think it's useful generally - i think we'd get requests for it if we hid it
we'd just document "you can only render to this once"