Perfore un agujero en una superposición de rectángulo con la aceleración HW habilitada en la vista


Tengo una vista que hace algunos dibujos básicos. Después de esto quiero dibujar un rectángulo con un agujero perforado para que solo una región del dibujo anterior sea visible. Y me gustaría hacer esto con la aceleración de hardware habilitada para mi vista para el mejor rendimiento.

Actualmente tengo dos métodos que funcionan, pero solo funciona cuando se deshabilita la aceleración de hardware y el otro es demasiado lento.

Método 1: Aceleración SW (Lenta)

final int saveCount = canvas.save();

// Clip out a circle.
circle.reset();
circle.addCircle(cx, cy, radius, Path.Direction.CW);
circle.close();
canvas.clipPath(circle, Region.Op.DIFFERENCE);

// Draw the rectangle color.
canvas.drawColor(backColor);

canvas.restoreToCount(saveCount);

Esto no funciona con la aceleración de hardware habilitada para la vista porque ' canvas.clipPath' no está soportado en este modo (sé que puedo forzar el renderizado SW, pero me gustaría evitar eso).

Método 2: Aceleración HW (V. Lenta)

// Create a new canvas.
final Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
final Canvas c = new Canvas(b);

// Draw the rectangle colour.
c.drawColor(backColor);

// Erase a circle.
c.drawCircle(cx, cy, radius, eraser);

// Draw the bitmap on our views  canvas.
canvas.drawBitmap(b, 0, 0, null);

Donde el borrador se crea como

eraser = new Paint()
eraser.setColor(0xFFFFFFFF);
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

Esto es obviamente lento {un nuevo Bitmap el tamaño de la vista se crea cada llamada de dibujo.

Método 3: Aceleración HW (Rápida, no funciona en algunos dispositivos)

canvas.drawColor(backColor);
canvas.drawCircle(cx, cy, radius, eraser);

Mismo como el método compatible de aceleración HW, pero no se requiere lienzo adicional. Sin embargo, hay un gran problema con esto works funciona con el renderizado SW forzado, pero en el HTC One X (Android 4.0.4 probably y probablemente algunos otros dispositivos) al menos con el renderizado HW habilitado, deja el círculo completamente negro. Esto probablemente está relacionado con 22361.

Método 4: Aceleración HW (Aceptable, funciona en todos los dispositivos)

Según la sugerencia de Jan para mejorar el método 2, I evitó crear el mapa de bits en cada llamada a onDraw, en lugar de hacerlo en onSizeChanged:

if (w != oldw || h != oldh) {
    b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    c = new Canvas(b);
}

Y luego solo usé estos en onDraw:

if (overlayBitmap == null) {
   b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
   c = new Canvas(b);
}
b.eraseColor(Color.TRANSPARENT);
c.drawColor(backColor);
c.drawCircle(cx, cy, radius, eraser);
canvas.drawBitmap(b, 0, 0, null);

El rendimiento no es tan bueno como el método 3, pero mucho mejor que 2 y ligeramente mejor que 1.

La cuestión

¿Cómo puedo lograr el mismo efecto pero hacerlo de una manera compatible con la aceleración HW (Y eso funciona de manera consistente en dispositivos)? Un método que aumenta el rendimiento de renderizado SW también sería aceptable.

NB: Al mover el círculo alrededor, solo estoy invalidando una región, no todo el lienzo, por lo que no hay espacio para una mejora del rendimiento allí.

Author: Joseph Earl, 2012-11-23

1 answers

En lugar de asignar un nuevo lienzo en cada repintado, debería poder asignarlo una vez y luego reutilizar el lienzo en cada repintado.

Al inicio y al redimensionar:

Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);

Al repintar:

b.eraseColor(Color.TRANSPARENT);
    // needed if backColor is not opaque; thanks @JosephEarl
c.drawColor(backColor);
c.drawCircle(cx, cy, radius, eraser);

canvas.drawBitmap(b, 0, 0, null);
 17
Author: John Dvorak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-23 13:26:21