Using WPF and SlimDx (DirectX 10/11) - c#

I am using SlimDX with WinForms for a while now, but want to make the switch to WPF now. However, I can't figure out how to get DX10/11 working with WPF. The February release of SlimDX provides a WPF example, which only works with DX 9 though.
I found the following solution: http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/437/Direct3D-10-11-Direct2D-in-WPF.aspx
but can't get it to work with SlimDX. My main problem is the shared resource handle as I don't know how to retrieve the shared handle from a SlimDX texture. I can't find any information to this topic.
In C++ the code looks like this:
HRESULT D3DImageEx::GetSharedHandle(IUnknown *pUnknown, HANDLE * pHandle)
{
HRESULT hr = S_OK;
*pHandle = NULL;
IDXGIResource* pSurface;
if (FAILED(hr = pUnknown->QueryInterface(__uuidof(IDXGIResource), (void**)&pSurface)))
return hr;
hr = pSurface->GetSharedHandle(pHandle);
pSurface->Release();
return hr;
}
Basically, what I want to do (because I think that this is the solution), is to share a texture between a Direct3d9DeviceEx (for rendering the WPF D3DImage) and a Direct3d10Device (a texture render target for my scene).
Any pointers in the right direction are greatly appreciated.

They posted some sample code on how to use slimdx/directx10 with WPF. Here's the link

There is a control called WindowsFormsHost, maybe you could integrate your current WinForm control that way?

Have a look at D3DImageEx. http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/437/Direct3D-10-11-Direct2D-in-WPF.aspx
You provide a reference to your rendertarget, but it has to be created with the Shared flag. I was not able to use a swapchain in this way though.
let renderTargetDescription = Texture2DDescription( Width=width,
Height=height,
MipLevels=1,
ArraySize=1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = SampleDescription(Count = 1),
BindFlags = (BindFlags.RenderTarget ||| BindFlags.ShaderResource),
OptionFlags = ResourceOptionFlags.Shared)

Related

c# SharpDX ScaleEffect Interpolation question

i've been using this wonderful library for low impact screen recording software however im at a point where i need to use a DirectX Scale Effect to scale the image down with anisotropic filtering.
I can create the effect just fine and set up most of its parameters, however im not able to set the most important one for me scaleEffect.SetValue((int)ScaleProperties.InterpolationMode, (int)SharpDX.Direct2D1.ScaleInterpolationMode.Anisotropic);
As soon as the program runs it crashes at that line with an invalid parameter exception.
I've searched and couldnt find anything wrong with the code, but then again i have almost 0 experience with anything Direct2D.
Here is the full code for that specific effect for reference:
SharpDX.Direct2D1.Effect scaleEffect = new D2D.Effect(textureDc, D2D.Effect.Scale);
scaleEffect.Cached = true;
scaleEffect.SetInput(0, frameBitmap, false);
var centerPoint = new SharpDX.Vector2(0, 0);
var newSize = new SharpDX.Vector2(0.2f, 0.2f);
scaleEffect.SetValue((int)ScaleProperties.CenterPoint, centerPoint);
scaleEffect.SetValue((int)ScaleProperties.Scale, newSize);
//Crashes Here: scaleEffect.SetValue((int)ScaleProperties.InterpolationMode, (int)SharpDX.Direct2D1.ScaleInterpolationMode.Anisotropic);
Error Message: SharpDX.SharpDXException: 'HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.'
textureDc.BeginDraw();
textureDc.DrawImage(scaleEffect, InterpolationMode.Anisotropic);
textureDc.EndDraw();
Thank you very much in advance for any help!
UPDATE:
As per #Simon Mourier comment, the solution to avoid this bug somewhere in the SharpDX API, is to use the SharpDX.Direct2D1.Effects.Scale instead.
This way, i can confirm the InterpolationMode does no longer crash and works as intended!
Here is the new, working code for anyone running into the same issue.
SharpDX.Direct2D1.Effects.Scale scaleClass = new D2D.Effects.Scale(textureDc);
scaleClass.SetInput(0, frameBitmap,false);
scaleClass.Cached = true;
var centerPoint = new SharpDX.Vector2(0, 0);
var newSize = new SharpDX.Vector2(0.2f, 0.2f);
scaleClass.CenterPoint = centerPoint;
scaleClass.ScaleAmount = newSize;
scaleClass.InterpolationMode = InterpolationMode.Anisotropic;
textureDc.BeginDraw();
textureDc.DrawImage(scaleClass);
textureDc.EndDraw();
PS: For anyone wondering about casting the value to uint instead using the first method, it returns the following error:
(Argument1 cannot convert from uint to int)
So it semms that there might be some underlying bug in this specific scenario.
One solution is to use the SharpDX.Direct2D1.Effects.Scale directly which is a wrapper over the Effect class and comes with an InterpolationMode property.

Aspect ratio of video is maintained on one computer but not the other with DirectShow

I have a C# application which plays videos using the DirectShowNet library. When I debug my application using Visual C# on my laptop, the video is stretched to fit the container's dimensions i.e. the aspect ratio of the video is not maintained. When I load and run my application on a different computer (same operating system), the aspect ratio is maintained and black bars are created on the screen.
I do not want the aspect ratio to be maintained. I want the other computer to display the video the same way my computer is displaying it.
Why do you think the two computer's act differently and/or how do I fix this?
When I first saw this behaviour on the other computer, I updated that computer's DirectX to no avail. The exact same videos are being run on both systems.
EDIT #1: Could it possibly be some missing filter on the other computer? I assumed the default behaviour of DirectShow was not to maintain the Aspect Ratio.
EDIT #2: When I attempted to use IVMRWindowlessControl (VMR-7 & VMR-9), the cast from the VMR to the IVMRWindowlessControl kept on resulting in a NULL variable. As a result I tried IVMRAspectRatioControl with VMR-7 and it worked on one of the computers. The other computer stayed in Letterbox mode despite the call to remove the Aspect Ratio preservation.
EDIT #3: Here is the code using IVMRAspectRatioControl with VMR-7:
int hr = 0;
this.graphBuilder = (IGraphBuilder)new FilterGraph();
this.vmr = new VideoMixingRenderer();
this.graphBuilder.AddFilter((IBaseFilter)vmr, "VMR");
this.aspectRatioControl = (IVMRAspectRatioControl)this.vmr;
hr = this.aspectRatioControl.SetAspectRatioMode(VMRAspectRatioMode.None);
DsError.ThrowExceptionForHR(hr);
hr = this.graphBuilder.RenderFile(filename, null);
DsError.ThrowExceptionForHR(hr);
I am then using IVideoWindow to display the video.
When attempting to use the IVMRWindowlessControl9, the this.windowlessControl evaluated to NULL after the cast on the 4th line. I get the same NULL error when I tried it with VMR-7. The following uses VMR-9:
this.graphBuilder = (IGraphBuilder)new FilterGraph();
this.vmr = new VideoMixingRenderer9();
this.graphBuilder.AddFilter((IBaseFilter)vmr, "VMR");
this.filterConfig = (IVMRFilterConfig9)vmr;
hr = this.filterConfig.SetNumberOfStreams(1);
DsError.ThrowExceptionForHR(hr);
hr = this.filterConfig.SetRenderingMode(VMR9Mode.Windowless);
DsError.ThrowExceptionForHR(hr);
this.windowlessControl = (IVMRWindowlessControl9)this.vmr;
hr = this.windowlessControl.SetAspectRatioMode(VMR9AspectRatioMode.None);
DsError.ThrowExceptionForHR(hr);
hr = this.graphBuilder.RenderFile(filename, null);
DsError.ThrowExceptionForHR(hr);
I'm not entirely sure how it works, but could it be possible that the second computer does not support VMR-7 for the IVMRAspectRatioControl? The operating systems on both computers are the same, however the first computer (which works) is where I'm writing the software (it has the IDE). The second computer had a fresh install of Windows. On the second computer, I also updated DirectX as mentioned earlier.
Video renderers can be configured to preserve or not preserve aspect ratio. Configuration method (and, perhaps, default setting, which can also depend on internal mode of the renderer such as overlay/offscreen surface) is dependent on video renderer version you are using, e.g. for VMR-7 you will use IVMRWindowlessControl::SetAspectRatioMode's (or, IVMRAspectRatioControl::SetAspectRatioMode if your VMR is in windowed mode) DirectShow.NET equivalent/wrapper. VMR-9, EVR has similar methods.
With VMR-9 you will use IVMRAspectRatioControl9::SetAspectRatioMode. With EVR it is IMFVideoDisplayControl::SetAspectRatioMode.
If you don't want any letterboxing and aspect ration preservation, you just disable it explicitly when you set the video renderer up.

XNA 3.1 DrawUserPrimitives with Anti Aliasing - MultiSampling doesn't work?

So this is a continuation of a question I asked earlier today. I've built myself some nice looking ribbon trails using XNA 3.1's DrawUserPrimitives method, essentially by expanding a polygon as motion occurs. It all looks super sleek and nice, except for one thing - anti-aliasing. I cannot for the life of me work out how to apply it.
I've set this in the game constructor:
graphics.PreferMultiSampling = true;
And I've also added this to test for the hardware:
graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>((sender, e) =>
{
PresentationParameters parameters = e.GraphicsDeviceInformation.PresentationParameters;
parameters.MultiSampleQuality = 0;
#if XBOX
pp.MultiSampleType = MultiSampleType.FourSamples;
return;
#else
int quality;
GraphicsAdapter adapter = e.GraphicsDeviceInformation.Adapter;
SurfaceFormat format = adapter.CurrentDisplayMode.Format;
if (adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, format, false, MultiSampleType.FourSamples, out quality))
{
parameters.MultiSampleType = MultiSampleType.FourSamples;
}
else if (adapter.CheckDeviceMultiSampleType(DeviceType.Hardware, format, false, MultiSampleType.TwoSamples, out quality))
{
parameters.MultiSampleType = MultiSampleType.TwoSamples;
}
#endif
});
By adding some print lines, I know my hardware can support 4 sample AA, but this all seems to make no difference. I just can't seem to get this to work.
Here's a screenshot of one of my trails with all of that code applied:
I'd really appreciate some help. I looked at this a while ago for a solution to a different problem, and couldn't get it to work then, either.
Well, cheers.
Fixed this one, too!
The issue was that, while the back buffer was getting the right anti-alias settings, the render target wasn't. This meant that drawing to the render target was done without AA, but the texture that was then drawn to the back buffer was done with it. I've fixed it now.

Managed DirectX9 ColorKey

I've managed to load a texture with TextureLoader.LoadFromFile(), and provided it with Color.Black.ToArgb() for it's colorkey.
Unfortunately, when I render it, using Device.DrawUserPrimitives, I'm still seeing black.
Am I missing some code to enable the use of the ColorKey?
Needed to set some renderstate on the Device:
Device.RenderState.AlphaBlendEnable = true;
Device.RenderState.SourceBlend = Blend.SourceAlpha;
Device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
I'm not certain which but I think you need to enable the render state(s) AlphaBlendEnable and/or AlphaTestEnable. You might also have to set the blend modes.
By the way, you're using Managed DirectX, which has long been discontinued. You should consider switching to XNA or SlimDX.

How do I enable a second monitor in C#?

Is it possible to enable a second monitor programatically and extend the Windows Desktop onto it in C#? It needs to do the equivalent of turning on the checkbox in the image below.
MSDN Device Context Functions
What you basically need to do:
Use the EnumDisplayDevices() API call
to enumerate the display devices on
the system and look for those that
don't have the
DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
flag set (this will include any
mirroring devices so not all will be
physical displays.) Once you've found
the display device you'll need to get
a valid display mode to change it to,
you can find this by calling the
EnumDisplaySettingsEx() API call -
Generally you'd display all the
available modes and allow the user to
choose however in your case it sounds
like this may be possible to hard-code
and save you an additional step. For
the sake of future-proofing your
application though I'd suggest having
this easily changeable without having
to dig through the source every time,
a registry key would be the obvious
choice. Once you've got that sorted
out populate a DevMode display
structure with the information about
the display positioning (set the
PelsWidth/Height, Position,
DisplayFrequency and BitsPerPel
properties) then set these flags in
the fields member. Finally call
ChangeDisplaySettingsEx() with this
settings structure and be sure to send
the reset and update registry flags.
That should be all you need, hope this
helps,
DISPLAY_DEVICE structure import using PInvoke
EnumDisplayDevices function import
EnumDisplaySettingsEx function import
etc. the rest of them functions can be found with a simple search by name.
If you have windows 7, then just start a process:
private static Process DisplayChanger = new Process
{
StartInfo =
{
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "DisplaySwitch.exe",
Arguments = "/extend"
}
};
then DisplayChanger.Start();
I don't have the full answer here but I am almost sure that you will have to call out of .Net to do this. You will have to use Pinvoke to call an unmanaged dll. A great resource for this is pinvoke.net.
I did a quick search and found http://www.pinvoke.net/default.aspx/user32/ChangeDisplaySettings.html which probably isn't exactly what you want but you will probably find it somewhere on pinvoke.net
I am looking for the same solution. I have written the following code to call ChangeDisplaySettingsEx with PInvoke:
DEVMODE dm = new DEVMODE();
dm.dmSize = (short)Marshal.SizeOf(dm);
dm.dmPelsWidth = 1680;
dm.dmPelsHeight = 1050;
dm.dmBitsPerPel = 32;
dm.dmDisplayFrequency = 60;
dm.dmFields = DevModeFields.DM_BITSPERPEL | DevModeFields.DM_PELSWIDTH |
DevModeFields.DM_PELSHEIGHT | DevModeFields.DM_DISPLAYFREQUENCY;
int res = ChangeDisplaySettingsEx(#"\\.\DISPLAY2", ref dm, IntPtr.Zero, CDS_RESET | CDS_UPDATEREGISTRY, IntPtr.Zero);
Console.WriteLine("result = " + res.ToString());
If the monitor is already enabled, this changes the resolution successfully. But if the monitor isn't attached to the desktop already, this won't activate it. So does anyone have a code example that works?
To enable a monitor, set its position to something other than 0,0, like as shown:
POINTL enabledPosition = new POINTL();
enabledPosition.x = -1280;
enabledPosition.y = 0;
dm.dmPosition = enabledPosition;
dm.dmFields = DM.Position;
res = ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, (uint) DeviceFlags.CDS_UPDATEREGISTRY, IntPtr.Zero);

Categories

Resources