         -         -        -      -   -   - - - - - -----Ŀ          
                      
     
        
               
                
               
           
                                    
                              
                                                     
                                         
                      
           ----- - - -  -   -    -      -         -          -       
                                                                            
                          |                      |                          
                   -  ---  -                  
                        issu e 2                        
              -   ---   -             
                           |                      |                          
                                                                            
                           Titulo: Efectos TrueColor
                              Autor: Wind/Network




                               EFECTOS TRUECOLOR


                                  Wind/Network

     Lo  Seguro  que  todos hemos visto alguna vez una demo con efectos en
HiColor  o  TrueColor,  no? Ah, que todos habeis hecho alguna demo o intro
con efectos asi? Pues mejor!!! De todas formas, quizas este articulo pueda
servir para aquel que ha hecho algo en TrueColor pero que esta pensando en
como optimizarlo.

     En  el  pasado  nmero  apareci un artculo explicando como realizar
sumas,  restas  y  medias  en  HiColor. Bien, lo que aqui escribo se puede
considerar  como  un  apendice  de  lo  all  expuesto,  pero  basta ya de
introduccin y veamos algo de coding!

  Carry Flag, te quiero!

     Al  mirar  en cualquier manual de programacin en ensamblador el tema
sobre  los  Flags  de  calculo  del  procesador  y  como  reaccionan a las
operaciones, normalmente suele poner algo como:

     "Carry  Flag: Este Flag contiene el resultado del Carry producido por
el ltimo bit usado en la operacin."

  En palabras llanas:

     0xf0  + 0x10 = 0x00 _PERO_ se activara el Flag de Carry para indicar
que el resultado debera haber sido 0x100.

     Supuestamente este Flag se debera usar para poder manejar nmeros de
multiprecisin  como  por  ejemplo  cantidades  enteros  de 128 bits en un
procesador  de  solo  (?)  64  bits,  pero  sus usos van mucho ms alla...
casualidades  de  la  vida  que  tambin  podamos usarlos para acelerar el
clculo de operaciones con pixeles de TrueColor.


                                SUMA EN TRUECOLOR

     Sumar  pixeles  en  TrueColor parece en principio muy facil. Solo hay
que  sumar  y si aparece algn valor mayor de 255, sobreescribirlo con 255
para que no se vea el (desgraciadamente) famoso efecto de 'paso de color'.
Una primera aproximacin sera:

  for(x=x0;x<x1;x++)
  for(i=0;i<3;i++){

      a=*p1++;
      b=*p2++;

      c=a+b

      if(c>255) c=255;

      *p3++=c;
  }

     Este programa funciona bien, pero puede haber problemas de velocidad:
supongamos  que  tenemos  dos efectos en 800x600 y queremos sumar ambos en
pantalla.  Quitando  el  espinoso tema de como haremos para poder calcular
800x600x2  pixeles a 70 fps, tenemos el escollo de sumar los pixeles... si
tenemos 800x600 pixeles para sumar y 3 componentes en cada uno de ellos...
son  600x600x3==1440000  posibles  saltos.  Estais  leyendo  bien, case un
millon  y  medio  de  posibles saltos. Quizas tengamos suerte y todos sean
no-tomados,  o  quizas  todos  sean  tomados  pero  lo  normal  es  que la
distribucin sea uniforme y ms bien aleatoria.

     Los  procesadores  modernos  incluyen  logica  para  la prediccin de
salto,  pero  si hay algo que son incapaces de hacer es de predecir saltos
con  distribucin casi aleatoria, que es el caso que tenemos aqui. Es ms,
este  tipo  de saltos tienden a ENLENTECER al procesador, con lo cual algo
que  supuestamente  debera  acelerar  se  vuelve  contra  nosotros.  Para
solucionarlo,  podemos  ayudarnos  de  algo  que  siempre  han  tenido los
procesadores, siempre til y eficiente... el Flag de Carry.


                          COMO SIMULAR SALTOS CON SBB

     Sabemos  que  el  Flag  de Carry se pone a uno cuando nos pasamos del
valor  ms  alto  de una suma, como sera por ejemplo 0xf0 + 0x11. Aqui el
procesador  nos  esta  avisando  precisamente de que se est cumpliendo la
condicin   que   en   el   anterior   source   de   ejemplo   comprobamos
explicitamente. Nos interesa en nuestro caso conseguir poner un registro a
255  si y slo si el Flag de Carry est encendido y para eso se puede usar
una pequea pero potente instruccin: SBB.

  SBB  es  el  mnemonico  asociado  a  'SuBstract  with Borrow', que se
  traduce como 'Resta con Acarreo'. Basicamente ejecuta esto:

  SBB dst,src --> if(CarryFlag) then dst=dst-src-1 else dst=dst-src

  Todo muy bien, no?  Ahora supongamos que hacemos dst igual a src:

  SBB src,src --> if(CarryFlag) then src=src-src-1 else src=src-src

     Pero  ahora  debemos  reflexionar  un  poco...  las  partes que dices
'src-src' se pueden sustituir por cero, quedando:

  SBB src,src --> if(CarryFlag) then src=0-1 else src=0

     Ahora  bien,  al  trabajar  en  binario,  0-1  ==  -1  ==  0xff  que,
casualmente,  es el valor que estabamos buscando. Ntese tambin que si el
Carry Flag era cero, entonces src == 0 == 0x00.

  Examinemos ahora este source mejorado:

  for(x=x0;x<x1;x++)
  for(i=0;i<3;i++){

      a=*p1++;
      b=*p2++;

      c=a+b;

      sbb d,d; // suponiendo que esto existiera en C, claro.

      c=c|d;

      *p3++=v;
  }

  Veamos que ocurre aqui...

     *  Si  c>255, se nos activa el CarryFlag, con lo cual en la siguiente
linea  d  se  hace  0xff  y  posteriormente  al hacer un OR entre un valor
cualquiera y 0xff, c pasa a valer 0xff.

     *  Si  0<=c<=255, _no_ se activa el CarryFlag, asi que d pasa a valer
cero y al calcular el OR no se cambia el valor de c.

     Claramente,  hemos  obtenido  el  mismo  valor de resultado que en el
programa  anterior  pero  esta  vez  sin  usar ningun salto, lo cual puede
acelerar muchiiiiisimo el cdigo.

  Esta tcnica no solo se puede aplicar aqui.  Veamos otro ejemplo:

  for(x=x0;x<x1;x++){

    a=*p1++;
    b=*p2++;
    c=*p3++;

    d=a-b;

    sbb d,d;

    a=a+(c&d);

    *p4++=a;
  }

  (Si, ya s que el ejemplo es un poco raro...  ;)

  Veamos los dos posibles casos...

  * a>=b: a-b>=0 -> d>0 -> d=0    -> a=a+(c&0x00)=a+0=a -> *p4++=a
  * a<b:  a-b< 0 -> d<0 -> d=0xff -> a=a+(c&0xff)=a+c   -> *p4++=a+c

  Vemos que estamos obteniendo un resultado equivalente a:

  for(x=x0;x<x1;x++){

    a=*p1++;
    b=*p2++;
    c=*p3++;

    if(a<b) then a=a+c;

    *p4++=a;
  }

     Cuando   debemos   optar   por  este  mtodo?  Depende  mucho  de  la
arquitectura  del  procesador  usado, aunque normalmente si lo usamos para
condiciones que incluyan dos o tres instrucciones simples, ser ms rpido
que  el  cdigo convencional. Existen procesadores (me parece recordar que
eran  los  usados por ACORN) que van ms alla y permiten usar determinados
Flags  para  encender  o  apagar  las operaciones de guardar resultados en
registros..  esto  permite  basicamente  encender/apagar el Flag segn una
condicin  y  simplemente  poner  el  cdigo  del  'if' seguidamente, para
terminar  apagando el Flag cuando se haya salido de la condicin. Desde el
punto   de  vista  de  diseo  de  procesador,  esa  idea  es  francamente
_ADMIRABLE_ ya que evita todo tipo de problemas con los saltos en pequeos
'if'   adems   de   librar  al  programador  de  la  tarea  de  hacer  el
enmascaramiento de resultados a mano.


                            POSIBLES OPTIMIZACIONES

     En  el  ejemplo  anterior de suma de pixeles optimizada, calculabamos
cada componente por separado. Si estamos trabajando en un procesador de 32
bits, eso significa desperdiciar el 75% del clculo porque slo trabajamos
con  8 bits cada vez (a no ser que los calculos de los efectos los hagamos
en TrueColor de 32bits por componente, claro). Sera posible usar SBB para
generar  varias  mascaras  a  la  vez?  No, pero si podemos aprovechar que
conocemos  la  tcnica bsica para crear nuestro propio SBB de 32 bits que
calcule a la vez todas las componentes de un pixel.

     Esa  misma tcnica es modificable para acelerar el clculo tambin en
12,  15  o  16  bits,  pudiendose  entonces  calcular  hasta  2 pixeles en
paralelo.  Claramente,  el cdigo sera un poco ms complejo, pero si duda
ms  rpido  porque  pasariamos  de calcular 1/3 de pixel cada vez (con su
correspondiente  salto!)  a  calcular  2 pixeles en no mucho ms del mismo
tiempo de procesador.

  Bien, esto es todo por hoy... hasta la proxima!
