theproadam / renderXF

High performance software rendering in c#
MIT License
11 stars 4 forks source link

Parallel rendering of multiple images (crash) #4

Closed kf6kjg closed 3 years ago

kf6kjg commented 3 years ago

I am attempting to render multiple images at the same time. Occasionally I get AccessViolationException errors. image

Each thread gets its own instance of renderX.

However if I render my images sequentially, which takes quite a bit of time, this is not the case. Is it a requirement of this library that there can only be a single instance running at a time?

theproadam commented 3 years ago

@kf6kjg Each renderX instance gets its own independent variables, so it should work perfectly fine in parallel. My theory is that the issue exists for both parallel and sequential drawing, however since the parallel version is much faster, you get the crash faster.

As for the crash, can you send the GLBuffer myBuffer = new GLBuffer(arg1, arg2) initialization which was used for buffer being drawn and the shader configuration for it, with its modifications, ie:

Shader myShader = new Shader(VS, FS, GLRenderMode.Triangle);
myShader.SetOverrideAttributeCopy(false); //Example modification 1
myShader.SetOverrideAttributeCount(3); //Example modification 2
kf6kjg commented 3 years ago

I've pushed my code to a temporary branch. Here's a link to the relevant location: https://github.com/kf6kjg/Anaximander2/blob/realrender/Source/Anaximander/Renderers/renderXFRenderer/xfRenderer.cs#L408

Relevant code block currently looks like

using (var vertexBuffer = new GLBuffer(terrainVertexPoints, terrainVertexStride, MemoryLocation.Heap))
{
    GL.SelectBuffer(vertexBuffer);
    var terrainShader = new Shader(_shaders.ScaleCorrectionVS, _shaders.TerrainShaderFS, GLRenderMode.Triangle);
    terrainShader.SetOverrideAttributeCount(terrainVertexStride - 3); // UVZ
    GL.SelectShader(terrainShader);
    GL.Draw();
}
theproadam commented 3 years ago

@kf6kjg Unfortunately I am stumped, as I cannot actually run the code, and my attempts at recreating the crash are unsuccessful. My first theory is related to the GLBuffer not being a complete triangle, as there are currently no checks for that, and my second theory is related with 64 bit code and memory usage, however crashing at index = 0, and no pointer casting to 32bit types should rule both of those out.

In the meanwhile can you add these extra lines to your code to first print the memory address of the buffer, and then to test if the allocated buffer is actually valid or not (to rule out Marshal.AllocHGlobal breaking). I would suggest running this until you crash and report back with the memory address of IN inside the Locals tab, and the Debug printout of the memory address. Ideally this should be ran not in parallel to easier debug the data, however if a crash takes too long it might just be faster do it in parallel.

using (var vertexBuffer = new GLBuffer(terrainVertexPoints, terrainVertexStride, MemoryLocation.Heap))
{
    GL.SelectBuffer(vertexBuffer);
    var terrainShader = new Shader(CubeVS, CubeFS, GLRenderMode.Triangle);
    terrainShader.SetOverrideAttributeCount(3); // UVZ
    GL.SelectShader(terrainShader);

    //DEBUG LINES:
    IntPtr addr = vertexBuffer.GetAddress(); //get address
    Debug.WriteLine("addr-> " + addr); //show address
    float readtest = ((float*)addr)[0];; //test address

    GL.Draw();
}
kf6kjg commented 3 years ago

Oh, I found the problem: I'm only using a single instance of my XFRenderer class, with its methods being called in parallel. That means that I'm using a single instance of renderX, which totally explains all this. Refactored it so that I utilized one instance of renderX per parallel image being rendered, and problem solved.