Dessinant des chemins d'accès et l'accélération matérielle
Je dessine un assez grand chemin, à mon avis, et je suis en cours d'exécution dans certains problèmes de performances. Le chemin est actuellement de 32 000 points de longtemps, mais mon application doit échelle d'au moins de 128 000 points. Je ne peux pas vraiment faire quelque chose au sujet de la taille de la trajectoire, comme les ensembles de données sont ce qu'ils sont grands et j'ai besoin d'être en mesure d'afficher le chemin d'accès complet à la fois et permettent de zoomer.
Je suis sur un Nexus 10 sous Android 4.2, qui a l'accélération matérielle activée par défaut pour les applications qui ne sont pas explicitement le désactiver.
Le chemin est créé avec le code suivant (j'ai omis certains d'installation et d'autres parties non pertinentes):
dataPath.moveTo(0, offset - (float) data[leftLimit]/ scalingFactor);
for (int i = leftLimit; i < rightLimit; ++i) {
x = (i - leftLimit) * dx;
y = offset - (float) data[i]/ scalingFactor;
dataPath.lineTo(x, y);
}
Et ensuite tirer dans le onDraw()
méthode:
canvas.drawColor(Color.WHITE);
canvas.drawPath(dataPath, linePaint);
J'ai mesuré le temps qu'il faut pour attirer mon point de vue à l'aide de adb shell dumpsys gfxinfo
avec et sans accélération matérielle, et à ma grande surprise, l'accélération matérielle est beaucoup plus lente:
Avec l'accélération matérielle:
Sans l'accélération matérielle:
L'accélération matérielle version prend environ 200-300 ms par image, pour la plupart passé dans l'étape de Processus. Le non-accéléré version dure environ 50 ms, avec 2/3 dans le Tirage au sort de scène et 1/3 dans l'étape de processus.
Évidemment, même ma version plus rapide sans l'accélération matérielle est encore trop lente pour atteindre les 60 fps, ou même d'être à peine utilisable quand je bouge de plus grands ensembles de données.
L'idée de rendre le chemin d'accès à une image et ensuite seulement de les transformer en une image bitmap à l'écran est également problématique dans mon cas. J'ai besoin de soutien zoom très loin sur le chemin, et pour activer le zoom avant sans le chemin d'accès de la qualité de l'obtention de beaucoup plus mauvais que j'aurais à rendre surdimensionné bitmaps du chemin (et serait susceptible d'exécuter dans les limites de la mémoire et de la taille de la texture des limites). Et lorsque le zoom au loin, j'aurais pour créer de la plus récente des images d'une partie seulement du chemin d'accès, ou de passer à juste rendu le chemin d'accès directement, ce qui risquait d'entraîner des retards de plus que le framerate si la performance est encore semblable à ce que j'ai droit maintenant.
Ce que je me pose maintenant est
- Est le dessin des lignes de chemins de quelque chose de juste le GPU est mauvaise et que l'on ne devrait pas essayer de matériel d'accélérer, ou suis-je susceptible de faire quelque chose de mal qui provoque la mauvaise performance?
- Est-ce que je peux faire pour attirer de tels chemins avec des performances acceptables?
- Comment OpenGL s'inscrivent dans ce exactement?
- L'accélération matérielle utilise OpenGL, autant que je le comprends. Mais je n'étais pas sûr de la balise à utiliser, il.
- Comment êtes-vous ce dessin? Si vous parcelle de 1 point à la fois pour le GPU, alors vous obtiendrez probablement un moins bon rendement, mais si vous le lot de tout à ceux que vous devriez voir une augmentation, au moins en théorie.
- J'ai ajouté le code qui dessine le chemin, je suis de la création du chemin d'accès complet et le tracer d'un seul coup.
- Si vous êtes un zoom, il n'y a vraiment aucun point dans le dessin 128k points? Très probablement, ils seront impossibles à distinguer. Je recommande si vous effectuez un zoom avant, vous pouvez sauter ou moyenne certains de ces points.
- J'y ai pensé, mais c'est assez compliqué. Je ne peux pas juste dans la moyenne des points, que pouvait cacher le montant de bruit dans les données, ce qui conduirait à un mauvais affichage des données. Je vais probablement avoir à aller dans cette direction à la fin, j'espérais que le pouvoir de l'actuel Gpu serait assez et j'ai pu mettre en œuvre une solution simple.
- hehe bon essayer, c'est de savoir comment vous faites les mauvais code 🙂
- Il peut être utile de vérifier Douglas-Pecker algorithme: en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
- En plus de la R*-arbres (ou quelque chose de similaire) peut efficacement répondre à la question: "Quels sont les Points à l'intérieur de ce rect"
- dans ce cas, ce type de cartes peut vous aider: en.wikipedia.org/wiki/Candlestick_chart. Cela peut ne pas être applicables dans votre cas, mais peut-être que vous avez l'idée et est venu avec quelque chose d'autre.
Vous devez vous connecter pour publier un commentaire.
Les chemins sont toujours rendus à l'aide de la CPU. Lorsque l'application est pour l'accélération matérielle cela signifie que le rendu sera d'abord attirer votre chemin à l'aide de la CPU dans un bitmap, puis de télécharger l'image bitmap comme texture pour le GPU et enfin dessiner la texture à l'écran.
Lignes sont entièrement à la charge l'accélération matérielle. Au lieu d'utiliser un
Path
je vous recommande d'utiliserCanvas.drawLines()
dans ce cas.Vous devez soit utiliser
Canvas.drawLines()
ou rendre le chemin vous-même dans unBitmap
que vous gérez.Bitmap
et leur permettant d'être déplacé le long de l'écran, j'ai poussé un code simple ici. J'ai utilisé la même technique pour réaliser le dessin de ces chemins sur l'accélération GPU MapView comme une superposition (où d'habitude l'accélération GPU de la méthode de Chemin de dessin sur l'écran de Superposition a été l'origine deShape path too large to be rendered into a texture
d'erreur en raison de la taille de la texture de la limitation sur le GPU).Canvas.drawLines(float[], Paint)
avec un lot de points, au lieu de multiples appels àCanvas.drawLine(int. int, int, int)
avec un seul point, l'augmentation de la performance de manière significative.Canvas.drawLines()
utilise l'accélération matérielle ? Je demande cela parce que j'avais une très mauvaise performance, la recherche de la performance des conseils, mais n'a pas trouver quelque chose de significatif, jusqu'à ce que j'ai lu cette réponse.Il semble que vous pourriez être en cours d'exécution en général goulot d'étranglement dans le GPU. Regardez les liens ci-dessous:
Comment faire la route de dessin plus efficace
Android toile chemin de la performance en temps réel
De commutation à partir d'une toile à OpenGL
En particulier la première, qui vous suggérons de faire une image bitmap et dessiner à la place. Il semble que vous pouvez obtenir de meilleures performances si vous changez d'openGL. Il y a peut être un peu de magie de manière à obtenir des méthode de travail, mais je ne suis pas au courant de cela en ce moment.
Pourquoi vous voyez le comportement que vous faites est probablement parce que vous envoyer toutes les données pour le GPU entre chaque tirage. Vous devez mettre en cache sur le GPU et l'utilisation de la traduction dans la place. Pas recréer les données et de les envoyer tous à la GPU. Vous êtes probablement I/O bound, ce qui signifie le taux de transmission entre le CPU et le GPU est qu'est-ce que la limitation de votre performance. Je ne peux pas être sûr à 100% de cette sur la base des données que vous avez fournies, mais c'est ma meilleure supposition. Essayez différentes techniques de mise en cache, principalement de la png-cache à partir du lien #1.
Dessin d'un chemin sera plus que de simplement "raconter" le GPU pour dessiner des lignes. Un chemin d'accès a de nombreuses caractéristiques, par exemple, comment extrémités des lignes sont traités ou qu'une ligne en pointillés, quelque chose qui est pas de l'accélération GPU. Il est probablement alors un autre hoquet lorsque vous rencontrez que de nombreuses lignes qui rend la combinaison du PROCESSEUR et de l'accélération GPU d'y aller plus lentement. La solution proposée ci-dessus pour passer à
canvas.drawLines
au lieu decanvs.drawPath
et essayez de ne pas utiliser de fantaisiePaint
méthode pourrait aider.Si cela n'aide pas, vous pouvez essayer d'utiliser un GLSurfaceView et de rendre les lignes directement dans la place. Qui va impliquer quelques OpenGL ES connaissances, mais ne devrait pas être très difficile à faire et pourrait être beaucoup plus efficace.