2009-03-19 13 views
20

esta es una pregunta "difícil". No he encontrado nada interesante en la web.C++ Memory Management for Texture Streaming in Videogames

Estoy desarrollando un módulo de gestión de memoria para mi empresa. Desarrollamos juegos para consolas de nueva generación (Xbox 360, PS3 y PC ... ¡consideramos PC una consola!).

Necesitaremos en el futuro, para nuestros próximos juegos, manejar la transmisión de texturas para mundos de juegos grandes que no pueden cargarse todos en la memoria de la consola principal (por ahora no se trata de PC).

Vamos a transmitir en el principio mipmaps de alta resolución de texturas (que es aproximadamente el 70% del tamaño de los datos mundiales). Tal vez en el futuro tengamos que transmitir también geometría, mipmaps más pequeños, audio, etc.

Estoy desarrollando un Administrador de memoria para ese tema, enfocado en X360 (porque a través de PS3 podemos usar la memoria del host y el asociado , autodefragmentando el asignador GMM).

El problema que estoy enfrentando es el siguiente: hemos decidido reservar un área de memoria específica para la transmisión de textura (por ejemplo, 64 megabytes) y queremos manejar todas las asignaciones y desasignaciones en esa área. Hemos asignado el área al principio de la aplicación y el área está Físicamente garantizada que es contigua (no solo virtualmente, porque necesitamos almacenar texturas allí).

Implementé un asignador de desfragmentación automático, usando identificadores en lugar de punteros. El tiempo no es un problema, el problema es la fragmentación de la memoria. En el juego, continuamente cargamos y descargamos los objetivos de transmisión, por lo que nos gustaría utilizar la cantidad máxima de nuestro búfer (64 megabytes).

Con este asignador podemos usar todo el espacio asignado pero la rutina de desfragmentación funciona en un tiempo inaccesible (a veces 60 milisegundos, ¡más que un fotograma!) Mientras que el algoritmo no está tan mal ... simplemente son demasiado mengosos ¡memcpy incurable!

Estoy buscando una solución para resolver este problema. Me gustaría encontrar al menos un buen artículo, una autopsia o alguien que haya tenido el mismo problema.

Ahora estoy eligiendo entre dos estrategias: 1) mover la rutina de desfragmentación en un subproceso dedicado (bueno para X360 con 6 subprocesos de hw, malo para PS3 con solo un subproceso de hw ... y no me digas para usar SPU's) con todos los problemas de multihilo de regiones de bloqueo, de acceso a una región que se está moviendo, ... 2) encontrar una solución "incremental" al problema de desfragmentación: podemos dar a cada marco un presupuesto de tiempo (por ejemplo, hasta a 1 milisegundo) para la desfragmentación y el Administrador de memoria hará lo que puede hacer en el presupuesto de cada cuadro.

¿Puede alguien contarme su experiencia?

Respuesta

14

He estudiado mucho recientemente sobre gestión de memoria y este es el artículo más informativo y útil que encontré en la red.

http://www.ibm.com/developerworks/linux/library/l-memory/

Sobre la base de ese papel lo mejor y más rápido resultado que se obtiene es dividir sus 64 MB en trozos de igual tamaño. El tamaño de los trozos dependerá del tamaño de tu objeto. Y asigne o desasigne un fragmento completo a la vez. Es

  1. Más rápido que la recolección de basura incremental.
  2. Más simple.
  3. Y resuelve ese problema de "demasiada fragmentación" en cierta medida.

Léelo, encontrará información excelente sobre cada solución posible y los méritos y deméritos de cada uno.

+1

Como programador de juegos Secundo esta idea, estamos texturas suerte Game tienen buenos tamaños, por defecto por lo que debería funcionar bien, pero también puede que quiera usar un cubo par tamaños en lugar de un solo cubo. Ahora, otra optimización a considerar es crear un algoritmo que coloque las texturas que se utilizarán en el mismo paso de renderización una al lado de la otra, pero no hará una diferencia increíblemente grande, tal vez simplemente recordar y optimizar si realmente lo necesita, depender de la juego y renderizado. –

+0

excelente enlace, ¡excelente respuesta! ¡Muchas gracias! – ugasoft

+0

este es uno de los mejores enlaces que he encontrado hasta ahora. Muchas gracias. – pigiuz

2

Dado que utiliza asas, tiene mucha libertad para mover la memoria. Creo que usar un hilo separado probablemente no sea el mejor (el más seguro o el más rápido), supongo que sería mejor usar un tipo de asignador de copiado incremental, donde en cada malloc() o free() compactas (copia hacia adelante o hacia atrás en la memoria) un número determinado de bloques asignados, con el número de bytes que copia, agotando un "presupuesto" que se restablece periódicamente a su valor inicial (por ejemplo, en cada actualización de pantalla). (Por supuesto, solo se copian bloques enteros)

La idea es que copiar un número determinado de bytes requiere una cantidad de tiempo bastante predecible, por lo que puede estimar cuántos bytes de copia puede realizar de manera segura por actualización de pantalla, y limítate a eso. Si hay suficiente tiempo en el presupuesto, una llamada a malloc() o free() desfragmentará completamente la memoria, de lo contrario desfragmentará tanto como sea posible en las limitaciones de tiempo dadas.

Hay algunas preguntas que estoy dejando sin resolver aquí - p. Ej. exactamente cómo compactar la memoria. Un asignador de copiado no incremental estándar puede comenzar a asignar desde el frente, luego copiar todo en la parte posterior (liberar memoria en la parte frontal) cuando se agota la memoria, pero no tiene esa libertad aquí. Es posible que necesite algunas heurísticas para decidir si mover bloques hacia adelante o hacia atrás. Lo importante es evitar oscilaciones (el mismo bloque se mueve hacia adelante y hacia atrás en llamadas sucesivas a malloc() o free()).

1

Recomendaría un enfoque incremental. Cada cuadro encuentra un bloque contiguo de memoria inusa que tiene espacio libre en ambos lados y lo mueve en la dirección que le permita encajar. o puedes mover todos los bloques en una sola dirección, encontrar un hueco y un bloque inuse que sea el más adecuado para él y moverlo. En el 360, probablemente deberías usar un hilo para hacer el movimiento, mientras que en el PS3 sería mejor usar la GPU para mover los datos por ti.

5

Por qué no usar múltiples áreas de memoria para las texturas escuchados y piscina de tamaño de la textura?

Insomniac tiene un artículo sobre su implementación textura streaming en PS3. Supongo que podría ser útil: link.

Para las estrategias de asignación general para minimizar la fragmentación, tal vez Doug Lea puede ayudar.

Pero a partir de la lectura de su pregunta, que suena como que está pensando demasiado y le recomiendo un enfoque combinado. (También ejecutar un pase de defragmentación en la memoria combinada de escritura no suena particularmente seguro o divertido.)

2

Tenemos casi exactamente el sistema que describió, excepto que asignamos en ranuras de tamaño fijo - 256x256, 512x512, 1024x1024 y Textura 2048x2048, en dos formatos cada uno (DXT1 y DXT5), precisamente para evitar la administración de la memoria.

+0

¿No tienes texturas rectangulares? también tenemos 512x1024, 256x512 y 256x1024 (pero evitamos 2048 texturas). Esto conducirá a una gran cantidad de "tamaños fijos" ... – ugasoft