[WIP] Direct3D with Silk.NET#1123
Conversation
|
Just to give a bit more explanation on what's going on in this PR : SharpDX went to great length abstracting Direct3D with C# OOP. Since Silk.NET uses raw native bindings all of the sweet OOP is gone and we are instead using native structures and interfaces, which will result in more mostly unsafe LOCs. The pain point of this PR is my limited experience with manipulating references in general and my limited knowledge of DirectX. Since i can't build until i finished porting everything, most of the implementation will be broken so if anything, most of the help needed will be in correcting my wrong uses of functions and values/parameters. Opinion on using Silk.NET : |
|
So i've got a good news and a bad news :
I removed the DXVA implementation in Stride.Video since it's old (it's from DX9 era and isn't used much anymore) in favor of FFMPEG which should be fine. |
| public enum DXGIMwaFlags : uint | ||
| { | ||
| NO_WINDOW_CHANGES = 0x1, | ||
| NO_ALT_ENTER = 0x2, | ||
| NO_PRINT_SCREEN = 0x4, | ||
| VALID = 0x7 | ||
| } |
There was a problem hiding this comment.
We'd welcome these contributions upstream in the Silk.NET library itself, our generator is still early days and doesn't necessarily generate everything today. In 3.0 we're rewriting our generator to be more stable, but that version is still in the planning stage at the moment.
There was a problem hiding this comment.
Sure! I got myself a bit more familiar with generators this week (I knew quasi nothing about it before that). I'll do my best but it might take some time!
There was a problem hiding this comment.
You can also just add these as manual files for now, which should be just a simple copy-and-paste job :)
(and maybe changing the names a bit to fit in!)
The generators are absolutely horrible to work with, so I wouldn't wish that upon a community contributor.
| private static IEnumerable<Guid> FindVideoFormatCompatibleProfiles(Silk.NET.Direct3D11.ID3D11VideoDevice1 videoDevice, AVCodec codec) | ||
| { | ||
| for (var i = 0; i < videoDevice.VideoDecoderProfileCount; ++i) | ||
| for (var i = 0; i < videoDevice.GetVideoDecoderProfileCount(); ++i) |
There was a problem hiding this comment.
This won't work as intended, and will likely crash.
In general, you should never have a struct representing an interface ever used by-value.
i.e. videoDevice needs to be ID3D11VideoDevice1* (note the pointer) or ComPtr<ID3D11VideoDevice1>, not ID3D11VideoDevice1
| var tex = new ID3D11Texture2D((void**)ptr); | ||
| textures[i].InitializeFromImpl(new ComPtr<ID3D11Texture2D>(&tex), false); |
There was a problem hiding this comment.
This also won't work as intended, for almost the same reason.
For context, how our struct wrappers work is they take a pointer to &this, which when used as a pointer maps to what DirectX has given us. I explained it to you in our Discord server before, but paraphrasing it here for others' reference:
let's say the variable [tex] is at address
0x1and [D3D11] returns address0x2as the [texture]'s address, with some internal state holding the [texture] info at0x3(i.e.0x2+1). when you dereference0x2into0x1, when [InitializeFromImpl] tries to get0x1+1you get a segfault because that state doesn't exist -&thisis now0x1instead of0x2.
You're probably looking for:
| var tex = new ID3D11Texture2D((void**)ptr); | |
| textures[i].InitializeFromImpl(new ComPtr<ID3D11Texture2D>(&tex), false); | |
| var tex = new ComPtr<ID3D11Texture2D>((ID3D11Texture2D*)ptr); | |
| textures[i].InitializeFromImpl(tex, false); |
| unsafe | ||
| { | ||
| var tex = new ID3D11Texture2D((void**)ptr); | ||
| textures[i].InitializeFromImpl(new ComPtr<ID3D11Texture2D>(&tex), false); |
There was a problem hiding this comment.
A general note about ComPtrs (not a problem here, but wanted to ensure I put this somewhere): the idea of ComPtr is that it does some of the management of the underlying pointer's lifetime for you.
So:
ID3D11Texture2D* nativePtr = /* some code to get a pointer from native */;
// let's call the refcount of nativePtr here "n"
var ptr1 = new ComPtr<ID3D11Texture2D>(nativePtr); // calls AddRef, meaning the refcount is now n + 1
var ptr2 = new ComPtr<ID3D11Texture2D>(ptr1); // copies ptr1 and calls AddRef again, meaning the refcount is now n + 2
ptr1.Dispose(); // Release is called, decrementing the refcount to n + 1
ptr2.Dispose(); // Release is called, decrementing the refcount back to n
// if n is zero, the native pointer is freed here.It's best to model this in your code as closely as possible. C# unfortunately does not have copy constructors like C++ does, otherwise this would be a lot easier.
As such, whenever you're passing a ComPtr to a method or something, it's best to clone that ComPtr as illustrated above (ptr2 being created from ptr1). Likewise, to avoid memory leaks always ensure you dispose your ComPtrs.
There was a problem hiding this comment.
I understand a bit better, i think i did some mistakes in other parts i will recheck everything to be sure.
If i understood well, everytime i need to "borrow" a ComPtr i should make sure to use it and dispose it after ward ?
There was a problem hiding this comment.
Yeah. How the C++ implementation does it is every time the struct is copied, the ref counter goes up and every time the struct goes out of scope, the ref counter goes down.
ComPtr<ID3D11Texture2D> thing_one { native_ptr };
{
ComPtr<ID3D11Texture2D> thing_two { thing_one }; // C++ magic increments the ref counter here because it's a copy
} // thing_two is out of scope now, so ref counter decrementsObviously it's not as easy to do that in C# so the closest you can get is:
- where you would otherwise copy:
new(ptr)to create a copy of the ptr. - at the end of methods which take a
ComPtr:ptr.Dispose()
Perhaps that's not the cleanest way, and feel free to do what fits best; but hopefully my explanation on how the C++ original works helps :)
|
#1715 is much better |
PR Details
This PR intends to switch from SharpDX to Silk.NET for Direct3D
Related Issue
#1176
Motivation and Context
SharpDX lacks support and development. As good as this library is, it's great to be able to use ones that are still updated to get access to newer technologies such as Mesh Shaders and other apis.
Types of changes
Related issues
#432
Checklist