2010-11-25 13 views
8

Me di cuenta en una aplicación MFC que estoy desarrollando que al arrastrar la barra de desplazamiento para deslizar hacia abajo el documento, la velocidad de fotogramas cae a niveles picos cuando hay un bloque que contiene aproximadamente un párrafo de texto pantalla, pero suave como la seda cuando está fuera de pantalla. Investigando el rendimiento, encontré la llamada única CDC::DrawText para el párrafo de texto responsable. Esto se encuentra en una compilación de versión optimizada.Rendimiento bajo con DrawText en Win7 x64

que utilizan QueryPerformanceCounter para obtener una medición de alta resolución de simplemente la llamada DrawText, así:

QueryPerformanceCounter(...); 
pDC->DrawText(some_cstring, some_crect, DT_WORDBREAK); 
QueryPerformanceCounter(...); 

El texto es de relleno estilo Unicode, lorem-ipsum, 865 caracteres de longitud y se envuelve sobre 7 líneas de un bit dado el rectángulo y la fuente (interfaz de usuario de Segoe, lfHeight = -12, un tamaño de texto de cuerpo estándar). A partir de mis mediciones, esa llamada sola toma un promedio de 7,5 ms, con un pico impar de 21 ms. (Nota para mantenerse al día con un monitor de 60 Hz se obtiene aproximadamente 16 ms para representar cada actualización.)

Traté de hacer algunos cambios para mejorar el rendimiento:

  • Extracción de la DT_WORDBREAK mejora el rendimiento hasta alrededor de 1 ms (aproximadamente 7 veces más rápido), pero dado que solo una línea de texto está llegando a la pantalla, y había un poco más de 7 líneas con la palabra quebrada, esto parece sugerirme que el cuello de botella está en otra parte.
  • Estaba dibujando texto en modo transparente (SetBkMode(TRANSPARENT)). Así que probé el modo opaco con un relleno de fondo sólido. Sin mejora.
  • Pensé que el procesamiento de ClearType podría ser el culpable. Cambié la fuente lfQuality de CLEARTYPE_QUALITY a NONANTIALIASED_QUALITY. Parecía una porquería con bordes filosos y todo, y ninguna mejora.
  • Según una sugerencia de comentario, estaba usando un CMemDC, pero me deshice de él e hice el dibujo directo. Parpadeó como loco y sin mejoría.

Esto se ejecuta en una computadora portátil con Windows 7 de 64 bits con un Intel Core 2 Duo P8400 a 2.26 GHz y 4 GB de RAM - No creo que cuente como un sistema lento.

Llamo a DrawText() cada vez que dibuja y esto obviamente reduce el rendimiento con una función tan lenta, especialmente si varios de esos bloques de texto son visibles a la vez. Es suficiente para que la experiencia sea lenta. Sin embargo, Firefox puede renderizar una página como esta en ClearType con mucho más texto, y parece funcionar muy bien. ¿Qué estoy haciendo mal? ¿Cómo puedo evitar el bajo rendimiento de una llamada real de DrawText?

+0

¿Qué sucede si cambia la aceleración de hardware? – Dialecticus

+0

Creo que la forma de usar el GDI de la vieja escuela (que supongo que es utilizado internamente por MFC) en Win7 simplemente no es bueno. Mi consejo es activar GDI + way. (http://msdn.microsoft.com/en-us/library/ms535991(v=VS.85).aspx). Podrías tratar de decirnos los resultados. – Keynslug

+0

¿Has visto esto? http://blog.m-ri.de/index.php/2009/02/15/slow-drawtext-performance-in-vista-and-windows-7-please-comment/ –

Respuesta

6

Dibujar el texto en cada actualización es un desperdicio. Utilice doble buffering, es decir, dibuje en un mapa de bits fuera de pantalla y simplemente blitelo a la pantalla. Luego, para desplazarse, simplemente copie la mayor parte del mapa de bits hacia arriba o hacia abajo o hacia los lados según sea necesario, luego dibuje solo el área invalidada (antes de ajustar el resultado a la pantalla).

Si incluso eso resulta ser demasiado lento, mantenga también el texto dibujado en un mapa de bits fuera de la pantalla, y blit en lugar de dibujar.

Saludos & HTH.,

2

De acuerdo con this german blogpost, el problema tiene que ver con la compatibilidad con fuentes de idiomas asiáticos. Si habilita aquellos en XP, obtendrá el mismo golpe de perforación. En Vista/7, están habilitados por defecto y no puede desactivarlos.

EDITAR: Solo tal vez, usar una fuente diferente podría ayudar .. (uno que no contenga caracteres asiáticos).

+0

La publicación del blog parece referirse al uso del indicador DT_CALCRECT, que en realidad no representa ningún texto, estoy hablando de la representación. Para tu información, parece que 7 veces más rápido cuando uso el DT_CALCRECT, así que, como era de esperar, la renderización es mucho más lenta que el cálculo de la extensión. Además, ¡preferiría si pudiera mantener el mejor apoyo internacional posible! – AshleysBrain

+0

@AshelysBrain: Sí, el escenario es diferente. Pero puede probar fácilmente si la causa raíz es la misma. Si habilita estas dos casillas de verificación en su máquina XP y ejecuta su código de prueba, ¿qué hace con el rendimiento? –

2

Los usuarios no pueden leer texto en 7 líneas en 7 milisegundos, por lo que la llamada es lo suficientemente rápida.

La frecuencia de actualización de 60 Hz del monitor es completamente irrelevante. No es necesario que vuelva a procesar el mismo texto para cada fotograma. La tarjeta de video enviará felizmente los mismos píxeles a la pantalla nuevamente.

Creo que tienes otro problema.¿Te estás preguntando sobre el desplazamiento de texto? Por favor, pregunte sobre el problema que realmente tiene, en lugar de asumir DrawText es el culpable.

+0

En la pregunta, estoy hablando del rendimiento mientras arrastro la barra de desplazamiento, por lo que está continuamente volviendo a dibujar el texto, idealmente a la frecuencia de actualización, para mostrar suavemente el documento de desplazamiento. – AshleysBrain

+0

Ah, a la derecha. Tenía la sensación de que tenías un problema XY. Entonces, sí, 'DrawText' es de hecho lo suficientemente rápido. Pero no debería volver a enviar el texto solo porque ahora necesita unos pocos píxeles más abajo en la pantalla. Volver a utilizar el CMemDC (¡no modificado!) En un desplazamiento diferente, y agregar un CMemDC adicional para la parte visible recientemente debería ser el truco. Este comentario es un poco pequeño para cubrir todos los detalles. – MSalters

1

Para romper el texto en saltos de palabra, DrawText necesita repetidamente intentar obtener el ancho de un bloque de texto para ver si cabe, luego tomar el resto y volver a hacerlo. Tendrá que hacer esto en cada llamada. Si su texto no cambia, esto es una sobrecarga innecesaria. Como solución alternativa, puede medir el texto usted mismo e insertar saltos de línea temporales y eliminar el indicador DT_WORDBREAK.

0

¿ha considerado Direct2D/DirectWrite?

De todos modos, debería funcionar mejor si solo dibuja el texto una vez en su propia memoria y lo coloca sobre cualquier dc que desee que se pinte en cada iteración.

Cuestiones relacionadas