Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





FPS en bloques

Iniciado por DoVerMan_, 01 de Enero de 1970, 01:00:00 AM

« anterior - próximo »

DoVerMan_

                                Bien, el problema quiza no sea un problema, la cosa es q estoy intentando hacer un engine isometrico utilizando directdraw, y como tengo la intencion de implementar translucencia utilizando alpha blend, decidi hacerme mis propios blt, utilizando asm en linea bajo c++.
Me he currado un blt que me coloca unos 700 bloques de 64x32 a 30 fps utilizando colorkey y con una res 640x480x16. Pero la verdad me parece un rendimiento bastante pobre, ya que imagino un mapeado, con transparencia e iluminación, y creo que necesitare bastante mar rendimiento. He buscado información, pero casi todo me lleva a utilizar mmx, y eso lo haria incompatible con maquinas antiguas.
Utilizo el siguiente planteamiento:
- Triple buffer en vram
- Surface de trabajo en memoria principal
- Surface de graficos en memoria principal

* utilizando mi blt coloco los bloques del surface de graficos al de trabajo
* una vez concluido el frame, copio el surface de trabajo al backbufer con bltfast
* hago un flip.

¿Podria sacar mas rendimiento utilizando alguna otra tecnica, q no pase por colocar todos los surfaces en vram?

gracias de antemano.
                               

DoVerMan_

                                Se me olvidaba, todo lo anterior son resultados en un k6-2 450 con una ati rage 8m y 192dRam                                

Drácula

                                La verdad es que como tu dices el rendimiento es pobre, pero quizás sea porque la tarjeta no da para más. Piensa que le estás enviando TODO el buffer, eso son 640x480x2 bytes=614.400 bytes x 30 Frames=18.432.000 bytes por segundo. Y estos datos sólo son de copiar con el BltFast.

Prueba a hacer sólo BltFast y mira cual es la velocidad que te da. Esa será tu velocidad máxima. Entonces si sube mucho las FPS sabes que el problema está en la construcción del BackBuffer, pero...¡yo creo que no subirá mucho!

De todas formas, estaría bien que pusieras aquí la rutina de copiar un bloque con ColorKey, para que la veamos y te podamos dar ideas de optimización.
                               
ltimas mejoras en Merlín: Multitextura.Control y generación automática de LOD.Importa ASE y X. Frustum Clipping por BB.Render añadido de wireframe y del BB.Animaciones por interpolación.Animaciones de textura...
Actualmente:Octree y jerarquías

DoVerMan_

                                Esta bien Dracula, la rutina es la siguiente:
       //pitch source
   sPitch = m_lPitch;
       //pitch destino
   dPitch = lpDest->GetPitch();
       //Puntero origen
   sPtr = GetSurfacePtr();
       //Puntero destino
   dPtr = lpDest->GetSurfacePtr();

   sPtr += (rSrc.top * sPitch);
   dPtr += (lDestY * dPitch);

   __asm
   {
      pushad
      mov eax, rSrc.left
      shl eax,1
      add [sPtr], eax      //sPtr= sPtr + (rSrc.top * sPitch)+(rSrc.left * bytesPerPixel)
      mov eax, lDestX
      shl eax,1
      add [dPtr], eax      //dPtr= dPtr + (lDestY * dPitch)+(lDestX * bytesPerPixel)
      

      mov ebx, rSrc.bottom   //Alto = bottom - top
      sub ebx, rSrc.top      //ebx = Alto

      mov edx, rSrc.right
      sub edx, rSrc.left
      shl edx,1
      sub [sPitch], edx   //sPitch = sPitch - (ancho*bytesPerPixel)
      sub [dPitch], edx   //dPitch = dPitch - (ancho*bytesPerPixel)
                     //edx ancho
      mov edi,dPtr
      mov esi,sPtr
linea:
      mov ecx, edx      //ecx = edx = ancho en bytes
clearloop:

      cmp ecx, 4
      jb menor4

      mov eax,ds:[esi]
      or eax, eax
      jz next
      or ax,ax
      jnz axsi
      shr eax,16
      mov ds:[edi+2],ax
      jmp next
axsi:
      push ax
      shr eax, 16
      jnz losdos
      pop ax
      mov ds:[edi],ax
      jmp next
losdos:
      shl eax,16
      pop ax
      mov ds:[edi],eax
next:
      add esi,4
      add edi,4
      
      sub ecx,4

      jnz clearloop
      jmp finbucle

menor4:
      mov ax, ds:[esi]
      or ax,ax
      jz next2
      mov ds:[edi], ax
next2:
      add esi,2
      add edi,2

finbucle:
      add edi, dPitch
      add esi, sPitch

      dec ebx
      jnz linea
   
      popad
   }
-----------------------------------------
rSrc es el RECT origen una vez hecho el clip necesario
lDestX, lDestY son las coordenadas de destino
Esta es la rutina para 16 BPP, procesa 2 pixel al mismo tiempo. Tengo otra para 8 BPP que procesa 4 pixels, pero saca un rendimiento parecido (unos 900 bloques).
Creo que al implementar alpha blend en 16BPP el rendimiento caera bestialmente. En 8BPP tmb caera, pero en menor medida, ya que utilizando una LUT imagino que la rutina no se ralentizara mucho (eso espero).
He estado observando el Diablo y Diablo2 y estoy seguro de que ambos trabajan en 8BPP, pero no imagino como hacen para colocar tantisimos bloques graficos, con transparencia, translucencia e iluminacion dinamica, espero que podais orientarme un poco.                                

Juan Mellado

                                Hola DoVerMan_.

Hace tiempo que no trasteo con ASM, asi que perdonadme si digo una burrada, pero no creo que las cosas hayan cambiado mucho con el tiempo.

Creo que esa subrutina tiene que ser lenta porque haces muchas comprobaciones y tiene una gran cantidad de saltos y accesos a memoria. Algo obvio: piensa en la cantidad de ciclos que tarda en volcar un único pixel y multiplicalos por todos los pixels para entender lo que tarda en total.

¿Has probado el típico bucle para dibujar un sprite (16bpp):
...
LODSW
OR AX, AX   ;Si es 0 no se imprime (colorkey)
JZ next
STOSW
next:
...?

¿No debería ser esto más rápido?

Saludos

[ Este Mensaje fue editado por: Juan Mellado el 2002-05-07 11:53 ]                                

fiero

                                Si, como dice Juan Mellado, me parece que para hacer la comprobación de los pixels negros no merece la pena hacerlo de 2 en 2, demasiadas comprobaciones...

prueba sin nada a ver:

   

   __asm
   {
       mov eax, rSrc.left
       shl eax,1
       add [sPtr], eax
//sPtr= sPtr + (rSrc.top * sPitch)+(rSrc.left * bytesPerPixel)
       mov eax, lDestX
       shl eax,1
       add [dPtr], eax
//dPtr= dPtr + (lDestY * dPitch)+(lDestX * bytesPerPixel)

       mov ebx, rSrc.bottom
//Alto = bottom - top
       sub ebx, rSrc.top
//ebx = Alto

       mov eax, rSrc.right
       sub eax, rSrc.left
       mov edx, eax
       shl eax,1
       sub [sPitch], eax
//sPitch = sPitch - (ancho*bytesPerPixel)
       sub [dPitch], eax
//dPitch = dPitch - (ancho*bytesPerPixel)
       
//edx ancho
       mov edi,dPtr
       mov esi,sPtr
       mov ecx, edx
   linea:
       mov ax,word ptr[esi]
       or ax,ax
       jz next
       mov word ptr[edi],ax
   next:
       add esi,2
       add edi,2

       dec ecx
       jnz linea
       add edi,dPitch
       add esi,sPitch
       mov ecx, edx
//ecx = edx = ancho en pixels

       dec ebx
       jnz linea
   }



... y haciendo que siempre salte al mismo sitio, a "linea", puede que corra mas...

un saludo

[ Este Mensaje fue editado por: fiero el 2002-05-07 12:18 ]                                
www.videopanoramas.com Videopanoramas 3D player

Emotion

                                Coño, como has hecho para que el codigo aparezca como en los foros de FlipCode??

Un secreto asi vale MILLONES :sonriendo:

P.D. por que no haces en lugar de 'jmp xx' un 'jmp short xx'. Tal y como veo el codigo, los bloques de instruccion apenas se distancian unos bytes en codigo, con lo que al realizar un salto con rango corto no se emplean tantos ciclos en el calculo de ramificacion, no? al menos antes se hacian esas optimizaciones, ahora no se...

[ Este Mensaje fue editado por: Emotion el 2002-05-07 12:22 ]                                
G3: Get the Power!

Juan Mellado

                                [Fiero]
Una duda, como este post va de optimización: ¿es más rápido el mov ax,[]/mov[],ax/add edi, 2/add esi, 2 que el lodsw/stosw?

[Emotion]
Para lo del código como en flipcode busca un post "Pasteo de Código" en el tablón General.

Lo de los saltos short/far ¿nos los resuelve (o debiera) el ensamblador a menos que se especifique de forma explícita?

Saludos                                

Emotion

                                Por eso dije que no sabia, aunque mas que no saber, no estaba seguro... pero claro, estamos hablando de asm inline, no asm puro... al menos yo ahora mismo no se si VC++ te hace las optimizaciones el solo (me gustaria pensar que es asi) o has de decirle tu como hacer los saltos... :sonriendo:                                
G3: Get the Power!

fiero

                                [Juan Mellado]
en un 386 (las tablas de pentium no las tengo a mano):

lodsw --- 5 ciclos

mov ax,word ptr[esi] --- 2 ciclos
add esi,2 --- 2 ciclos

stosw --- 4 ciclos

mov word ptr[esi],ax --- 2 ciclos
add edi,2 --- 2 ciclos

A mi me parece que tanto monta, monta tanto. Incluso leí en un manual de Intel que con un pentium y posterior es más rápido hacer "dec ecx", "jnz etiqueta"  que un "loop etiqueta" como antiguamente, o sea, que estan optimizando las instrucciones sueltas y las que hacen varias cosas a la vez internamente ejecutan las instrucciones sencillas.

[Emotion]
Coño, no te pierdes una!! :riendo:

un saludo                                
www.videopanoramas.com Videopanoramas 3D player

Drácula

                                Doverman, no me has dado el ejemplo de los FPS que tienes al hacer un simple BltFast. Pruébalo y postealo.

                               
ltimas mejoras en Merlín: Multitextura.Control y generación automática de LOD.Importa ASE y X. Frustum Clipping por BB.Render añadido de wireframe y del BB.Animaciones por interpolación.Animaciones de textura...
Actualmente:Octree y jerarquías

DoVerMan_

                                [Juan Mellado][Emotion]:
He probado lo que me indicabais: colocar los pixels 1 a 1, pero es bastante mas lento que mi rutina 2 a 2 y creo q se porq:
1.- Al leer lees 2 pixels en vez de 1
2.- Si un pixel es 0, hay muchas probabilidades de que el siguiente tmb, por lo que comprobar dos pixels de golpe, en la mayoria d los casos es más rapido. Sin olvidar el formato de un tile isometrico, en los que prácticamente el 50% es transparente.
3.- Si despues de realizar los test, son validos los dos pixels, se colocan de una vez, con lo que puede aumentar el rendimiento.

Además, en casi toda la documentación que puedes encontrar sobre alpha blend en 16BPP, se menciona que una de las mejoras q se obtiene al utilizar mmx (entre otras muchas, por supuesto) son los registros de 64 bits, que te permiten leer y escribir en bloques de 4 pixels.

De todas formas sigo sin saber xq el rendimiento es tan pobre. Estoy realizando multiples pruebas, y obtengo mejoras sobre el rendimiento anterior, pero mejoras de 20 25 bloques +, lo cual no me soluciona nada.
Lo peor de todo es q estoy seguro de q se pude hacer mejor d otra forma.
Gracias por vuestra ayuda, y no dejeis de colocar cualquier otra idea o sugerencia q tengais.

[ Este Mensaje fue editado por: DoVerMan_ el 2002-05-07 14:04 ]                                

DoVerMan_

                                Dracula, ¿cuando dices lo de un BltFast simple, te refieres a q haga simplemente BltFast de la superficie de trabajo al BackBuffer y obtenga el rendimiento?                                

Juan Mellado

                                Pues lo siento. Tenía buena pinta. Pero si no va más rápido, no va más rápido y punto.

Otra posibilidad sería optimizar más el bucle usando código in-line para disminuir el número de saltos. Repites 2 veces seguidas el bucle más interno y ejecutas el bucle la mitad de veces. Se ahorra la mitad de dec/jnz. (Este esquema lo puedes repetir para más de 2 veces).

Otra posibilidad (por aquello del 50% vacio) es utilizar sprites RLE (creo que los llamaban así). En vez de tratar los sprites como bloques los tratas línea a línea y span a span guardando donde empieza cada span y la longitud de cada uno de ellos. Lees donde empiezan, la longitud y vuelcas todos los pixels de golpe (o los procesas o lo que quieras). Pero ten en cuenta en que el recorte ahora es distinto, puedes hacer el backbuffer más grande para evitarlo.

Lo del MMX: ¿no decías que no lo querías para mantener compatibilidad con máquinas antiguas?

Saludos

P.D. En todo caso espero no estar haciendote perder el tiempo con estas sugerencias.                                

Emotion

                                Para Juan Mellado,

Bueno, lo de desenrollar los bucles es buena idea, siempre y cuando no tengas que pasar por el bucle inicial mas de 10000 veces :sonriendo:

En cuanto a lo del RLE, debes tener cuidado, ya que en si mismo no es un sistema de codificacion, sino de compresion (RLE: Run-Length Encoded), y si lo que buscas es velocidad, no te la dara, de hecho la unica ventaja que tiene el RLE es que es un algoritmo de compresion lossless, aunque no comprime mucho, la verdad, aunque no se a que modelo de RLE te refieres, al menos yo conozco 2: el RLE4 y el RLE8 (que es el que se usa o, mejor dicho, usaba con los archivos graficos .PCX, al menos aquellos que iban comprimidos, si bien creo que el .BMP tambien lo podia usar)

Para Doverman_:

En cuanto a lo del MMX, a que tipo de maquinas te quieres acercar con el motor? si no utilizas MMX la 'mejor' maquina a la que te podrias acercar, creo que era un pentium 166 no? es decir, tu lo quieres compatibilizar con procesadores pentium de gama baja? bueno, evidentemente no es una mala manera de hacer las cosas, tendras una buena razon para ello, aunque creo que hoy dia el que tiene la maquina mas lenta o de mas baja gama tiene un pentium MMX, asi que creo que deberias pensarlo, ya que eso incluso haria que el codigo se ejecutara igual en un Intel que en un AMD, lo que si que no vale (o al menos eso tengo entendido) es utilizar instrucciones SIMD de 128bits (o sea, ni SSE ni SSE2), ya que tengo entendido que AMD tiene su propio juego de instrucciones.

De cualquier manera, creo que lo del MMX es una buena opcion... estas seguro de que quieres eliminarlo?

Un Saludo
                               
G3: Get the Power!






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.