Рисование движущейся диаграммы с использованием CocoSharp в Xamarin приводит к снижению частоты кадров - PullRequest
0 голосов
/ 12 июля 2020

Я делаю приложение, которое будет показывать линейную диаграмму измерителя ускорения. Диаграмма должна сдвинуться в сторону, чтобы показать новые результаты. Для рисования я использую графическую библиотеку CocoSharp.

Первая попытка заключалась в том, чтобы перерисовывать всю диаграмму при каждом обновлении, но этого было недостаточно быстро, и почему-то вы не можете рисовать прозрачными, это не стирает ранее нарисованные пиксели, поэтому моя диаграмма просто заполнено.

Вторая попытка заключалась в том, чтобы сделать диаграмму в 4 раза шире экрана и отрисовать последнее обновление только в 2-х позициях: в позиции, которую мы рисуем, и в 2-х ширинах экрана назад (вне экрана). Перед рисованием линии я рисую черную линию вместо прозрачной, чтобы стереть предыдущий результат.

Затем я перемещаю весь слой влево, получая красивую диаграмму прокрутки. Затем, когда позиция превышает 2 ширины экрана, я сбрасываю позицию обратно на 0, но поскольку мы рисуем в двух позициях, график уже нарисован так же, как и в том месте, где мы оставили, что делает его плавным прокруткой навсегда.

Это работает очень хорошо, но через несколько минут рисования можно заметить, что экран начинает отставать в частоте кадров. Я исследовал все, но мой поток рисования работает отлично, выкачивая полное обновление каждые 16 мс, поэтому я думаю, что это библиотека CocoSharp.

Как я уже говорил ранее, когда вы рисуете прозрачным, пиксели не стираются, что заставляет меня думать, что каждое обновление отрисовки каким-то образом сохраняется в памяти, через некоторое время замедляя работу графического процессора. Это могло быть правильно? И если да, то как мне это исправить?

using CocosSharp;
using JumpMeter.Shared;
using JumpMeter.Shared.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JumpMeter
{
    public class ChartLayer
    {
        public ChartLayer(CCScene scene, float x, float y, float width, float height)
        {
            List = new ConcurrentQueue<CalculationLog>();

            RasterLayer = new CCLayer();
            RasterNode = new CCDrawNode();

            GraphLayer = new CCLayer();
            GraphNode = new CCDrawNode();

            // Add the background layer
            RasterLayer.AddChild(RasterNode);

            // Draw the "zero lines"
            RasterNode.DrawLine(new CCPoint(0, height / 2), new CCPoint(width, height / 2), 0.1f, CCColor4B.White);
            RasterNode.DrawLine(new CCPoint(0, 2), new CCPoint(width, 2), 0.1f, CCColor4B.White);
            scene.AddLayer(RasterLayer);

            // Add the graphics layer
            GraphLayer.AddChild(GraphNode);
            scene.AddLayer(GraphLayer);

            Width = width;
            Height = height;

            RasterLayer.PositionX = x;

            RasterLayer.PositionY = y;
            GraphLayer.PositionY = y;
        }

        public CCLayer RasterLayer { get; }
        public CCDrawNode RasterNode { get; }

        public CCLayer GraphLayer { get; }
        public CCDrawNode GraphNode { get; }

        float Width { get; }
        float Height { get; }

        // Buffer for the drawn items
        ConcurrentQueue<CalculationLog> List { get; }

        // Current position of the graph
        float Position { get; set; }

        // Here we get the new values for the graph
        public void AddValue(CalculationLog value)
        {
            List.Enqueue(value);
        }

        // This function will be called every 16ms
        public bool Draw()
        {
            while (List.TryDequeue(out CalculationLog value))
            {
                Position += Constants.GraphSpeed; // = 0.1f

                // If the position is bigger than 2 screen widths (* 1000 for ultra slow speeds)
                if (Convert.ToInt32(Position * 1000) >= Convert.ToInt32(Width * 2 * 1000))
                    Position = 0;

                // Calculate real positions
                var x = Position + RasterLayer.PositionX;
                var y = Convert.ToSingle(value.AccelerationUp / Constants.Scale) * (Height / 2) + Height / 2;

                if (y > Height) y = Height;
                if (y < 0) y = 0;

                var y2 = Convert.ToSingle(value.Height / Constants.Scale * 2) * (Height / 2) + 1;
                if (y2 > Height) y2 = Height;
                if (y2 < 0) y2 = 0;

                // Then draw them
                GraphNode.DrawLine(new CCPoint(x, 0), new CCPoint(x, Height), Constants.GraphSpeed, CCColor4B.Black);
                GraphNode.DrawLine(new CCPoint(x, Height / 2), new CCPoint(x, y), Constants.GraphSpeed, CCColor4B.White);
                GraphNode.DrawLine(new CCPoint(x, y2), new CCPoint(x, y2 + 1), Constants.GraphSpeed, CCColor4B.White);

                GraphNode.DrawLine(new CCPoint(x - Width * 2, 0), new CCPoint(x - Width * 2, Height), Constants.GraphSpeed, CCColor4B.Black);
                GraphNode.DrawLine(new CCPoint(x - Width * 2, Height / 2), new CCPoint(x - Width * 2, y), Constants.GraphSpeed, CCColor4B.White);
                GraphNode.DrawLine(new CCPoint(x - Width * 2, y2), new CCPoint(x - Width * 2, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
            }

            // Move the position of the graph layer
            GraphLayer.PositionX = Convert.ToInt32(Width - Position);

            return true;
        }
    }
}

(на самом деле я рисую 2 графика в 1 графике, я забыл об этом в своем общем описании)

1 Ответ

0 голосов
/ 20 июля 2020

Хорошо, кажется, я был прав. После тестирования без рисования графика приложение не начало заикаться. Теперь я изменил график для работы с двумя слоями, почти так же, как и раньше, только когда я сбрасываю прокрутку, я также сбрасываю предыдущий CCDrawNode с помощью:

GraphNode.Clear();

Полный код:

public class ChartLayer
{
    public ChartLayer(CCScene scene, float x, float y, float width, float height)
    {
        List = new ConcurrentQueue<ICalculationLog>();

        RasterLayer = new CCLayer();
        RasterNode = new CCDrawNode();

        GraphLayer1 = new CCLayer();
        GraphNode1 = new CCDrawNode();

        GraphLayer2 = new CCLayer();
        GraphNode2 = new CCDrawNode();

        // Add the background layer
        RasterLayer.AddChild(RasterNode);

        // Draw the "zero lines"
        RasterNode.DrawLine(new CCPoint(0, height / 2), new CCPoint(width, height / 2), 0.1f, CCColor4B.White);
        RasterNode.DrawLine(new CCPoint(0, 2), new CCPoint(width, 2), 0.1f, CCColor4B.White);
        scene.AddLayer(RasterLayer);

        // Add the graphics layer
        GraphLayer1.AddChild(GraphNode1);
        scene.AddLayer(GraphLayer1);

        GraphLayer2.AddChild(GraphNode2);
        scene.AddLayer(GraphLayer2);

        Width = width;
        Height = height;

        RasterLayer.PositionX = x;

        RasterLayer.PositionY = y;
        GraphLayer1.PositionY = y;
        GraphLayer2.PositionY = y;
    }

    public CCLayer RasterLayer { get; }
    public CCDrawNode RasterNode { get; }

    bool Node1Selected = false;


    public CCLayer GraphLayerForeground => Node1Selected ? GraphLayer1 : GraphLayer2;
    public CCDrawNode GraphNodeForeground => Node1Selected ? GraphNode1 : GraphNode2;
    public CCLayer GraphLayerBackground => Node1Selected ? GraphLayer2 : GraphLayer1;
    public CCDrawNode GraphNodeBackground => Node1Selected ? GraphNode2 : GraphNode1;

    public CCLayer GraphLayer1 { get; }
    public CCDrawNode GraphNode1 { get; }
    public CCLayer GraphLayer2 { get; }
    public CCDrawNode GraphNode2 { get; }

    float Width { get; }
    float Height { get; }

    // Buffer for the drawn items
    ConcurrentQueue<ICalculationLog> List { get; }

    // Current position of the graph
    float Position { get; set; }

    // Here we get the new values for the graph
    public void AddValue(ICalculationLog value)
    {
        List.Enqueue(value);
    }

    // This function will be called every 16ms
    public void Draw()
    {
        while (List.TryDequeue(out ICalculationLog value))
        {
            Position += Constants.GraphSpeed; // = 0.1f

            // If the position is bigger than 2 screen widths (* 1000 for ultra slow speeds)
            if (Convert.ToInt32(Position * 1000) >= Convert.ToInt32(Width * 2 * 1000))
            {
                Position = 0;
                Node1Selected = !Node1Selected;
                GraphNodeBackground.Clear();
            }

            // Calculate real positions
            var x = Position + RasterLayer.PositionX;
            var y = Convert.ToSingle((value.Acceleration.Z - 1) / Constants.Scale) * (Height / 2) + Height / 2;

            if (y > Height) y = Height;
            if (y < 0) y = 0;

            var y2 = Convert.ToSingle(value.Height / Constants.Scale * 2) * (Height / 2) + 1;
            if (y2 > Height) y2 = Height;
            if (y2 < 0) y2 = 0;

            // Then draw them
            //GraphNode1.DrawLine(new CCPoint(x, 0), new CCPoint(x, Height), Constants.GraphSpeed, CCColor4B.Black);
            GraphNodeForeground.DrawLine(new CCPoint(x, Height / 2), new CCPoint(x, y), Constants.GraphSpeed, CCColor4B.White);
            GraphNodeForeground.DrawLine(new CCPoint(x, y2), new CCPoint(x, y2 + 1), Constants.GraphSpeed, CCColor4B.White);

            //GraphNode1.DrawLine(new CCPoint(x - Width * 2, 0), new CCPoint(x - Width * 2, Height), Constants.GraphSpeed, CCColor4B.Black);
            GraphNodeBackground.DrawLine(new CCPoint(x - Width * 2, Height / 2), new CCPoint(x - Width * 2, y), Constants.GraphSpeed, CCColor4B.White);
            GraphNodeBackground.DrawLine(new CCPoint(x - Width * 2, y2), new CCPoint(x - Width * 2, y2 + 1), Constants.GraphSpeed, CCColor4B.White);
        }

        // Move the position of the graph layer
        GraphNodeForeground.PositionX = Convert.ToInt32(Width - Position);
    }
    public void Clear()
    {
        GraphNode1.Clear();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...