Un interesante artículo que describe como desarrollar aplicaciones con el mejor rendimiento posible en aparatos móviles, usando JavaFX Script:
- Evitar bindings innecesarios
- Mantener el scenegraph lo más pequeño posible
- Usar Integer en vez de Number
- Usar figuras simples en vez de imágenes
- Usar funcionalidad de pre-escalado
- Usar background loading ("descarga de fondo")
- Usar funciones de clase Sequences
Aquí está el artículo completo. Más adelante revisaré cada recomendación, para compartir los "descubrimientos" ;)
http://java.sun.com/developer/technicalArticles/javafx/mobile/
Mostrando entradas con la etiqueta rendimiento. Mostrar todas las entradas
Mostrando entradas con la etiqueta rendimiento. Mostrar todas las entradas
viernes, 8 de mayo de 2009
jueves, 23 de abril de 2009
Cache:true ... otro detalle para mejorar el rendimiento gráfico
Si, por ejemplo, utilizas una figura con una gradiente -o sombra- como fondo de un área, es mejor agregar a esa figura el parámetro cache:true, de manera de evitar que el objeto sea re-dibujado con cada cambio que se realiza por encima de él (en el caso de una gradiente, debe volver a recalcular y redibujar cada franja de color que conforma la transición entre los colores... lo que resulta sumamente "caro" en términos de procesamiento).
El código al pie del artículo
El código al pie del artículo
Al agregar cache:true se le indica al sistema que debe generar la imagen una vez y guardarla en cache, de esta menera, cuando se realiza un cambio sobre ella, sólo recupera la imagen desde una copia almacenada en memoria (como bytes) y pinta los cambios encima, lo que resulta sumamente rápido y menos "costoso" en ciclos de procesamiento.
En todo caso, no debes utilizar cache:true cuando la imagen va a cambiar con frecuencia, porque esto sólo producirá que sea re-generada con cada cambio, pero además almacenada, lo que da por resultado un proceso mucho más "costoso". El cache:true debe ser utilizado en imágenes que NO cambian frecuentemente.
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.scene.effect.DropShadow;
var px:Number;
var py:Number;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse:true
keyFrames : [
KeyFrame {
time : 0s
values: [px=>100, py=>100]
}
KeyFrame {
time : 3s
canSkip : true
values: [px=>1180, py=>680]
}
]
}.play();
var angle:Number;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse:true
keyFrames : [
KeyFrame {
time : 0s
values: [angle=>0]
}
KeyFrame {
time : 1.5s
canSkip : true
values: [angle=>360]
}
]
}.play();
Stage {
title: "Application title"
width: 1024
height: 768
scene: Scene {
content: [
Rectangle {
cache:true
x: 0, y: 0
width: 1280, height: 768
fill: LinearGradient {
startX : 0.0
startY : 0.0
endX : 1.0
endY : 0.0
stops: [
Stop {
color : Color.BLACK
offset: 0.0
},
Stop {
color : Color.BLUE
offset: 1.0
},
]
}
effect: DropShadow { offsetX:10, offsetY:10 }
}
Rectangle {
x: bind px, y: bind py
width: 200, height: 200
fill: Color.RED
rotate: bind angle
}
]
}
}
sábado, 18 de abril de 2009
Como mejorar la partida de Java Web Start
Aquí hay un truco para mejorar la velocidad de partida de las aplicaciones JavaFX Web Start.
Todo lo que necesitas hacer es agregar una linea a tus archivos JNLP.
El elemento update se usa para indicar la preferencia sobre como Java Web Start maneja las actualizaciones. El elemento update puede contener los siguientes atributos opcionales:
Atributo check: El atributo check indica la preferencia sobre cuando el cliente JNLP debe chequear por actualizaciones, y puede tener uno de los siguientes tres valores:
1. "always": Siempre chequea por actualizaciones antes de lanzar la aplicación.
2. "timeout" (default): Chequea por actualizaciones hasta alcanzar un umbral de tiempo (timeout) antes de lanzar la aplicación. Si el chequeo de actualización no se completa antes del timeout, la aplicación es lanzada, y el chequeo de actualización continua por "atras" del proceso de la aplicación.
3. "background": Lanza la aplicación mientras chequea si existen actualizaciones simultaneamente, por "atras".
La opción 3 mejorará el tiempo de partida de las aplicaciones JavaFX Web Start.
Todo lo que necesitas hacer es agregar una linea a tus archivos JNLP.
<update check="background">
El elemento update se usa para indicar la preferencia sobre como Java Web Start maneja las actualizaciones. El elemento update puede contener los siguientes atributos opcionales:
Atributo check: El atributo check indica la preferencia sobre cuando el cliente JNLP debe chequear por actualizaciones, y puede tener uno de los siguientes tres valores:
1. "always": Siempre chequea por actualizaciones antes de lanzar la aplicación.
2. "timeout" (default): Chequea por actualizaciones hasta alcanzar un umbral de tiempo (timeout) antes de lanzar la aplicación. Si el chequeo de actualización no se completa antes del timeout, la aplicación es lanzada, y el chequeo de actualización continua por "atras" del proceso de la aplicación.
3. "background": Lanza la aplicación mientras chequea si existen actualizaciones simultaneamente, por "atras".
La opción 3 mejorará el tiempo de partida de las aplicaciones JavaFX Web Start.
Etiquetas:
como,
configuracion,
how to,
howto,
java web start,
javafx,
jnlp,
jws,
mas,
mejora,
mejorar,
partida,
performace,
rendimiento,
tip,
trick,
truco,
velocidad
jueves, 16 de abril de 2009
Un detalle para obtener una mejor performance
Este detalle (junto con incluir canSkip:true en los timelines asociados a animaciones o transiciones gráficas de algún tipo) puede hacer una gran diferencia en la performance gráfica de JavaFX.
Tengo un CustomNode cuyo contenido son unos nodos almacenados en una secuencia:
Digamos que se necesita reemplazar con frecuencia los nodos en objs y que tengo una función que realiza este trabajo:
Como muestra el video, eso es ineficiente. Al estar enlazado el contenido de objs con el contenido del componente e ir cambiando el contenido de objs, se va gatillando trabajo para refrescar el componente.
Es más eficiente crear una secuencia temporal y traspasar al final todos los nodos a la secuencia asociada al componente:
Habría que probar si esto también es aplicable cuando se realizan cambios a los elementos en la secuencia (y no sólo cuando estos se reemplazan). Es probable que ocurra lo mismo, porque al actualizar uno a uno los elementos, es muy probable que también se vaya gatillando trabajo parcial, mientras si se reemplaza toda la secuencia de una vez, ese trabajo debería ocurrir una sóla vez... ¿?
Tengo un CustomNode cuyo contenido son unos nodos almacenados en una secuencia:
public class myComponent extends CustomNode {
var objs:Node[];
public override function create(): Node {
Group {
content: bind objs
};
};
}
Digamos que se necesita reemplazar con frecuencia los nodos en objs y que tengo una función que realiza este trabajo:
function paint():Void {
delete objs;
for (element in someGroup) {
...
insert newNode into objs;
...
}
}
Como muestra el video, eso es ineficiente. Al estar enlazado el contenido de objs con el contenido del componente e ir cambiando el contenido de objs, se va gatillando trabajo para refrescar el componente.
Es más eficiente crear una secuencia temporal y traspasar al final todos los nodos a la secuencia asociada al componente:
function paint():Void {
var tmpObjs:Node[];
for (element in someGroup) {
...
insert newNode into tmpObjs;
...
}
objs = tmpObjs;
}
Habría que probar si esto también es aplicable cuando se realizan cambios a los elementos en la secuencia (y no sólo cuando estos se reemplazan). Es probable que ocurra lo mismo, porque al actualizar uno a uno los elementos, es muy probable que también se vaya gatillando trabajo parcial, mientras si se reemplaza toda la secuencia de una vez, ese trabajo debería ocurrir una sóla vez... ¿?
Etiquetas:
animacion,
animaciones,
como,
fps,
frames,
grafica,
grafico,
graphic,
how to,
javafx,
per second,
performance,
por segundo,
problema,
rendimiento,
resolver,
solucion,
velocidad
sábado, 31 de enero de 2009
JavaFX: ¿Cuantas bolitas? (test de rendimiento gráfico)
Este ejercicio contiene 3 controles de barra que permiten ajustar:
1) El número de bolas rebotando en la ventana;
2) La transparencia de las bolas;
3) El radio de las bolas.
Cada nueva bola que se agrega, lo hace con un efecto (cambia el radio un par de veces) y luego continua rebotando entre los márgenes de la ventana. Si se aumenta el tamaño de la ventana, el area de desplazamiento aumenta, si se reduce, las bolas que se encuentran más alla del nuevo margen, regresan al centro de la ventana.
Un area de texto muestra el número de bolas en la ventana, el porcentaje de transparencia y el radio de los círculos.
Una instrucción importante es "canSkip:true", en el Timeline que actualiza la posicion de las bolas (y que por lo tanto, las redibuja). Esta instrucción evita que la CPU se sobrecargue de trabajo y solo realiza la actualización de las bolas si hay capacidad de procesamiento disponible. Intenten con unas 200 bolas y quiten el canSkip y veran como el programa se "pega".
Archivo Maix.fx
Archivo element.fx
1) El número de bolas rebotando en la ventana;
2) La transparencia de las bolas;
3) El radio de las bolas.
Cada nueva bola que se agrega, lo hace con un efecto (cambia el radio un par de veces) y luego continua rebotando entre los márgenes de la ventana. Si se aumenta el tamaño de la ventana, el area de desplazamiento aumenta, si se reduce, las bolas que se encuentran más alla del nuevo margen, regresan al centro de la ventana.
Un area de texto muestra el número de bolas en la ventana, el porcentaje de transparencia y el radio de los círculos.
Una instrucción importante es "canSkip:true", en el Timeline que actualiza la posicion de las bolas (y que por lo tanto, las redibuja). Esta instrucción evita que la CPU se sobrecargue de trabajo y solo realiza la actualización de las bolas si hay capacidad de procesamiento disponible. Intenten con unas 200 bolas y quiten el canSkip y veran como el programa se "pega".
Archivo Maix.fx
package howmany;
import javafx.scene.*;
import javafx.stage.Stage;
import javafx.ext.swing.SwingSlider;
import javafx.scene.layout.VBox;
import javafx.scene.text.*;
// si cambia tamaño de la ventana
// reposiciona los circulos mas alla del margen
var maxX=250.0 on replace { circles.resetPos() };
var maxY=250.0 on replace { circles.resetPos() };
// seleccion numero de bolas
var selector = SwingSlider {
minimum: 0
maximum: 100
value: 0
vertical: false
};
// transparencia de las bolas
var transparency = SwingSlider {
minimum: 0
maximum: 100
value: 50
vertical: false
};
// radio de las bolas
var radius = SwingSlider {
minimum: 0
maximum: 40
value: 20
vertical: false
};
// texto para desplegar valores
var total = Text {
font: Font { size: 18 }
textOrigin:TextOrigin.TOP;
};
// componente que contiene los circulos
var circles = element {
balls:bind selector.value;
radius:bind radius.value;
level:bind transparency.value / 100.0;
display: total
maxX:bind maxX
maxY:bind maxY
};
Stage {
// si cambia tamaño de la ventana
// actualiza variables con dimensiones
width: bind maxX with inverse
height: bind maxY with inverse
scene: Scene { content: [
circles,
VBox { content: [
selector,
transparency,
radius,
total ]
} ]
}
}
Archivo element.fx
package howmany;
import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.animation.*;
import java.lang.Math;
// clase que extiende circulos
class ball extends Circle {
// "sobreescribe" los parametros del circulo normal,
// de manera de tener los valores en la nueva clase
override var stroke = null;
override var fill = Color.RED;
override var centerX = 100;
override var centerY = 100;
override var radius = 10;
override var scaleX;
override var scaleY;
public var incx;
public var incy;
// mueve el circulo en los incrementos de la instancia
function move():Void {
centerX += incx;
centerY += incy;
if (centerX<0 or centerX>maxX) then
incx = -incx;
if (centerY<0 or centerY>maxY) then
incy = -incy;
};
// efecto para cuando crea el circulo
// cambia un par de veces de tamaño (como rebote)
var dropIn = Timeline {
repeatCount:5
autoReverse:true
keyFrames: [
at (0s) { scaleX => 2.0; scaleY => 2.0 }
at (0.3s) { scaleX => 1.0; scaleY => 1.0 }
]
};
// al crear el circulo, dispara el efecto de rebote
postinit {
dropIn.play();
};
};
// clase que contiene a todos los circulos
public class element extends CustomNode {
public var balls = 50.0;
public var display = Text { };
public var maxX;
public var maxY;
// si cambia la transparencia
public var level = 1.0 on replace {
// actualiza la opacidad de todos los circulos
for (obj in objs) obj.opacity = level; };
// si cambia el radio
public var radius = 10.0 on replace {
// actualiza el radio de todos los circulos
for (obj in objs) obj.radius = radius; };
// arreglo que contiene todos los circulos
var objs:ball[];
// colores que asigna a los circulos
var colors:Color[]=[
Color.RED, Color.BLUE, Color.YELLOW,
Color.PURPLE, Color.CYAN];
var i=0;
// agrega nuevo circulo al componente
function addBall():Void {
var ix=Math.random()*15 - 7;
var iy=Math.random()*15 - 7;
var circ = ball {
centerX:maxX/2
centerY:maxY/2
incx: ix
incy:iy
radius:radius
fill: colors[i mod sizeof colors]
opacity:level
};
insert circ into objs;
};
// crea el componente con los circulos
override function create():Node {
// chequea si debe agregar o quitar circulos
Timeline {
repeatCount:Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0.2s
action: function():Void {
display.content=
"{sizeof objs} / {(level*100) as Integer}% / {radius}";
if (sizeof objs < balls) then {
addBall();
i++;
}
if (sizeof objs > balls) then
delete objs[0];
}
}
]
}.play();
// mueve los circulos
Timeline {
repeatCount:Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0.04s
// para evitar que se sobrecargue de trabajo
canSkip: true
action: function():Void {
for (obj in objs)
obj.move();
}
}
]
}.play();
// retorna el componente con los circulos
Group {
content: bind objs
};
};
// reposicion los circulos si excende el margen
public function resetPos():Void {
for (obj in objs) {
var pos = obj.boundsInScene;
if (pos.maxX > maxX) then
obj.centerX = maxX/2 ;
if (pos.maxY > maxY) then
obj.centerY = maxY/2 ;
}
};
}
Etiquetas:
ajuste,
animacion,
animation,
barra,
control,
controles,
grafico,
graficos,
graphics,
java,
javafx,
performace,
rendimiento,
resize,
slider,
tamaño,
transparencia,
transparency,
ventana,
windows
Suscribirse a:
Entradas (Atom)