C# How to Improve Efficiency in Direct2D Drawing The Next CEO of Stack OverflowHow do I calculate someone's age in C#?What is the difference between String and string in C#?Hidden Features of C#?Calling the base constructor in C#Cast int to enum in C#How do you give a C# Auto-Property a default value?How do I enumerate an enum in C#?How to create Excel (.XLS and .XLSX) file in C# without installing Ms Office?What are the correct version numbers for C#?How do I get a consistent byte representation of strings in C# without manually specifying an encoding?

Sending manuscript to multiple publishers

Does it take more energy to get to Venus or to Mars?

Which tube will fit a -(700 x 25c) wheel?

Can we say or write : "No, it'sn't"?

How do I transpose the 1st and -1th levels of an arbitrarily nested array?

WOW air has ceased operation, can I get my tickets refunded?

How do we know the LHC results are robust?

What was the first Unix version to run on a microcomputer?

Can you replace a racial trait cantrip when leveling up?

sp_blitzCache results Memory grants

How did the Bene Gesserit know how to make a Kwisatz Haderach?

Is it ever safe to open a suspicious html file (e.g. email attachment)?

How do I make a variable always equal to the result of some calculations?

What does convergence in distribution "in the Gromov–Hausdorff" sense mean?

How to count occurrences of text in a file?

Why am I allowed to create multiple unique pointers from a single object?

Example of a Mathematician/Physicist whose Other Publications during their PhD eclipsed their PhD Thesis

Would a galaxy be visible from outside, but nearby?

What happens if you roll doubles 3 times then land on "Go to jail?"

What flight has the highest ratio of time difference to flight time?

In excess I'm lethal

Can someone help

Indicator light circuit

What exact does MIB represent in SNMP? How is it different from OID?



C# How to Improve Efficiency in Direct2D Drawing



The Next CEO of Stack OverflowHow do I calculate someone's age in C#?What is the difference between String and string in C#?Hidden Features of C#?Calling the base constructor in C#Cast int to enum in C#How do you give a C# Auto-Property a default value?How do I enumerate an enum in C#?How to create Excel (.XLS and .XLSX) file in C# without installing Ms Office?What are the correct version numbers for C#?How do I get a consistent byte representation of strings in C# without manually specifying an encoding?










6















Good morning,



I have been teaching myself a bit of Direct2D programming in C#, utilizing native wrappers that are available (currently using d2dSharp, but have also tried SharpDX). I'm running into problems with efficiency, though, where the basic drawing Direct2D drawing methods are taking approximately 250 ms to draw 45,000 basic polygons. The performance I am seeing is on par, or even slower than, Windows GDI+. I'm hoping that someone can take a look at what I've done and propose a way(s) that I can dramatically improve the time it takes to draw.



The background to this is that I have a personal project in which I am developing a basic but functional CAD interface capable of performing a variety of tasks, including 2D finite element analysis. In order to make it at all useful, the interface needs to be able to display tens-of-thousands of primitive elements (polygons, circles, rectangles, points, arcs, etc.).



I initially wrote the drawing methods using Windows GDI+ (System.Drawing), and performance is pretty good until I reach about 3,000 elements on screen at any given time. The screen must be updated any time the user pans, zooms, draws new elements, deletes elements, moves, rotates, etc. Now, in order to improve efficiency, I utilize a quad tree data structure to store my elements, and I only draw elements that actually fall within the bounds of the control window. This helped significantly when zoomed in, but obviously, when fully zoomed out and displaying all elements, it makes no difference. I also use a timer and tick events to update the screen at the refresh rate (60 Hz), so I'm not trying to update thousands of times per second or on every mouse event.



This is my first time programming with DirectX and Direct2D, so I'm definitely learning here. That being said, I've spent days reviewing tutorials, examples, and forums, and could not find much that helped. I've tried a dozen different methods of drawing, pre-processing, multi-threading, etc. My code is below



Code to Loop Through and Draw Elements



List<IDrawingElement> elementsInBounds = GetElementsInDraftingWindow();

_d2dContainer.Target.BeginDraw();
_d2dContainer.Target.Clear(ColorD2D.FromKnown(Colors.White, 1));

if (elementsInBounds.Count > 0)

Stopwatch watch = new Stopwatch();
watch.Start();

#region Using Drawing Element DrawDX Method

foreach (IDrawingElement elem in elementsInBounds)

elem.DrawDX(ref _d2dContainer.Target, ref _d2dContainer.Factory, ZeroPoint, DrawingScale, _selectedElementBrush, _selectedElementPointBrush);


#endregion

watch.Stop();
double drawingTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX drawing time = " + drawingTime);
watch.Reset();
watch.Start();

Matrix3x2 scale = Matrix3x2.Scale(new SizeFD2D((float)DrawingScale, (float)DrawingScale), new PointFD2D(0, 0));
Matrix3x2 translate = Matrix3x2.Translation((float)ZeroPoint.X, (float)ZeroPoint.Y);

_d2dContainer.Target.Transform = scale * translate;

watch.Stop();
double transformTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX transform time = " + transformTime);



DrawDX Function for Polygon



public override void DrawDX(ref WindowRenderTarget rt, ref Direct2DFactory fac, Point zeroPoint, double drawingScale, SolidColorBrush selectedLineBrush, SolidColorBrush selectedPointBrush)

if (_pathGeometry == null)

CreatePathGeometry(ref fac);


float brushWidth = (float)(Layer.Width / (drawingScale));
brushWidth = (float)(brushWidth * 2);

if (Selected == false)

rt.DrawGeometry(Layer.Direct2DBrush, brushWidth, _pathGeometry);
//Note that _pathGeometry is a PathGeometry

else

rt.DrawGeometry(selectedLineBrush, brushWidth, _pathGeometry);




Code to Create Direct2D Factory & Render Target



private void CreateD2DResources(float dpiX, float dpiY)

Factory = Direct2DFactory.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None, FactoryVersion.Auto);

RenderTargetProperties props = new RenderTargetProperties(
RenderTargetType.Default, new PixelFormat(DxgiFormat.B8G8R8A8_UNORM,
AlphaMode.Premultiplied), dpiX, dpiY, RenderTargetUsage.None, FeatureLevel.Default);

Target = Factory.CreateWindowRenderTarget(_targetPanel, PresentOptions.None, props);
Target.AntialiasMode = AntialiasMode.Aliased;

if (_selectionBoxLeftStrokeStyle != null)

_selectionBoxLeftStrokeStyle.Dispose();


_selectionBoxLeftStrokeStyle = Factory.CreateStrokeStyle(new StrokeStyleProperties1(LineCapStyle.Flat,
LineCapStyle.Flat, LineCapStyle.Flat, LineJoin.Bevel, 10, DashStyle.Dash, 0, StrokeTransformType.Normal), null);



I create a Direct2D factory and render target once and keep references to them at all times (that way I'm not recreating each time). I also create all of the brushes when the drawing layer (which describes color, width, etc.) is created. As such, I am not creating a new brush every time I draw, simply referencing a brush that already exists. Same with the geometry, as can be seen in the second code-snippet. I create the geometry once, and only update the geometry if the element itself is moved or rotated. Otherwise, I simply apply a transform to the render target after drawing.



Based on my stopwatches, the time taken to loop through and call the elem.DrawDX methods takes about 225-250 ms (for 45,000 polygons). The time taken to apply the transform is 0-1 ms, so it appears that the bottleneck is in the RenderTarget.DrawGeometry() function.



I've done the same tests with RenderTarget.DrawEllipse() or RenderTarget.DrawRectangle(), as I've read that using DrawGeometry is slower than DrawRectangle or DrawEllipse as the rectangle / ellipse geometry is known beforehand. However, in all of my tests, it hasn't mattered which draw function I use, the time for the same number of elements is always about equal.



I've tried building a multi-threaded Direct2D factory and running the draw functions through tasks, but that is much slower (about two times slower). The Direct2D methods appear to be utilizing my graphics card (hardware accelerated is enabled), as when I monitor my graphics card usage, it spikes when the screen is updating (my laptop has an NVIDIA Quadro mobile graphics card).



Apologies for the long-winded post. I hope this was enough background and description of things I've tried. Thanks in advance for any help!



Edit #1
So changed the code from iterating over a list using foreach to iterating over an array using for and that cut the drawing time down by half! I hadn't realized how much slower lists were than arrays (I knew there was some performance advantage, but didn't realize this much!). It still, however, takes 125 ms to draw. This is much better, but still not smooth. Any other suggestions?










share|improve this question
























  • A list is not slow - foreach is. List<T> is pretty fast and better than using arrays in general.

    – xxbbcc
    Mar 21 at 17:36











  • See this article: codingsight.com/foreach-or-for-that-is-the-question Haven't vetted it myself, and it seems like it might not be 100% correct, but there seems to be some indication that lists are slower than arrays. I will check out using just the list though. See what happens.

    – Anthony
    Mar 21 at 17:44












  • There's a reason that article has 2 stars. List<T> is just an array with internal logic to resize it as needed but that doesn't apply when accessing elements.

    – xxbbcc
    Mar 21 at 17:49












  • Thanks, I didn't see the comment at the bottom of the post until now. Looks like you are correct. In process of changing back to list to make sure performance is the same.

    – Anthony
    Mar 21 at 17:53






  • 1





    Ah, ok. Direct2D should definitely be faster than Win32 GDI (even though both are accelerated). I'm not a D2D expert so I can't help you much there - make sure your output surface is correctly configured. You may also need to consider double- or triple-buffering for fast output and efficient use of clipping things that didn't change from the previous draw.

    – xxbbcc
    Mar 21 at 18:09















6















Good morning,



I have been teaching myself a bit of Direct2D programming in C#, utilizing native wrappers that are available (currently using d2dSharp, but have also tried SharpDX). I'm running into problems with efficiency, though, where the basic drawing Direct2D drawing methods are taking approximately 250 ms to draw 45,000 basic polygons. The performance I am seeing is on par, or even slower than, Windows GDI+. I'm hoping that someone can take a look at what I've done and propose a way(s) that I can dramatically improve the time it takes to draw.



The background to this is that I have a personal project in which I am developing a basic but functional CAD interface capable of performing a variety of tasks, including 2D finite element analysis. In order to make it at all useful, the interface needs to be able to display tens-of-thousands of primitive elements (polygons, circles, rectangles, points, arcs, etc.).



I initially wrote the drawing methods using Windows GDI+ (System.Drawing), and performance is pretty good until I reach about 3,000 elements on screen at any given time. The screen must be updated any time the user pans, zooms, draws new elements, deletes elements, moves, rotates, etc. Now, in order to improve efficiency, I utilize a quad tree data structure to store my elements, and I only draw elements that actually fall within the bounds of the control window. This helped significantly when zoomed in, but obviously, when fully zoomed out and displaying all elements, it makes no difference. I also use a timer and tick events to update the screen at the refresh rate (60 Hz), so I'm not trying to update thousands of times per second or on every mouse event.



This is my first time programming with DirectX and Direct2D, so I'm definitely learning here. That being said, I've spent days reviewing tutorials, examples, and forums, and could not find much that helped. I've tried a dozen different methods of drawing, pre-processing, multi-threading, etc. My code is below



Code to Loop Through and Draw Elements



List<IDrawingElement> elementsInBounds = GetElementsInDraftingWindow();

_d2dContainer.Target.BeginDraw();
_d2dContainer.Target.Clear(ColorD2D.FromKnown(Colors.White, 1));

if (elementsInBounds.Count > 0)

Stopwatch watch = new Stopwatch();
watch.Start();

#region Using Drawing Element DrawDX Method

foreach (IDrawingElement elem in elementsInBounds)

elem.DrawDX(ref _d2dContainer.Target, ref _d2dContainer.Factory, ZeroPoint, DrawingScale, _selectedElementBrush, _selectedElementPointBrush);


#endregion

watch.Stop();
double drawingTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX drawing time = " + drawingTime);
watch.Reset();
watch.Start();

Matrix3x2 scale = Matrix3x2.Scale(new SizeFD2D((float)DrawingScale, (float)DrawingScale), new PointFD2D(0, 0));
Matrix3x2 translate = Matrix3x2.Translation((float)ZeroPoint.X, (float)ZeroPoint.Y);

_d2dContainer.Target.Transform = scale * translate;

watch.Stop();
double transformTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX transform time = " + transformTime);



DrawDX Function for Polygon



public override void DrawDX(ref WindowRenderTarget rt, ref Direct2DFactory fac, Point zeroPoint, double drawingScale, SolidColorBrush selectedLineBrush, SolidColorBrush selectedPointBrush)

if (_pathGeometry == null)

CreatePathGeometry(ref fac);


float brushWidth = (float)(Layer.Width / (drawingScale));
brushWidth = (float)(brushWidth * 2);

if (Selected == false)

rt.DrawGeometry(Layer.Direct2DBrush, brushWidth, _pathGeometry);
//Note that _pathGeometry is a PathGeometry

else

rt.DrawGeometry(selectedLineBrush, brushWidth, _pathGeometry);




Code to Create Direct2D Factory & Render Target



private void CreateD2DResources(float dpiX, float dpiY)

Factory = Direct2DFactory.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None, FactoryVersion.Auto);

RenderTargetProperties props = new RenderTargetProperties(
RenderTargetType.Default, new PixelFormat(DxgiFormat.B8G8R8A8_UNORM,
AlphaMode.Premultiplied), dpiX, dpiY, RenderTargetUsage.None, FeatureLevel.Default);

Target = Factory.CreateWindowRenderTarget(_targetPanel, PresentOptions.None, props);
Target.AntialiasMode = AntialiasMode.Aliased;

if (_selectionBoxLeftStrokeStyle != null)

_selectionBoxLeftStrokeStyle.Dispose();


_selectionBoxLeftStrokeStyle = Factory.CreateStrokeStyle(new StrokeStyleProperties1(LineCapStyle.Flat,
LineCapStyle.Flat, LineCapStyle.Flat, LineJoin.Bevel, 10, DashStyle.Dash, 0, StrokeTransformType.Normal), null);



I create a Direct2D factory and render target once and keep references to them at all times (that way I'm not recreating each time). I also create all of the brushes when the drawing layer (which describes color, width, etc.) is created. As such, I am not creating a new brush every time I draw, simply referencing a brush that already exists. Same with the geometry, as can be seen in the second code-snippet. I create the geometry once, and only update the geometry if the element itself is moved or rotated. Otherwise, I simply apply a transform to the render target after drawing.



Based on my stopwatches, the time taken to loop through and call the elem.DrawDX methods takes about 225-250 ms (for 45,000 polygons). The time taken to apply the transform is 0-1 ms, so it appears that the bottleneck is in the RenderTarget.DrawGeometry() function.



I've done the same tests with RenderTarget.DrawEllipse() or RenderTarget.DrawRectangle(), as I've read that using DrawGeometry is slower than DrawRectangle or DrawEllipse as the rectangle / ellipse geometry is known beforehand. However, in all of my tests, it hasn't mattered which draw function I use, the time for the same number of elements is always about equal.



I've tried building a multi-threaded Direct2D factory and running the draw functions through tasks, but that is much slower (about two times slower). The Direct2D methods appear to be utilizing my graphics card (hardware accelerated is enabled), as when I monitor my graphics card usage, it spikes when the screen is updating (my laptop has an NVIDIA Quadro mobile graphics card).



Apologies for the long-winded post. I hope this was enough background and description of things I've tried. Thanks in advance for any help!



Edit #1
So changed the code from iterating over a list using foreach to iterating over an array using for and that cut the drawing time down by half! I hadn't realized how much slower lists were than arrays (I knew there was some performance advantage, but didn't realize this much!). It still, however, takes 125 ms to draw. This is much better, but still not smooth. Any other suggestions?










share|improve this question
























  • A list is not slow - foreach is. List<T> is pretty fast and better than using arrays in general.

    – xxbbcc
    Mar 21 at 17:36











  • See this article: codingsight.com/foreach-or-for-that-is-the-question Haven't vetted it myself, and it seems like it might not be 100% correct, but there seems to be some indication that lists are slower than arrays. I will check out using just the list though. See what happens.

    – Anthony
    Mar 21 at 17:44












  • There's a reason that article has 2 stars. List<T> is just an array with internal logic to resize it as needed but that doesn't apply when accessing elements.

    – xxbbcc
    Mar 21 at 17:49












  • Thanks, I didn't see the comment at the bottom of the post until now. Looks like you are correct. In process of changing back to list to make sure performance is the same.

    – Anthony
    Mar 21 at 17:53






  • 1





    Ah, ok. Direct2D should definitely be faster than Win32 GDI (even though both are accelerated). I'm not a D2D expert so I can't help you much there - make sure your output surface is correctly configured. You may also need to consider double- or triple-buffering for fast output and efficient use of clipping things that didn't change from the previous draw.

    – xxbbcc
    Mar 21 at 18:09













6












6








6


1






Good morning,



I have been teaching myself a bit of Direct2D programming in C#, utilizing native wrappers that are available (currently using d2dSharp, but have also tried SharpDX). I'm running into problems with efficiency, though, where the basic drawing Direct2D drawing methods are taking approximately 250 ms to draw 45,000 basic polygons. The performance I am seeing is on par, or even slower than, Windows GDI+. I'm hoping that someone can take a look at what I've done and propose a way(s) that I can dramatically improve the time it takes to draw.



The background to this is that I have a personal project in which I am developing a basic but functional CAD interface capable of performing a variety of tasks, including 2D finite element analysis. In order to make it at all useful, the interface needs to be able to display tens-of-thousands of primitive elements (polygons, circles, rectangles, points, arcs, etc.).



I initially wrote the drawing methods using Windows GDI+ (System.Drawing), and performance is pretty good until I reach about 3,000 elements on screen at any given time. The screen must be updated any time the user pans, zooms, draws new elements, deletes elements, moves, rotates, etc. Now, in order to improve efficiency, I utilize a quad tree data structure to store my elements, and I only draw elements that actually fall within the bounds of the control window. This helped significantly when zoomed in, but obviously, when fully zoomed out and displaying all elements, it makes no difference. I also use a timer and tick events to update the screen at the refresh rate (60 Hz), so I'm not trying to update thousands of times per second or on every mouse event.



This is my first time programming with DirectX and Direct2D, so I'm definitely learning here. That being said, I've spent days reviewing tutorials, examples, and forums, and could not find much that helped. I've tried a dozen different methods of drawing, pre-processing, multi-threading, etc. My code is below



Code to Loop Through and Draw Elements



List<IDrawingElement> elementsInBounds = GetElementsInDraftingWindow();

_d2dContainer.Target.BeginDraw();
_d2dContainer.Target.Clear(ColorD2D.FromKnown(Colors.White, 1));

if (elementsInBounds.Count > 0)

Stopwatch watch = new Stopwatch();
watch.Start();

#region Using Drawing Element DrawDX Method

foreach (IDrawingElement elem in elementsInBounds)

elem.DrawDX(ref _d2dContainer.Target, ref _d2dContainer.Factory, ZeroPoint, DrawingScale, _selectedElementBrush, _selectedElementPointBrush);


#endregion

watch.Stop();
double drawingTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX drawing time = " + drawingTime);
watch.Reset();
watch.Start();

Matrix3x2 scale = Matrix3x2.Scale(new SizeFD2D((float)DrawingScale, (float)DrawingScale), new PointFD2D(0, 0));
Matrix3x2 translate = Matrix3x2.Translation((float)ZeroPoint.X, (float)ZeroPoint.Y);

_d2dContainer.Target.Transform = scale * translate;

watch.Stop();
double transformTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX transform time = " + transformTime);



DrawDX Function for Polygon



public override void DrawDX(ref WindowRenderTarget rt, ref Direct2DFactory fac, Point zeroPoint, double drawingScale, SolidColorBrush selectedLineBrush, SolidColorBrush selectedPointBrush)

if (_pathGeometry == null)

CreatePathGeometry(ref fac);


float brushWidth = (float)(Layer.Width / (drawingScale));
brushWidth = (float)(brushWidth * 2);

if (Selected == false)

rt.DrawGeometry(Layer.Direct2DBrush, brushWidth, _pathGeometry);
//Note that _pathGeometry is a PathGeometry

else

rt.DrawGeometry(selectedLineBrush, brushWidth, _pathGeometry);




Code to Create Direct2D Factory & Render Target



private void CreateD2DResources(float dpiX, float dpiY)

Factory = Direct2DFactory.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None, FactoryVersion.Auto);

RenderTargetProperties props = new RenderTargetProperties(
RenderTargetType.Default, new PixelFormat(DxgiFormat.B8G8R8A8_UNORM,
AlphaMode.Premultiplied), dpiX, dpiY, RenderTargetUsage.None, FeatureLevel.Default);

Target = Factory.CreateWindowRenderTarget(_targetPanel, PresentOptions.None, props);
Target.AntialiasMode = AntialiasMode.Aliased;

if (_selectionBoxLeftStrokeStyle != null)

_selectionBoxLeftStrokeStyle.Dispose();


_selectionBoxLeftStrokeStyle = Factory.CreateStrokeStyle(new StrokeStyleProperties1(LineCapStyle.Flat,
LineCapStyle.Flat, LineCapStyle.Flat, LineJoin.Bevel, 10, DashStyle.Dash, 0, StrokeTransformType.Normal), null);



I create a Direct2D factory and render target once and keep references to them at all times (that way I'm not recreating each time). I also create all of the brushes when the drawing layer (which describes color, width, etc.) is created. As such, I am not creating a new brush every time I draw, simply referencing a brush that already exists. Same with the geometry, as can be seen in the second code-snippet. I create the geometry once, and only update the geometry if the element itself is moved or rotated. Otherwise, I simply apply a transform to the render target after drawing.



Based on my stopwatches, the time taken to loop through and call the elem.DrawDX methods takes about 225-250 ms (for 45,000 polygons). The time taken to apply the transform is 0-1 ms, so it appears that the bottleneck is in the RenderTarget.DrawGeometry() function.



I've done the same tests with RenderTarget.DrawEllipse() or RenderTarget.DrawRectangle(), as I've read that using DrawGeometry is slower than DrawRectangle or DrawEllipse as the rectangle / ellipse geometry is known beforehand. However, in all of my tests, it hasn't mattered which draw function I use, the time for the same number of elements is always about equal.



I've tried building a multi-threaded Direct2D factory and running the draw functions through tasks, but that is much slower (about two times slower). The Direct2D methods appear to be utilizing my graphics card (hardware accelerated is enabled), as when I monitor my graphics card usage, it spikes when the screen is updating (my laptop has an NVIDIA Quadro mobile graphics card).



Apologies for the long-winded post. I hope this was enough background and description of things I've tried. Thanks in advance for any help!



Edit #1
So changed the code from iterating over a list using foreach to iterating over an array using for and that cut the drawing time down by half! I hadn't realized how much slower lists were than arrays (I knew there was some performance advantage, but didn't realize this much!). It still, however, takes 125 ms to draw. This is much better, but still not smooth. Any other suggestions?










share|improve this question
















Good morning,



I have been teaching myself a bit of Direct2D programming in C#, utilizing native wrappers that are available (currently using d2dSharp, but have also tried SharpDX). I'm running into problems with efficiency, though, where the basic drawing Direct2D drawing methods are taking approximately 250 ms to draw 45,000 basic polygons. The performance I am seeing is on par, or even slower than, Windows GDI+. I'm hoping that someone can take a look at what I've done and propose a way(s) that I can dramatically improve the time it takes to draw.



The background to this is that I have a personal project in which I am developing a basic but functional CAD interface capable of performing a variety of tasks, including 2D finite element analysis. In order to make it at all useful, the interface needs to be able to display tens-of-thousands of primitive elements (polygons, circles, rectangles, points, arcs, etc.).



I initially wrote the drawing methods using Windows GDI+ (System.Drawing), and performance is pretty good until I reach about 3,000 elements on screen at any given time. The screen must be updated any time the user pans, zooms, draws new elements, deletes elements, moves, rotates, etc. Now, in order to improve efficiency, I utilize a quad tree data structure to store my elements, and I only draw elements that actually fall within the bounds of the control window. This helped significantly when zoomed in, but obviously, when fully zoomed out and displaying all elements, it makes no difference. I also use a timer and tick events to update the screen at the refresh rate (60 Hz), so I'm not trying to update thousands of times per second or on every mouse event.



This is my first time programming with DirectX and Direct2D, so I'm definitely learning here. That being said, I've spent days reviewing tutorials, examples, and forums, and could not find much that helped. I've tried a dozen different methods of drawing, pre-processing, multi-threading, etc. My code is below



Code to Loop Through and Draw Elements



List<IDrawingElement> elementsInBounds = GetElementsInDraftingWindow();

_d2dContainer.Target.BeginDraw();
_d2dContainer.Target.Clear(ColorD2D.FromKnown(Colors.White, 1));

if (elementsInBounds.Count > 0)

Stopwatch watch = new Stopwatch();
watch.Start();

#region Using Drawing Element DrawDX Method

foreach (IDrawingElement elem in elementsInBounds)

elem.DrawDX(ref _d2dContainer.Target, ref _d2dContainer.Factory, ZeroPoint, DrawingScale, _selectedElementBrush, _selectedElementPointBrush);


#endregion

watch.Stop();
double drawingTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX drawing time = " + drawingTime);
watch.Reset();
watch.Start();

Matrix3x2 scale = Matrix3x2.Scale(new SizeFD2D((float)DrawingScale, (float)DrawingScale), new PointFD2D(0, 0));
Matrix3x2 translate = Matrix3x2.Translation((float)ZeroPoint.X, (float)ZeroPoint.Y);

_d2dContainer.Target.Transform = scale * translate;

watch.Stop();
double transformTime = watch.ElapsedMilliseconds;
Console.WriteLine("DirectX transform time = " + transformTime);



DrawDX Function for Polygon



public override void DrawDX(ref WindowRenderTarget rt, ref Direct2DFactory fac, Point zeroPoint, double drawingScale, SolidColorBrush selectedLineBrush, SolidColorBrush selectedPointBrush)

if (_pathGeometry == null)

CreatePathGeometry(ref fac);


float brushWidth = (float)(Layer.Width / (drawingScale));
brushWidth = (float)(brushWidth * 2);

if (Selected == false)

rt.DrawGeometry(Layer.Direct2DBrush, brushWidth, _pathGeometry);
//Note that _pathGeometry is a PathGeometry

else

rt.DrawGeometry(selectedLineBrush, brushWidth, _pathGeometry);




Code to Create Direct2D Factory & Render Target



private void CreateD2DResources(float dpiX, float dpiY)

Factory = Direct2DFactory.CreateFactory(FactoryType.SingleThreaded, DebugLevel.None, FactoryVersion.Auto);

RenderTargetProperties props = new RenderTargetProperties(
RenderTargetType.Default, new PixelFormat(DxgiFormat.B8G8R8A8_UNORM,
AlphaMode.Premultiplied), dpiX, dpiY, RenderTargetUsage.None, FeatureLevel.Default);

Target = Factory.CreateWindowRenderTarget(_targetPanel, PresentOptions.None, props);
Target.AntialiasMode = AntialiasMode.Aliased;

if (_selectionBoxLeftStrokeStyle != null)

_selectionBoxLeftStrokeStyle.Dispose();


_selectionBoxLeftStrokeStyle = Factory.CreateStrokeStyle(new StrokeStyleProperties1(LineCapStyle.Flat,
LineCapStyle.Flat, LineCapStyle.Flat, LineJoin.Bevel, 10, DashStyle.Dash, 0, StrokeTransformType.Normal), null);



I create a Direct2D factory and render target once and keep references to them at all times (that way I'm not recreating each time). I also create all of the brushes when the drawing layer (which describes color, width, etc.) is created. As such, I am not creating a new brush every time I draw, simply referencing a brush that already exists. Same with the geometry, as can be seen in the second code-snippet. I create the geometry once, and only update the geometry if the element itself is moved or rotated. Otherwise, I simply apply a transform to the render target after drawing.



Based on my stopwatches, the time taken to loop through and call the elem.DrawDX methods takes about 225-250 ms (for 45,000 polygons). The time taken to apply the transform is 0-1 ms, so it appears that the bottleneck is in the RenderTarget.DrawGeometry() function.



I've done the same tests with RenderTarget.DrawEllipse() or RenderTarget.DrawRectangle(), as I've read that using DrawGeometry is slower than DrawRectangle or DrawEllipse as the rectangle / ellipse geometry is known beforehand. However, in all of my tests, it hasn't mattered which draw function I use, the time for the same number of elements is always about equal.



I've tried building a multi-threaded Direct2D factory and running the draw functions through tasks, but that is much slower (about two times slower). The Direct2D methods appear to be utilizing my graphics card (hardware accelerated is enabled), as when I monitor my graphics card usage, it spikes when the screen is updating (my laptop has an NVIDIA Quadro mobile graphics card).



Apologies for the long-winded post. I hope this was enough background and description of things I've tried. Thanks in advance for any help!



Edit #1
So changed the code from iterating over a list using foreach to iterating over an array using for and that cut the drawing time down by half! I hadn't realized how much slower lists were than arrays (I knew there was some performance advantage, but didn't realize this much!). It still, however, takes 125 ms to draw. This is much better, but still not smooth. Any other suggestions?







c# direct2d






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 21 at 17:26







Anthony

















asked Mar 21 at 17:07









AnthonyAnthony

343




343












  • A list is not slow - foreach is. List<T> is pretty fast and better than using arrays in general.

    – xxbbcc
    Mar 21 at 17:36











  • See this article: codingsight.com/foreach-or-for-that-is-the-question Haven't vetted it myself, and it seems like it might not be 100% correct, but there seems to be some indication that lists are slower than arrays. I will check out using just the list though. See what happens.

    – Anthony
    Mar 21 at 17:44












  • There's a reason that article has 2 stars. List<T> is just an array with internal logic to resize it as needed but that doesn't apply when accessing elements.

    – xxbbcc
    Mar 21 at 17:49












  • Thanks, I didn't see the comment at the bottom of the post until now. Looks like you are correct. In process of changing back to list to make sure performance is the same.

    – Anthony
    Mar 21 at 17:53






  • 1





    Ah, ok. Direct2D should definitely be faster than Win32 GDI (even though both are accelerated). I'm not a D2D expert so I can't help you much there - make sure your output surface is correctly configured. You may also need to consider double- or triple-buffering for fast output and efficient use of clipping things that didn't change from the previous draw.

    – xxbbcc
    Mar 21 at 18:09

















  • A list is not slow - foreach is. List<T> is pretty fast and better than using arrays in general.

    – xxbbcc
    Mar 21 at 17:36











  • See this article: codingsight.com/foreach-or-for-that-is-the-question Haven't vetted it myself, and it seems like it might not be 100% correct, but there seems to be some indication that lists are slower than arrays. I will check out using just the list though. See what happens.

    – Anthony
    Mar 21 at 17:44












  • There's a reason that article has 2 stars. List<T> is just an array with internal logic to resize it as needed but that doesn't apply when accessing elements.

    – xxbbcc
    Mar 21 at 17:49












  • Thanks, I didn't see the comment at the bottom of the post until now. Looks like you are correct. In process of changing back to list to make sure performance is the same.

    – Anthony
    Mar 21 at 17:53






  • 1





    Ah, ok. Direct2D should definitely be faster than Win32 GDI (even though both are accelerated). I'm not a D2D expert so I can't help you much there - make sure your output surface is correctly configured. You may also need to consider double- or triple-buffering for fast output and efficient use of clipping things that didn't change from the previous draw.

    – xxbbcc
    Mar 21 at 18:09
















A list is not slow - foreach is. List<T> is pretty fast and better than using arrays in general.

– xxbbcc
Mar 21 at 17:36





A list is not slow - foreach is. List<T> is pretty fast and better than using arrays in general.

– xxbbcc
Mar 21 at 17:36













See this article: codingsight.com/foreach-or-for-that-is-the-question Haven't vetted it myself, and it seems like it might not be 100% correct, but there seems to be some indication that lists are slower than arrays. I will check out using just the list though. See what happens.

– Anthony
Mar 21 at 17:44






See this article: codingsight.com/foreach-or-for-that-is-the-question Haven't vetted it myself, and it seems like it might not be 100% correct, but there seems to be some indication that lists are slower than arrays. I will check out using just the list though. See what happens.

– Anthony
Mar 21 at 17:44














There's a reason that article has 2 stars. List<T> is just an array with internal logic to resize it as needed but that doesn't apply when accessing elements.

– xxbbcc
Mar 21 at 17:49






There's a reason that article has 2 stars. List<T> is just an array with internal logic to resize it as needed but that doesn't apply when accessing elements.

– xxbbcc
Mar 21 at 17:49














Thanks, I didn't see the comment at the bottom of the post until now. Looks like you are correct. In process of changing back to list to make sure performance is the same.

– Anthony
Mar 21 at 17:53





Thanks, I didn't see the comment at the bottom of the post until now. Looks like you are correct. In process of changing back to list to make sure performance is the same.

– Anthony
Mar 21 at 17:53




1




1





Ah, ok. Direct2D should definitely be faster than Win32 GDI (even though both are accelerated). I'm not a D2D expert so I can't help you much there - make sure your output surface is correctly configured. You may also need to consider double- or triple-buffering for fast output and efficient use of clipping things that didn't change from the previous draw.

– xxbbcc
Mar 21 at 18:09





Ah, ok. Direct2D should definitely be faster than Win32 GDI (even though both are accelerated). I'm not a D2D expert so I can't help you much there - make sure your output surface is correctly configured. You may also need to consider double- or triple-buffering for fast output and efficient use of clipping things that didn't change from the previous draw.

– xxbbcc
Mar 21 at 18:09












0






active

oldest

votes












Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55285723%2fc-sharp-how-to-improve-efficiency-in-direct2d-drawing%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55285723%2fc-sharp-how-to-improve-efficiency-in-direct2d-drawing%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript