Closed vmx17 closed 1 year ago
Hi,
Buffer.BlockCopy
only supports .NET arrays, while we're mostly dealing with IntPtr
-type variables here , so you can do it like this:
var gc = GCHandle.Alloc(Data.VertexData, GCHandleType.Pinned);
var vertexData = new D3D11_SUBRESOURCE_DATA();
vertexData.pSysMem = gc.AddrOfPinnedObject();
gc.Free();
var map = _deviceContext.Map(_vertexBuffer, 0, D3D11_MAP.D3D11_MAP_WRITE_DISCARD);
CopyMemory(map.pData, vertexData.pSysMem, (IntPtr)Data.VertexData.SizeOf());
_deviceContext.Unmap(_vertexBuffer, 0);
And you need an IntPtr
to IntPtr
copy method wich doesn't exist by default in .NET, so:
[DllImport("kernel32", ExactSpelling = true, EntryPoint = "RtlMoveMemory")]
private static extern void CopyMemory(IntPtr destination, IntPtr source, IntPtr length);
PS: I've added CopyMemory support since it's useful: https://github.com/smourier/DirectN/commit/cace81ff0dd9c0c627acd6749088f975bdd34c1b
I'm really appreciated. It made reduce error rate but now it changed to System.AccessViolationException
at CopyMemory()
. The error occurs randomly, after adding several, or some ten's of vertex value. I'm re-checking the vertex data (now it can be accessed as ((App)Application.Current)).DrawManager.VertexData
) is correctly sent to this method. The other issue, even after the mapping is done successfully, the screen does not change. I'll cut out the part to show the way to modify the data.
Hi,
DirectN consist merely of .NET bindings over the underlying technology (here Direct3D). It means it does almost nothing by itself but pass things back and forth.
So, AccesViolationException is a memory access error: pointer that points to invalid memory, memory copy of invalid size, writing read-only memory, etc. like we're used to do using C/C++, etc.
Make sure you've defined your _vertexBuffer properly if you want to write to it (D3D11_CPU_ACCESS_WRITE, etc.), make sure about the buffer size, etc. If you post a reproducible code, I can try to have a look at it.
As for the screen that doesn't change this is purely a DirectX issue.
Now I put my code here Though it still has some degraded, but the error can be reproduced at the same point. By the way, are there possibility to use C++ renderer and SwapChainPanel with C#? By making NuGet package, it seems work. Am I dreaming? Good night, anyway.
I don't reproduce but your _vertexBuffer is allocated with 576 bytes (vertexBufferDesc.ByteWidth = (uint)((App)Application.Current).DrawManager.VertexData.SizeOf()), and then you map it and copy 672 bytes to it with CopyMemory. That's called a buffer overflow and a good recipe for crashes
Hmm... I see. But before using "Map", I tried to remake _vertexBuffer with such code below but it cause error 'COM object that has been separated from its underlying RCW cannot be used.'
. (Are there any way to avoid it?)
Though I think this is a very basic question but in "DirectX way", is it genenerally get "buffer" sufficiently at initialization, and add/remove primitives in the limit of buffer? means, the buffer once aquired, we should NOT re-size it? I was trying to re-make buffers everytime with exact same size of its content. Or are there any right way to resize buffers? (I'm sorry this is the question for DirectX.)
Now my repository contains code below but _device.CreateBuffer()
cause the exception. (Also I put another feature and reduce some nuget packages.)
private void RemakeVBuffer()
{
D3D11_BUFFER_DESC vertexBufferDesc;
_vertexBuffer.Object.GetDesc(out vertexBufferDesc);
var gc = GCHandle.Alloc(((App)Application.Current).DrawManager.VertexData, GCHandleType.Pinned);
vertexBufferDesc.ByteWidth = (uint)((App)Application.Current).DrawManager.VertexData.SizeOf();
var subResourceData = new D3D11_SUBRESOURCE_DATA();
subResourceData.pSysMem = gc.AddrOfPinnedObject();
if ((_vertexBuffer!=null) && !_vertexBuffer.IsDisposed) _vertexBuffer.Dispose();
_vertexBuffer = _device.CreateBuffer(vertexBufferDesc, subResourceData);
gc.Free();
}
In your code here https://github.com/vmx17/ProtoDraw/blob/main/ProtoDraw/Renderers/Dx11Renderer.cs#L139 you do this in a method:
var DXGIDev = new ComObject<IDXGIDevice1>(dxgiDevice);
This will create a disposable DXGIDev
object (ComObject
implements IDisposable
) which instructs the .NET GC to call Dispose
on it "sometimes in the future". When Dispose is called, it will release the underlying COM object. What happens is when you release the DXGI Device, you release the underlying D3D11 device too.
So the solution is to declare DXGIDev as a member instead, like this;
...
private IComObject<ID3D11DeviceContext> _deviceContext;
private IComObject<IDXGIDevice1> _dxgiDevice; // member
private IComObject<IDXGISwapChain1> _swapChain;
...
And do this:
var dxgiDevice = _device.As<IDXGIDevice1>(true);
_dxgiDevice = new ComObject<IDXGIDevice1>(dxgiDevice);
_swapChain = fac.CreateSwapChainForComposition<IDXGISwapChain1>(_dxgiDevice, desc);
Thank you so much. Finally(?) I could understand the reason of RCW error. Though dynamic buffering may be have performance issue, there seems a way to exist. I'can close this issue. Everyone around me was almost giving up WinUI3+DirectX desktop but this is a good progress. Thank you, again.
(my prototype has still have funny matrix issue, but it should be solved with matrices in Render()
method.)
Actually, adding a WinUI3 + DirectN sample to this repo could be interesting.
I've added it here: https://github.com/smourier/DirectN/tree/master/DirectN/DirectN.WinUI3.MinimalD3D11
That's my first trial. Then I derived my least prototyping code from it. My small code is also working. By NOT using normalized axis, and using orthographic projection matrix it became very simple to sync pointer and drawing position.
BTW, don't you have a plan to wrap DirectXMath? I think there are no wrap XMMatrix
in DirectN. I'm now using JeremyAnsel.DirectX.DXMath
.
DirectN is not even a "layer" on top of anything, it's merely .NET bindings over some Windows binaries. The advantages is there's not much code done by hand/a human so it requires much less maintenance.
DirectXMath is only C/C++ code, there's no binary (dll) shipped, so it's not accessible by a .NET bindings. The library you're using is a manual port from some DirectXMath functions (just like some DirectN code in the Manual folder), it's not really "DirectXMath" per se (and it's not up to date with latest DirectXMath precisely because it's a human port).
I manually added some particularly common classes in https://github.com/smourier/DirectN/tree/master/DirectN/DirectN/Manual such as XMFLOAT4 or XMFLOAT3, as well as D2DMATRIX* with some (matrix) utilities, but it's far from being equivalent. More could be added if someone proposes to work on it.
Au... so, XMath/C# function cannot utilize GPU (and it's the reason why I can see C# code). I should not use such functions for many data. The folder name 'Manual' represents such meaning... Thank you (and I'm sorry after closing).
Sorry for the drive by comment, I guess a better alternative to DirectXMath would be to use the .NET SIMD numeric classes.
Sorry for the drive by comment, I guess a better alternative to DirectXMath would be to use the .NET SIMD numeric classes.
Absolutely, but rewriting DirectXMath with SIMD may be quite a work. I don't know of any project that has done that.
In these days I've been trying to use DirectN to my drawing program for prototyping. Now I'm stuck to make dynamic vertex buffer. According to this article and that article, there is a way to translate vertex data via map.
I think this is a simple translation and resizing buffer matter when translate code from C++ to DirectN, please make me understand or point me the way to do. The initialization (written in the first article) seems succeeded with code below; (The code comes from the minimal example but
DemoData
is not in static array.)where;
float[]
) can be obtained as "DemoData.VertexData", but this is NOT static._device
is device created byD3D11Functions.D3D11CreateDevice()
.Before adding new vertex, it just work fine. Just re-sizing
_vertexBuffer
byvertexBufferDesc.ByteWidth
cause errorCOM object that has been separated from its underlying RCW cannot be used.
. So I tried with the code (as writtend in the second article) like below but I could not find out the way to map vertex data correctly. I think the way of "map" seems differ from the way of initialization. There article's code seems no vertex/index buffer update.;Though there are no
_indexBuffer
, situation is same.