SharpGL - Утечка памяти при использовании массива вершинных буферов? - PullRequest
0 голосов
/ 04 августа 2020

В настоящее время я работаю над графическим приложением в WPF. По соображениям производительности (и из любопытства) я использую SharpGL для рендеринга графиков, который отлично работает. По крайней мере, на поверхности.

Когда я недавно переключился на использование массива буферов вершин, чтобы минимизировать вызовы отрисовки и поместить больше кода масштабирования в шейдеры, я обнаружил утечку памяти. Я в основном перешел с использования gl.Vertex(px, py, z); на код, показанный ниже. Это привело к значительному увеличению частоты кадров, но также в приложении внезапно произошла утечка памяти, что можно увидеть на снимке экрана профилирования. Первый скачок происходит при загрузке данных графика, но после этого в основном продолжается рост.

Результаты профилирования

Кто-нибудь может указать мне, где может быть проблема? В основном это соответствует образцу кода из репозитория SharpGL, который, как я ожидал, будет работать нормально. видимый временной диапазон. В будущем, если возможно, это будет перенесено в вершинный шейдер.

Вот код отрисовки (не очень оптимизированный, не очень чистый, но, я думаю, вы поняли):

private void openGLControl1_OpenGLDraw(object sender, SharpGL.WPF.OpenGLRoutedEventArgs args)
    {
        //  Get the OpenGL instance.
        var gl = args.OpenGL;

        gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
        
        // Resample datapoints dynamically if horizontal scale changed
        if (_horizontalScale != _prevHorizontalScale || firstRender)
        {
            ApplyDynamicDownsampling(ActiveSeriesCount, false, false);
            _prevHorizontalScale = _horizontalScale;
        }

        // Rendering process
        int z = 0;
        double x_min = 0;
        double x_max = 1;
        double y_min = 0.0;
        double y_max = 0.0;
        double x_start = _startingPoint;
        double x_end = _startingPoint + _horizontalScale;
        foreach (string sname in _rawSeries.Keys)
        {
            // Vertex and color data (flattened)
            float[] vertexData = new float[3* _sampledPoints[sname].Count];
            float[] colorData = new float[3 * _sampledPoints[sname].Count];
          
            // Only draw enabled series
            if (_sampledPoints.ContainsKey(sname) && _rawSeries[sname].Enabled)
            {
                var col = _rawSeries[sname].Color;
                
                // Flatten datapoints for vertex buffer
                float px, py;
                for (int i = 0; i < _sampledPoints[sname].Count; i++)
                {
                    // Get point coordinates
                    px = (float)_sampledPoints[sname][i].X;
                    py = (float)_sampledPoints[sname][i].Y;
                    // Get graph limits
                    x_min = Math.Min(x_min, px);
                    x_max = Math.Max(x_max, px);
                    y_min = Math.Min(y_min, py);
                    y_max = Math.Max(y_max, py);
                    // Store vertex data
                    vertexData[3 * i + 0] = px;
                    vertexData[3 * i + 1] = py;
                    vertexData[3 * i + 2] = z;
                    // Store color data
                    colorData[3 * i + 0] = (float)col.R / 255.0f;
                    colorData[3 * i + 1] = (float)col.G / 255.0f;
                    colorData[3 * i + 2] = (float)col.B / 255.0f;
                }

                // Create a orthogonal projection matrix and map 0...HorizontalScale to the screen
                projectionMatrix = glm.ortho(0, (float)_horizontalScale, (float)y_min, (float)y_max);
                // Translate the whole graph based on the chosen starting point
                modelMatrix = glm.translate(new mat4(1.0f), new vec3(-(float)_startingPoint, 0,0));

                // Vertex Array Buffer Variant
                // ------------------------------------------
                //  Create the vertex buffer array object.
                vertexBufferArray.Bind(gl);
                vertexBufferArray.Create(gl);
                vertexBufferArray.Bind(gl);

                //  Create a vertex buffer for the vertex data.
                vertexDataBuffer.Create(gl);
                vertexDataBuffer.Bind(gl);
                vertexDataBuffer.SetData(gl, attribute_vpos, vertexData, false, 3);

                //  Now do the same for the colour data.
                colourDataBuffer.Create(gl);
                colourDataBuffer.Bind(gl);
                colourDataBuffer.SetData(gl, attribute_vcol, colorData, false, 3);

                //  Unbind the vertex buffer array, we've finished specifying data for it.
                vertexBufferArray.Unbind(gl);

                // Shader-Stuff
                shaderProgram.Bind(gl);
                shaderProgram.SetUniformMatrix4(gl, "projectionMatrix", projectionMatrix.to_array());
                shaderProgram.SetUniformMatrix4(gl, "viewMatrix", viewMatrix.to_array());
                shaderProgram.SetUniformMatrix4(gl, "modelMatrix", modelMatrix.to_array());

                // Render vertex buffer contents
                vertexBufferArray.Bind(gl);
                gl.DrawArrays(OpenGL.GL_LINE_STRIP, 0, _sampledPoints[sname].Count);
                vertexBufferArray.Unbind(gl);

                // Shader-Stuff
                shaderProgram.Unbind(gl);
            }
        }
    }
...