I’m experimenting with creating a CustomRenderableSeries.
I was expecting VisualXcceleratorRenderSurface to perform the fastest. But what I am finding is that it is noticeably slower than XamlRenderSurface. By slower, I mean interaction with zoom/pan becomes choppy and resizing the window is choppy. Which is surprising because I’m really not rendering much at all.
We plan on rendering a lot more than this, but it already appears to struggling. Can you shed some light?
public class MyDataSeries : XyDataSeries<double>
{
public MyDataSeries()
{
}
}
public class MyRenderableSeries : CustomRenderableSeries
{
public MyRenderableSeries()
{
}
protected override void Draw(IRenderContext2D renderContext, IRenderPassData renderPassData)
{
base.Draw(renderContext, renderPassData);
if (DataSeries is not MyDataSeries series)
return;
using (var brush = renderContext.CreateBrush(Brushes.Red))
using (var pen = renderContext.CreatePen(Colors.Black, true, 1))
{
for (int i = 0; i < series.Count; ++i)
{
double pos = (double)series.XValues[i];
var x = renderPassData.XCoordinateCalculator.GetCoordinate(pos);
var y = renderPassData.YCoordinateCalculator.GetCoordinate(pos);
var s = renderPassData.XCoordinateCalculator.GetCoordinate(0) - renderPassData.XCoordinateCalculator.GetCoordinate(1);
var points = CreateCircle(new Point(x, y), s);
renderContext.FillPolygon(brush, points);
}
}
}
private List<Point> CreateCircle(Point pos, double radius)
{
var points = new List<Point>();
int count = 1000;
for (int i = 0; i < count; ++i)
{
double angle = (360.0 / count * i) * (Math.PI / 180);
double x = Math.Cos(angle) * radius;
double y = Math.Sin(angle) * radius;
points.Add(new Point(pos.X + x, pos.Y + y));
}
points.Add(points[0]);
return points;
}
}
public class MyRenderableSeriesViewModel : BaseRenderableSeriesViewModel
{
public override Type ViewType => typeof(MyRenderableSeries);
}
public class MyViewModel : BaseViewModel
{
public List<IRenderableSeriesViewModel> RenderableSeriesViewModels { get; }
public MyViewModel()
{
RenderableSeriesViewModels = new List<IRenderableSeriesViewModel>
{
Generate(Enumerable.Range(0, 25).Select(x => (double)x).ToArray()),
};
}
private IRenderableSeriesViewModel Generate(double[] data)
{
var dataSeries = new MyDataSeries();
dataSeries.Append(data, data);
return new MyRenderableSeriesViewModel
{
DataSeries = dataSeries,
StyleKey = "mySeriesStyle"
};
}
}
<UserControl x:Class="SciChart.Examples.Examples.SeeFeaturedApplication.Histogram.ViolinView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:s="http://schemas.abtsoftware.co.uk/scichart"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SciChart.Examples.Examples.SeeFeaturedApplication.Histogram"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/SciChart.Charting;component/Themes/Default.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:MyRenderableSeries}"
BasedOn="{StaticResource MvvmDefaultRenderableSeriesStyle}"
x:Key="mySeriesStyle">
</Style>
</ResourceDictionary>
</UserControl.Resources>
<s:SciChartSurface x:Name="SciChart"
RenderableSeries="{s:SeriesBinding RenderableSeriesViewModels}">
<s:SciChartSurface.RenderSurface>
<s:VisualXcceleratorRenderSurface />
</s:SciChartSurface.RenderSurface>
<s:SciChartSurface.XAxis>
<s:NumericAxis />
</s:SciChartSurface.XAxis>
<s:SciChartSurface.YAxis>
<s:NumericAxis />
</s:SciChartSurface.YAxis>
<s:SciChartSurface.ChartModifier>
<s:ModifierGroup>
<s:ZoomPanModifier />
<s:RubberBandXyZoomModifier ExecuteOn="MouseRightButton" />
<s:ZoomExtentsModifier ReceiveHandledEvents="False" />
<s:MouseWheelZoomModifier />
</s:ModifierGroup>
</s:SciChartSurface.ChartModifier>
</s:SciChartSurface>
I have tested this on 3 machines, and all show the same behaviour.
**VisualXcceleratorEngine: Creating VisualXcceleratorRenderSurface Visual Xccelerator Engine v7.0.1.27055
GPU Capability Test ### Is BGRA feature required: TRUE
Examining Graphics Adapter: Intel(R) Iris(R) Xe Graphics VRAM:
128Mb DeviceId: 39497Visual Xccelerator Engine Direct3D9 Compatibility
Determines whether the adapter is blacklisted due to its unstable work… FALSE
Trying to create Direct3D9 Device… SUCCESSVisual Xccelerator Engine Direct3D11 Compatibility
Trying to create Direct3D9Ex Device (WPF Compatibility)… SUCCESS
Trying to create Direct3D11 Device… SUCCESSRank: 3000128 Points
Examining Graphics Adapter: NVIDIA T500 VRAM: 1928Mb DeviceId:
8123Visual Xccelerator Engine Direct3D9 Compatibility
Determines whether the adapter is blacklisted due to its unstable work… FALSE
Trying to create Direct3D9 Device… FAILEDVisual Xccelerator Engine Direct3D11 Compatibility
Trying to create Direct3D9Ex Device (WPF Compatibility)… FAILED
Trying to create Direct3D11 Device… SUCCESSRank: 3001928 Points
Examining Graphics Adapter: Microsoft Basic Render Driver VRAM: 0Mb
DeviceId: 140Visual Xccelerator Engine Direct3D9 Compatibility
Determines whether the adapter is blacklisted due to its unstable work… FALSE
Trying to create Direct3D9 Device… FAILEDVisual Xccelerator Engine Direct3D11 Compatibility
Trying to create Direct3D9Ex Device (WPF Compatibility)… FAILED
Trying to create Direct3D11 Device… SUCCESSRank: 2000000 Points
Selected Graphics Adapter, where DeviceId is: 8123 Is Direct3D9
Supported: FALSE Is Direct3D11 Supported: TRUE Is Blacklisted:
FALSEPlease find the log file here:
C:\dev\TestApps\SciChart_Violin\bin\Debug\net6.0-windows\GpuCapability.log**VisualXcceleratorEngine: SUCCESS! VisualXcceleratorRenderSurface: attempt to initialize the engine with parameters: Use Direct3D9 –
False
- Ben Green asked 1 year ago
- last edited 1 year ago
-
Have you profiled the code? CreatePen, CreateBrush are a huge bottleneck in VisualXcceleratorRenderSurface. Ideally you want to create these once when stroke/fill is changed and only recreate when needed. FillPolygon also requires tesselation CPU side. It would be faster to create raw triangles and send them to the GPU. There’s no API to do raw triangles in 2D but if you tell us more about the use case we can expose something suitable.
-
I’ve now cached the pen/brush so they’re only created once, but unfortunately has made no difference. Basically, we’re creating a CustomRenderableSeries so we can render Violin charts, so we need to render custom polygons. I’ve managed to get it working performantly with XamlRenderSurface, I was just surprised to see how badly it performs with VisualXcceleratorRenderSurface?? This seems completely backwards to me, as it should be much more performant than WPF polygons? I’ve worked with SlimDx/SharpDX in the past and they can easily handle 25,000 vertices being updated each frame, so it feels like there is a bottleneck somewhere?
-
Well the reason why is that we haven’t optimised this as it’s a very rare use-case. VisualXcceleratorRenderSurface is highly optimised for cached geometry that we use in SciChart like lines, columns, scatter, mountains etc. All of which use batching to overcome GPU / DirectX limitations. The IRenderContext2D however has to be backward compatible to the old render surface types so we have implemented shims for each function like IRenderContext.DrawPolygon. The ideal thing would be for you to profile it and send us a profiling report using dotTrace. Or, code to reproduce that we can profile ourselves. From that we can optimise. Should be easy to do – we just need something to work with.
- You must login to post comments
Hi Ben,
Waiting on code to reproduce this so our team can profile & optimise.
Best regards,
Andrew
- Andrew Burnett-Thompson answered 1 year ago
- You must login to post comments
Hi Andrew,
I provided the code to reproduce the issue in the question? The bit where it calls CreateCircle is basically where we’re doing our own rendering using FillPolygon. The example using the circle demonstrates the issue in the same way.
Did you want a VS solution instead?
One other point which might be useful is that technically, we don’t need to recreate the geometry every frame. So if there was a way to create the geometry once, and cache it, then simply call renderContext with the cached geometry, that would also work for us. I assume this would get around the issues of tessellating every frame and only tessellating once?
- Ben Green answered 1 year ago
- last edited 1 year ago
-
Hi Ben, it would be helpful if it won’t take too much time, because we can look at the whole use case and think of ways to optimise it. At the moment it’s likely DrawPolygon() is a bottleneck and we can promise that one function, but without your solution wouldn’t be able to see the impact and whether it actually helps, or if another bottleneck is revealed
- You must login to post comments
Hi Ben,
We haven’t heard from you for a while.
Could you please tell if this issue is still relevant for you and did you have a chance to prepare a small sample project for us?
You can also submit the project via our priority support ticketing system if you don’t wish to share a code in public. Here is a corresponding link:
https://www.scichart.com/contact-us/#tech-support
With best regards,
Lex
SciChart Technical Support Engineer
- Lex answered 11 months ago
- You must login to post comments
Please login first to submit.