问题描述
对不起,这么长,我想证明足够的代码,因为它本身很难解释
我正在设置一个小型测试程序来制作 2D 视觉仪表。项目的结构是我有一个类; 'DirectX11Renderer' 初始化所有 SharpDX 对象以设置工厂、设备、后台缓冲区、渲染目标、交换链和层。
这个类然后包含用于绘制基本形状、填充形状和文本的绘制方法,它们很可能被忽略,但是程序的想法是能够在一层(背景、没有真正移动的东西)和另一层上的动态内容,因此每个绘图方法都有一个枚举作为参数,指定要在其上绘制的层,然后将其传递给此方法,该方法开始在渲染目标上绘制(如果还没有),弹出最后推入的图层(如果有的话)并推入需要绘制的图层:
private void StartDrawingAndSwitchLayer(TargetLayer layer,bool draw = true)
{
if (draw && !isDrawing)
{
d2drendertarget.BeginDraw();
isDrawing = true;
}
switch (layer)
{
case TargetLayer.Static:
if (isDynamicLayerPushed)
{
d2drendertarget.PopLayer();
isDynamicLayerPushed = false;
}
if (!isstaticLayerPushed)
{
d2drendertarget.PushLayer(ref layerParams,staticLayer);
isstaticLayerPushed = true;
}
break;
case TargetLayer.Dynamic:
if (isstaticLayerPushed)
{
d2drendertarget.PopLayer();
isstaticLayerPushed = false;
}
if (!isDynamicLayerPushed)
{
d2drendertarget.PushLayer(ref layerParams,dynamicLayer);
isDynamicLayerPushed = true;
}
break;
case TargetLayer.None:
if (isstaticLayerPushed)
{
d2drendertarget.PopLayer();
isstaticLayerPushed = false;
}
if (isDynamicLayerPushed)
{
d2drendertarget.PopLayer();
isDynamicLayerPushed = false;
}
break;
}
if (!draw && isDrawing)
{
d2drendertarget.EndDraw();
isDrawing = false;
}
}
因此,在使用此 DirectX11Renderer 类实例的类中,它首先设置背景颜色而不推送图层,通过清除图层来渲染静态内容,然后使用静态图层作为参数调用几个绘制方法让枚举推送静态图层,然后在每次值更改时渲染动态内容,通过使用枚举作为参数来弹出静态图层并推送动态图层,然后在其上绘制,从而执行相同的操作。最后在动态绘制方法的最后,我通过使用TargetLayer.None的enum参数来弹出所有图层,然后呈现框架。
我发现每次更改值时(在其图层上渲染动态内容,弹出图层然后显示)屏幕交替显示黑色背景上的动态图层内容,以及所有静态和动态内容,如果这 100% 工作,我希望看到它。
作为最低限度的工作示例,以下是包含仪表控件的表单的代码:
using System.Windows.Forms;
using System;
namespace SharpDXGauge
{
public partial class Form1 : Form
{
Gauge control;
public Form1()
{
InitializeComponent();
control = new Gauge(100,0);
control.Dock = DockStyle.Left;
this.Controls.Add(control);
}
private void numericupdown1_ValueChanged(object sender,EventArgs e)
{
control.IndicatorValue = (float)numericupdown1.Value;
}
}
}
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Generic;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.dxgi;
using SharpDX.DirectWrite;
using dxgi = SharpDX.dxgi; // Direct X Graphics Infrastructure
using D3D = SharpDX.Direct3D;
using D2D1 = SharpDX.Direct2D1;
using D3D11 = SharpDX.Direct3D11;
using DWrite = SharpDX.DirectWrite;
namespace SharpDXGauge
{
public partial class Gauge : UserControl
{
#region Members
private DirectX11Renderer renderer;
private float max;
private float min;
private float indicatorValue;
private Point topLeft;
private Point bottomright;
private float height;
private float width;
Point valueTextTopLeft;
Point valueLabelOutlinetopLeft;
Point valueLabelOutlineBottomright;
#endregion
public Gauge(float max,float min)
{
InitializeComponent();
renderer = new DirectX11Renderer(this);
this.max = max;
this.min = min;
this.indicatorValue = min;
renderer.SetBackgroundColor(renderer.SystemDrawingColorToSharpdxcolor(this.BackColor));
DrawStaticContent();
DrawDynamicContent();
}
#region Drawing
private void CalculateSizes()
{
// Static
topLeft = new Point() { x = 25,y = 10 };
bottomright = new Point() { x = topLeft.x + 20,y = this.Height - 50 };
height = bottomright.y - topLeft.y;
width = bottomright.x - topLeft.x;
// Dynamic
string valueText = indicatorValue.ToString();
Size2F valueTextSize = renderer.GetTextSize(valueText,9.75f);
valueTextTopLeft = new Point() { x = bottomright.x + 15,y = bottomright.y - height * indicatorValue / (max - min) - (valueTextSize.Height / 2) };
}
private void DrawStaticContent()
{
CalculateSizes();
renderer.ClearLayer(TargetLayer.Static,Color.Transparent);
renderer.DrawRectangle(TargetLayer.Static,topLeft,bottomright,Color.Black);
DrawDynamicContent();
renderer.PresentFrame();
}
private void DrawDynamicContent()
{
renderer.ClearLayer(TargetLayer.Dynamic,Color.Transparent);
CalculateSizes();
renderer.DrawText(TargetLayer.Dynamic,indicatorValue.ToString(),Color.White,valueTextTopLeft,9.75f);
renderer.DrawRoundedRectangle(TargetLayer.Dynamic,valueLabelOutlinetopLeft,valueLabelOutlineBottomright,20,Color.Black);
renderer.PresentFrame();
}
#endregion
#region Properties
public float IndicatorValue
{
get
{
return indicatorValue;
}
set
{
if (indicatorValue != value)
{
indicatorValue = value;
DrawDynamicContent();
}
}
}
#endregion
#region disposal
public new void dispose()
{
renderer.dispose();
}
#endregion
}
}
还有我的 DirectX11Renderer 类,我已经删除了所有不必要的绘图方法等:
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Generic;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.dxgi;
using SharpDX.DirectWrite;
using dxgi = SharpDX.dxgi; // Direct X Graphics Infrastructure
using D3D = SharpDX.Direct3D;
using D2D1 = SharpDX.Direct2D1;
using D3D11 = SharpDX.Direct3D11;
using DWrite = SharpDX.DirectWrite;
using DMaths = SharpDX.Mathematics.Interop;
namespace SharpDXGauge
{
public enum TargetLayer
{
Static,Dynamic,None
}
public struct Point
{
public float x;
public float y;
}
public partial class DirectX11Renderer : Idisposable
{
private Surface backBuffer;
private D3D11.Device d3dDevice;
private D3D11.Device1 d3dDevice1;
private dxgi.Device2 dxgiDevice2;
private D2D1.Device d2dDevice;
private SwapChain1 swapChain1;
private D2D1.Factory d2dFactory;
private dxgi.Factory2 dxgiFactory2;
private Adapter dxgiAdapter;
private rendertarget d2drendertarget;
private DWrite.Factory dWriteFactory;
private Layer staticLayer;
private Layer dynamicLayer;
SolidColorBrush solidColorBrush;
//RadialGradientBrush radialGradientBrush;
//LinearGradientBrush linearGradientBrush;
private Color lastBackColour;
private bool isDrawing;
private LayerParameters layerParams;
private bool isstaticLayerPushed;
private bool isDynamicLayerPushed;
List<double> renderTimesMsec = new List<double>();
public DirectX11Renderer(Control surfacetoDrawOn)
{
// There seems to be endless ways to set up the different objects required for rendering
// This is the most efficient I've found that get's everything you need for 2d rendering
SwapChainDescription1 description = new SwapChainDescription1()
{
Width = surfacetoDrawOn.Width,Height = surfacetoDrawOn.Height,Format = Format.R8G8B8A8_Unorm,Stereo = false,SampleDescription = new SampleDescription(1,0),Usage = Usage.BackBuffer | Usage.rendertargetOutput,BufferCount = 2,Scaling = Scaling.None,SwapEffect = SwapEffect.FlipSequential,};
d3dDevice = new D3D11.Device(DriverType.Hardware,DeviceCreationFlags.BgraSupport);
d3dDevice1 = d3dDevice.QueryInterface<D3D11.Device1>();
dxgiDevice2 = d3dDevice1.QueryInterface<dxgi.Device2>();
d2dDevice = new D2D1.Device(dxgiDevice2);
dxgiAdapter = dxgiDevice2.Adapter;
d2dFactory = new D2D1.Factory(D2D1.FactoryType.SingleThreaded);
dxgiFactory2 = dxgiAdapter.GetParent<dxgi.Factory2>();
swapChain1 = new SwapChain1(dxgiFactory2,d3dDevice1,surfacetoDrawOn.Handle,ref description);
backBuffer = swapChain1.GetBackBuffer<Surface>(0);
d2drendertarget = new rendertarget(d2dFactory,backBuffer,new rendertargetProperties(new PixelFormat(Format.R8G8B8A8_Unorm,D2D1.AlphaMode.Premultiplied)));
staticLayer = new Layer(d2drendertarget);
dynamicLayer = new Layer(d2drendertarget);
dWriteFactory = new DWrite.Factory(DWrite.FactoryType.Shared);
layerParams = new LayerParameters()
{
ContentBounds = RectangleF.Infinite,Opacity = 1
};
solidColorBrush = new SolidColorBrush(d2drendertarget,Color.White);
}
public void PresentFrame()
{
StartDrawingAndSwitchLayer(TargetLayer.None,false);
swapChain1.Present(0,PresentFlags.None);
}
public void SetBackgroundColor(Color colour)
{
StartDrawingAndSwitchLayer(TargetLayer.None);
lastBackColour = colour;
d2drendertarget.Clear(colour);
}
public void ClearLayer(TargetLayer layer,Color fillColorAfterClear)
{
StartDrawingAndSwitchLayer(layer);
d2drendertarget.Clear(fillColorAfterClear);
}
public void DrawRectangle(TargetLayer layer,Point topLeft,Point bottomright,Color colour,float strokeWidth = 1)
{
StartDrawingAndSwitchLayer(layer);
solidColorBrush.Color = colour;
d2drendertarget.DrawRectangle(new DMaths.RawRectangleF(topLeft.x,topLeft.y,bottomright.x,bottomright.y),solidColorBrush,strokeWidth);
}
public void DrawRoundedRectangle(TargetLayer layer,float roundingRadius,float strokeWidth = 1)
{
StartDrawingAndSwitchLayer(layer);
solidColorBrush.Color = colour;
RoundedRectangle roundedRect = new RoundedRectangle();
roundedRect.Rect = new DMaths.RawRectangleF(topLeft.x,bottomright.y);
roundedRect.RadiusX = roundingRadius;
roundedRect.RadiusY = roundingRadius;
d2drendertarget.DrawRoundedRectangle(roundedRect,strokeWidth);
}
public void DrawText(TargetLayer layer,string text,float fontSize,FontWeight weight = FontWeight.normal,FontStyle style = FontStyle.normal,string font = "Microsoft Sans Serif")
{
StartDrawingAndSwitchLayer(layer);
solidColorBrush.Color = colour;
textformat format = new textformat(dWriteFactory,font,weight,style,FontStretch.normal,fontSize);
Size2F textSize = GetTextSize(text,fontSize,100,100);
Point bottomright = new Point() { x = topLeft.x + (int)Math.Ceiling(textSize.Width),y = topLeft.y + (int)Math.Ceiling(textSize.Height) };
d2drendertarget.DrawText(text,format,new DMaths.RawRectangleF(topLeft.x,solidColorBrush);
}
public Size2F GetTextSize(string text,float maxWidth = 100000,float maxHeight = 100000,string font = "Microsoft Sans Serif")
{
textformat format = new textformat(dWriteFactory,fontSize);
TextLayout layout = new TextLayout(dWriteFactory,text,maxWidth,maxHeight);
return new Size2F(layout.Metrics.Width,layout.Metrics.Height);
}
public Color SystemDrawingColorToSharpdxcolor(System.Drawing.Color colour)
{
Color toRtn = new Color(new byte[4] { colour.R,colour.G,colour.B,colour.A,});
return toRtn;
}
private void StartDrawingAndSwitchLayer(TargetLayer layer,dynamicLayer);
isDynamicLayerPushed = true;
}
break;
case TargetLayer.None:
if (isstaticLayerPushed)
{
d2drendertarget.PopLayer();
isstaticLayerPushed = false;
}
if (isDynamicLayerPushed)
{
d2drendertarget.PopLayer();
isDynamicLayerPushed = false;
}
break;
}
if (!draw && isDrawing)
{
d2drendertarget.EndDraw();
isDrawing = false;
}
}
public void dispose()
{
// Release all resources
backBuffer.dispose();
d3dDevice.dispose();
d3dDevice1.dispose();
dxgiDevice2.dispose();
d2dDevice.dispose();
swapChain1.dispose();
d2dFactory.dispose();
dxgiFactory2.dispose();
dxgiAdapter.dispose();
d2drendertarget.dispose();
staticLayer.dispose();
dynamicLayer.dispose();
}
}
}
将这些放在一起给出了我所看到的最小示例,我已经删除了代码处理表单调整大小,因此,下半部分开始时显示为黑色,但使用表单上的数字向上更新来更新 IndicatorValue属性创建交替的全黑/我想看到的帧。
我已经尝试调试了一段时间,我开始怀疑这是否与我如何设置交换链有关?起初我认为这一定是我处理图层的方式,也许其他所有更改和动态内容都以某种方式呈现它不会弹出图层而只显示动态图层的内容?但是,就我所见,逐步执行每个更新都会正确地推送和弹出图层,并且通常不正确会引发异常。
对不起,太长了,
乔。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)