尝试在direct2d中使用ID2D1SpriteBatch来提高常规DrawBitmap()的性能。
管理设置它,但当我调用DeviceContext.EndDraw()时,我得到“对象处理方法的状态不正确”。
我可以让DeviceContext.DrawBitmap()工作(参见注释掉的部分)。尝试了我能想到的所有东西,以使设备上下文处于正确的状态来处理spritebatch但没有运气。
试图尽可能地将这个样本煮沸,但也不想遗漏任何步骤,以防万一是罪魁祸首。
任何想法如何让它工作?
using SharpDX;
using _d2d = SharpDX.Direct2D1;
using _d3d = SharpDX.Direct3D;
using _d3d11 = SharpDX.Direct3D11;
using _dxgi = SharpDX.DXGI;
using _directWrite = SharpDX.DirectWrite;
using _wic = SharpDX.WIC;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpDX.IO;
using SharpDX.Mathematics.Interop;
namespace TestApp
{
public class SpriteBatchIssue
{
[STAThread]
static void Main(string[] args)
{
var app = new SpriteBatchIssue();
app.Run();
}
bool isClosed = false;
public void Run()
{
#region setup resources
var clientSize = new Size2(1000, 500);
var mainForm = new RenderForm();
mainForm.ClientSize = new System.Drawing.Size(
clientSize.Width,
clientSize.Height);
mainForm.FormClosed += mainForm_FormClosed;
var scDescription = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription =
new ModeDescription(
clientSize.Width,
clientSize.Height,
new Rational(60, 1),
Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = mainForm.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
// Create Device and SwapChain
_d3d11.Device d3d11Device;
SwapChain swapChain;
_d3d11.Device.CreateWithSwapChain(
DriverType.Hardware,
DeviceCreationFlags.BgraSupport,
new[] { _d3d.FeatureLevel.Level_12_1 },
scDescription,
out d3d11Device,
out swapChain);
// Ignore all windows events
var dxgiFactory = swapChain.GetParent<_dxgi.Factory1>();
dxgiFactory.MakeWindowAssociation(mainForm.Handle, WindowAssociationFlags.IgnoreAll);
// New RenderTargetView from the backbuffer
var backBuffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
var backBufferView = new RenderTargetView(d3d11Device, backBuffer);
var d2dFactory = new _d2d.Factory();
var d2dFactory4 = d2dFactory.QueryInterface<_d2d.Factory4>();
var dxgiDevice = d3d11Device.QueryInterface<_dxgi.Device>();
var d2dDevice3 = new _d2d.Device3(d2dFactory4, dxgiDevice);
var d2dDeviceContext3 = new _d2d.DeviceContext3(d2dDevice3, DeviceContextOptions.None);
using (var surface = backBuffer.QueryInterface<Surface>())
{
var bmpProperties = new BitmapProperties1(
new PixelFormat(Format.R8G8B8A8_UNorm, _d2d.AlphaMode.Premultiplied),
dpiX: 96,
dpiY: 96,
bitmapOptions: BitmapOptions.Target | BitmapOptions.CannotDraw);
var d2dTarget = new Bitmap1(
d2dDeviceContext3,
surface,
bmpProperties);
d2dDeviceContext3.Target = d2dTarget;
}
#endregion
#region setup drawing parameters
var bmp = createD2DBitmap(@"C:\yourPath\yourImage.png", d2dDeviceContext3);
var spriteBatch = new SpriteBatch(d2dDeviceContext3);
var destinationRects = new RawRectangleF[1];
destinationRects[0] = new RectangleF(100, 50, bmp.Size.Width, bmp.Size.Height);
var sourceRects = new RawRectangle[1];
sourceRects[0] = new RectangleF(0, 0, bmp.Size.Width, bmp.Size.Height);
var colors = new RawColor4[1];
colors[0] = Color.White;
var transforms = new RawMatrix3x2[1];
transforms[0] = Matrix3x2.Identity;
#endregion
#region mainLoop
RenderLoop.Run(mainForm, () =>
{
if (isClosed)
{
return;
}
d3d11Device.ImmediateContext.Rasterizer.SetViewport(new Viewport(0, 0, clientSize.Width, clientSize.Height));
d3d11Device.ImmediateContext.OutputMerger.SetTargets(backBufferView);
d2dDeviceContext3.BeginDraw();
//this technique works
//d2dDeviceContext3.DrawBitmap(
// bitmap: bmp,
// destinationRectangle: destinationRects[0],
// opacity: 1,
// interpolationMode: BitmapInterpolationMode.Linear,
// sourceRectangle: new RectangleF(0, 0, bmp.Size.Width, bmp.Size.Height));
//this technique does not work
spriteBatch.Clear();
spriteBatch.AddSprites(
1,
destinationRects,
sourceRects,
colors,
transforms,
destinationRectanglesStride: 0, //0 stride because there is only 1 element
sourceRectanglesStride: 0, //i've also tried using Marshal.SizeOf() to get the stride, but i get the same error
colorsStride: 0,
transformsStride: 0);
d2dDeviceContext3.DrawSpriteBatch(
spriteBatch: spriteBatch,
startIndex: 0,
spriteCount: 1,
bitmap: bmp,
interpolationMode: BitmapInterpolationMode.Linear,
spriteOptions: SpriteOptions.ClampToSourceRectangle);
//when using the spritebatch technique, this throws exception:
// "The object was not in the correct state to process the method"
d2dDeviceContext3.EndDraw();
//first param set to 1 would indicate waitVerticalBlanking
swapChain.Present(0, PresentFlags.None);
});
#endregion
}
Bitmap createD2DBitmap(string filePath, _d2d.DeviceContext deviceContext)
{
var imagingFactory = new _wic.ImagingFactory();
var fileStream = new NativeFileStream(
filePath,
NativeFileMode.Open,
NativeFileAccess.Read);
var bitmapDecoder = new _wic.BitmapDecoder(imagingFactory, fileStream, _wic.DecodeOptions.CacheOnDemand);
var frame = bitmapDecoder.GetFrame(0);
var converter = new _wic.FormatConverter(imagingFactory);
converter.Initialize(frame, SharpDX.WIC.PixelFormat.Format32bppPRGBA);
var newBitmap = SharpDX.Direct2D1.Bitmap1.FromWicBitmap(deviceContext, converter);
return newBitmap;
}
void mainForm_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
{
isClosed = true;
}
}
}
问题是你不能使用spritebatch进行每个原始抗锯齿。在BeginDraw()修复它之前的这一行:d2dDeviceContext3.AntialiasMode = AntialiasMode.Aliased;
最后还了解了如何使调试层工作。创建设备时包含调试标志(请参阅下面的注释)。如果它抛出一个异常,那可能是因为你没有正确版本的windows sdk。如果您正在使用visual studio,请转到visual studio安装程序并修改您的安装以包含Windows sdk。
接下来,您需要右键单击您的项目 - > properties-> debug(在左侧面板上) - >选中“启用本机代码调试”。在我这样做之后,有一行写入输出窗口,说明:“D2D DEBUG ERROR - DrawSpriteBatch要求将抗锯齿模式设置为D2D1_ANTIALIAS_MODE_ALIASED。”
我学到的其他东西与答案没有直接关系,但值得注意:“请注意,SharpDX中的ComObject不是由.NET终结器处理的。如果没有通过调用Dispose()或ReleaseReference()释放COM对象,它不会释放附加到它的本机对象和内存。“从这里:http://sharpdx.org/wiki/usage/
这是一个完整的工作示例:
using SharpDX;
using _d2d = SharpDX.Direct2D1;
using _d3d = SharpDX.Direct3D;
using _d3d11 = SharpDX.Direct3D11;
using _dxgi = SharpDX.DXGI;
using _directWrite = SharpDX.DirectWrite;
using _wic = SharpDX.WIC;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpDX.IO;
using SharpDX.Mathematics.Interop;
namespace TestApp
{
public class SpriteBatchIssue
{
[STAThread]
static void Main(string[] args)
{
var app = new SpriteBatchIssue();
app.Run();
}
#region Variables
_d3d11.Device d3d11Device;
SwapChain swapChain;
_dxgi.Factory1 dxgiFactory;
_d2d.Factory d2dFactory;
_d2d.Factory4 d2dFactory4;
_dxgi.Device dxgiDevice;
_d2d.Device3 d2dDevice3;
_d2d.DeviceContext3 d2dDeviceContext3;
Bitmap1 sourceImage;
SpriteBatch spriteBatch;
Bitmap1 d2dTarget;
#endregion
~SpriteBatchIssue()
{
safeDispose(ref d3d11Device);
safeDispose(ref swapChain);
safeDispose(ref dxgiFactory);
safeDispose(ref d2dFactory);
safeDispose(ref d2dFactory4);
safeDispose(ref dxgiDevice);
safeDispose(ref d2dDevice3);
safeDispose(ref d2dDeviceContext3);
safeDispose(ref sourceImage);
safeDispose(ref spriteBatch);
safeDispose(ref d2dTarget);
}
public void Run()
{
#region setup resources
var mainForm = new RenderForm();
var scDescription = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription =
new ModeDescription(
0,
0,
new Rational(60, 1),
Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = mainForm.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
//DeviceCreationFlags.Debug flag below will show debug layer messages in your output window.
//Need proper version of windows sdk for it to work, otherwise it will throw an exception.
//You also need to right click your project->properties->debug (on the left panel)-> check "enable native code debugging"
// Create Device and SwapChain
_d3d11.Device.CreateWithSwapChain(
DriverType.Hardware,
DeviceCreationFlags.BgraSupport | DeviceCreationFlags.Debug,
new[] { _d3d.FeatureLevel.Level_12_1 },
scDescription,
out d3d11Device,
out swapChain);
// Ignore all windows events
dxgiFactory = swapChain.GetParent<_dxgi.Factory1>();
dxgiFactory.MakeWindowAssociation(mainForm.Handle, WindowAssociationFlags.IgnoreAll);
d2dFactory = new _d2d.Factory();
d2dFactory4 = d2dFactory.QueryInterface<_d2d.Factory4>();
dxgiDevice = d3d11Device.QueryInterface<_dxgi.Device>();
d2dDevice3 = new _d2d.Device3(d2dFactory4, dxgiDevice);
d2dDeviceContext3 = new _d2d.DeviceContext3(d2dDevice3, DeviceContextOptions.None);
#endregion
#region create drawing input
sourceImage = createD2DBitmap(@"yourFile.png", d2dDeviceContext3);
spriteBatch = new SpriteBatch(d2dDeviceContext3);
var destinationRects = new RawRectangleF[1];
destinationRects[0] = new RectangleF(100, 50, sourceImage.Size.Width, sourceImage.Size.Height);
var sourceRects = new RawRectangle[1];
sourceRects[0] = new RectangleF(0, 0, sourceImage.Size.Width, sourceImage.Size.Height);
#endregion
#region mainLoop
RenderLoop.Run(mainForm, () =>
{
if (d2dTarget != null)
{
d2dTarget.Dispose();
d2dTarget = null;
}
using (var backBuffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0))
{
using (var surface = backBuffer.QueryInterface<Surface>())
{
var bmpProperties = new BitmapProperties1(
new PixelFormat(Format.R8G8B8A8_UNorm, _d2d.AlphaMode.Premultiplied),
dpiX: 96,
dpiY: 96,
bitmapOptions: BitmapOptions.Target | BitmapOptions.CannotDraw);
d2dTarget = new Bitmap1(
d2dDeviceContext3,
surface,
bmpProperties);
d2dDeviceContext3.Target = d2dTarget;
}
}
//the key missing piece: cannot use per primitive antialiasing with spritebatch
d2dDeviceContext3.AntialiasMode = AntialiasMode.Aliased;
d2dDeviceContext3.BeginDraw();
spriteBatch.Clear();
spriteBatch.AddSprites(
1,
destinationRects,
sourceRects,
null,
null,
destinationRectanglesStride: 0, //0 stride because there is only 1 element
sourceRectanglesStride: 0,
colorsStride: 0,
transformsStride: 0);
d2dDeviceContext3.DrawSpriteBatch(
spriteBatch: spriteBatch,
startIndex: 0,
spriteCount: 1,
bitmap: sourceImage,
interpolationMode: BitmapInterpolationMode.Linear,
spriteOptions: SpriteOptions.ClampToSourceRectangle);
d2dDeviceContext3.EndDraw();
//first param set to 1 would indicate waitVerticalBlanking
swapChain.Present(0, PresentFlags.None);
});
#endregion
}
void safeDispose<T>(ref T disposable) where T : class, IDisposable
{
if (disposable != null)
{
disposable.Dispose();
disposable = null;
}
}
Bitmap1 createD2DBitmap(string filePath, _d2d.DeviceContext deviceContext)
{
var imagingFactory = new _wic.ImagingFactory();
var fileStream = new NativeFileStream(
filePath,
NativeFileMode.Open,
NativeFileAccess.Read);
var bitmapDecoder = new _wic.BitmapDecoder(imagingFactory, fileStream, _wic.DecodeOptions.CacheOnDemand);
var frame = bitmapDecoder.GetFrame(0);
var converter = new _wic.FormatConverter(imagingFactory);
converter.Initialize(frame, SharpDX.WIC.PixelFormat.Format32bppPRGBA);
var newBitmap = SharpDX.Direct2D1.Bitmap1.FromWicBitmap(deviceContext, converter);
return newBitmap;
}
}
}