Dibujar mapa de bits rápidamente en ARM Cotex

0

Estoy tratando de borrar una imagen con sprites, animada. Al dibujar el sprite animado, dibujo un fondo antes de los sprites. Con los sprites, el juego se ve suave y jugable, y el fondo se vuelve muy lento.

Estoy usando una imagen de 240 * 320. Hice lo mejor que pude para optimizar el código y eso es a lo que he recurrido.

void  DrawSprite(sprite_ptr spr, uint8_t *fb)
{
    const uint16_t* data = (spr->num_frames > 1 ) ? spr->frames[spr->curr_frame] : spr->imgData;

    uint16_t spriteHeight = spr->height;
    uint16_t spriteWidth  = spr->width;
    uint16_t x = spr->x;
    uint16_t y = spr->y;  

    for (int i = 0; i < spriteHeight; i++)
    {
        for (int j = 0; j < spriteWidth; j++)  
        {
            uint16_t color = data[j];
            if (color != 0)
            {
                LCD_DrawPixel(fb,j + x , i + y, color);
            }
        }

        data+=spriteWidth;  
    }
}

CÓDIGO MODIFICADO:

void  DrawSprite(sprite_ptr spr, uint8_t *fb)
{
      const uint16_t* data = (spr->num_frames > 1 ) ? spr->frames[spr->curr_frame] : spr->imgData  ;


      uint32_t spriteHeight = spr->height;
      uint32_t spriteWidth  = spr->width;
      uint32_t x = spr->x;
      uint32_t y = spr->y;
    for (uint32_t i = 0; i < spriteHeight; i++)
        {
        for (uint32_t j = 0; j < spriteWidth; j++) {
            uint16_t color = *data++;
            if (color != 0)
            {
                                 *(__IO uint16_t*) (fb + (2*((i+y)*BSP_LCD_GetXSize() + j + x))) = color;

            }
             }

        }
}

Todavía la velocidad de fotogramas no es aceptable

    
pregunta Ahmed Saleh

2 respuestas

2

BSP_LCD_GetXSize () puede ser movido trivialmente fuera del bucle, pero esto puede no ser algo que pueda hacer el compilador, ya que sabemos que su valor no cambiará.

¿Se pueden combinar el dibujo de fondo y el sprite, entonces son posibles varias optimizaciones? Por ejemplo, puede tener una matriz de bits Ysize en longitud, que se establece en 1 si un sprite ocupa esa línea, de lo contrario cero, lo mismo para el eje X, entonces si hay un eje sprite en alguna parte en el bit de esta línea es cero, solo puede usar el DMA para borrar toda la línea desde el fondo (o incluso todas las líneas hasta que encuentre un cero en las banderas de presencia del eje Y), si la línea tiene un bit de sprite es 1 y luego cocina el DMA desactivado para la línea hasta el primer sprite, y mientras el motor DMA está moviendo el fondo, realice el bucle de pintura del sprite para la línea apropiada, luego cocine el DMA para la siguiente línea de línea y así sucesivamente. Este enfoque en particular solo funciona de manera óptima con una pantalla asignada en memoria.

Es útil mantener una lista ordenada de sprites, ya que hace que encontrar el que necesita para trabajar más rápido, también le permite imponer un pedido a los sprites para que ocurra algo razonable cuando se superponen dos sprites.

Mantener un anillo de búferes de control de DMA es muy útil, ya que significa que no es necesario que dejes de generar sprites mientras esperas a que se complete el núcleo de DMA.

El motor DMA es tu amigo, algunas veces es un poco difícil de usar, pero realmente lo quieres haciendo las cosas constantes en el fondo.

Realmente desea pintar en un búfer de cuadros en memoria, luego DMA lo hace en la pantalla durante el "VBI" para evitar que se rasgue, no siempre es posible porque no siempre tiene suficiente ram, pero es bueno cuando puede quítalo.

Puede haber algunas cosas útiles en los libros "Gráficos de gemas", probablemente el volumen uno o dos, son la biblia de las cosas en 2D basadas en la CPU.

    
respondido por el Dan Mills
0

Primero, reemplace la llamada a LCD_DrawPixel con una simple escritura en una variable global volátil. Si la velocidad mejora dramáticamente, entonces el problema está en LCD_DrawPixel en lugar de en su bucle.

Está mezclando enteros de 32 bits con signo (probablemente) (i, j) y enteros de 16 bits sin signo (x, y) en su código, lo que puede hacer que el compilador realice verificaciones o conversiones innecesarias. El tipo de datos de hardware para un procesador Cortex-M es un número entero de 32 bits, por lo que recomendaría que todas de las variables utilizadas para los cálculos en su bucle interno (i, j, x, y) se declaren como uint32_t.

También deberías probar diferentes configuraciones de optimización para el compilador. Optimice este código para la velocidad en lugar del tamaño.

    
respondido por el Elliot Alderson

Lea otras preguntas en las etiquetas