Compartir a través de


Copia y acceso a datos de recursos

Las marcas de uso indican cómo la aplicación pretende usar los datos de recursos para colocar los recursos en el área de memoria más eficaz posible. Los datos de recursos se copian entre recursos para que la CPU o la GPU puedan acceder a ellos sin afectar al rendimiento.

No es necesario pensar en los recursos que se crean en la memoria de vídeo o en la memoria del sistema, o para decidir si el tiempo de ejecución debe administrar la memoria. Con la arquitectura del WDDM (modelo de controlador para pantalla de Windows), las aplicaciones crean recursos de Direct3D con diferentes marcas de uso para indicar cómo la aplicación pretende usar los datos de recursos. Este modelo de controlador virtualiza la memoria usada por los recursos; es responsabilidad del sistema operativo, controlador o administrador de memoria colocar recursos en el área de memoria más eficaz posible, dado el uso esperado.

El caso predeterminado es que los recursos estén disponibles para la GPU. Hay ocasiones en las que los datos de recursos deben estar disponibles para la CPU. Copiar datos de recursos para que el procesador adecuado pueda acceder a ellos sin afectar al rendimiento requiere cierto conocimiento de cómo funcionan los métodos de API.

Copia de datos de recursos

Los recursos se crean en memoria cuando Direct3D ejecuta una llamada Create. Se pueden crear en memoria de vídeo, memoria del sistema o cualquier otro tipo de memoria. Dado que el modelo de controlador WDDM virtualiza esta memoria, las aplicaciones ya no necesitan realizar un seguimiento del tipo de recursos de memoria en los que se crean.

Lo ideal es que todos los recursos se encuentren en la memoria de vídeo para que la GPU pueda tener acceso inmediato a ellos. Sin embargo, a veces es necesario que la CPU lea los datos del recurso o que la GPU acceda a los datos de recursos a los que la CPU ha escrito. Direct3D controla estos diferentes escenarios solicitando que la aplicación especifique un uso y, a continuación, ofrece varios métodos para copiar datos de recursos cuando sea necesario.

Dependiendo de cómo se creó el recurso, no siempre es posible acceder directamente a los datos subyacentes. Esto puede significar que los datos del recurso deben copiarse del recurso de origen a otro recurso al que pueda acceder el procesador adecuado. En términos de Direct3D, la GPU puede acceder a los recursos predeterminados directamente, la CPU puede acceder directamente a los recursos dinámicos y de ensayo.

Una vez creado un recurso, no se puede cambiar su uso. En su lugar, copie el contenido de un recurso en otro recurso que se creó con un uso diferente. Los datos de recursos se copian de un recurso a otro o se copian datos de la memoria en un recurso.

Hay dos tipos principales de recursos: asignables y no asignables. Los recursos creados con usos dinámicos o de ensayo se pueden asignar, mientras que los recursos creados con usos predeterminados o inmutables no se pueden asignar.

Copiar datos entre recursos no asignables es muy rápido porque este es el caso más común y se ha optimizado para funcionar bien. Dado que la CPU no puede acceder directamente a estos recursos, están optimizados para que la GPU pueda manipularlos rápidamente.

La copia de datos entre recursos asignables es más problemática porque el rendimiento dependerá del uso con el que se creó el recurso. Por ejemplo, la GPU puede leer un recurso dinámico de forma bastante rápida, pero no puede escribir en ellos, y la GPU no puede leer ni escribir en recursos de almacenamiento provisional directamente.

Las aplicaciones que desean copiar datos de un recurso con uso predeterminado en un recurso con uso provisional (para permitir que la CPU lea los datos, es decir, el problema de devolución de gpu) deben hacerlo con cuidado. Consulte Acceso a los datos de recursos, a continuación.

Acceso a datos de recursos

El acceso a un recurso requiere la asignación del recurso; la asignación básicamente significa que la aplicación está intentando conceder acceso a la CPU a la memoria. El proceso de asignación de un recurso para que la CPU pueda tener acceso a la memoria subyacente puede provocar algunos cuellos de botella de rendimiento y, por este motivo, se debe tener cuidado sobre cómo y cuándo realizar esta tarea.

El rendimiento puede detenerse si la aplicación intenta asignar un recurso en el momento incorrecto. Si la aplicación intenta obtener acceso a los resultados de una operación antes de que finalice esa operación, se producirá una parada de canalización.

La realización de una operación de mapa en el momento incorrecto podría provocar una caída grave en el rendimiento al forzar la GPU y la CPU a sincronizarse entre sí. Esta sincronización se producirá si la aplicación quiere acceder a un recurso antes de que la GPU termine de copiarla en un recurso al que la CPU pueda asignar.

Consideraciones sobre el rendimiento

Es mejor pensar en un equipo como una máquina que se ejecuta como una arquitectura paralela con dos tipos principales de procesadores: una o varias CPU y una o varias GPU. Como en cualquier arquitectura paralela, el mejor rendimiento se logra cuando cada procesador está programado con suficientes tareas para evitar que se vaya inactivo y cuando el trabajo de un procesador no esté esperando el trabajo de otro.

El peor escenario para el paralelismo de GPU/CPU es la necesidad de forzar a un procesador a esperar los resultados del trabajo realizado por otro. Direct3D quita este costo haciendo asincrónicos los métodos de copia; la copia no se ha ejecutado necesariamente en el momento en que el método devuelve.

La ventaja de esto es que la aplicación no paga el costo de rendimiento de copiar realmente los datos hasta que la CPU accede a los datos, que es cuando se llama a Map. Si se llama al método Map después de copiar los datos, no se produce ninguna pérdida de rendimiento. Por otro lado, si se llama al método Map antes de copiar los datos, se producirá una parada de canalización.

Las llamadas asincrónicas en Direct3D (que son la gran mayoría de los métodos y, especialmente, las llamadas de representación) se almacenan en lo que se denomina búfer de comandos. Este búfer es interno para el controlador de gráficos y se usa para procesar por lotes las llamadas al hardware subyacente para que el costoso cambio del modo de usuario al modo kernel en Microsoft Windows se produzca lo antes posible.

El búfer de comandos se vacía, lo que provoca un modificador de modo de usuario o kernel, en una de las cuatro situaciones, que son las siguientes.

  1. Se llama a present.
  2. Se llama a Flush.
  3. El búfer de comandos está lleno; su tamaño es dinámico y está controlado por el sistema operativo y el controlador gráfico.
  4. La CPU requiere acceso a los resultados de un comando que espera a ejecutarse en el búfer de comandos.

De las cuatro situaciones anteriores, el número cuatro es el más crítico para el rendimiento. Si la aplicación emite una llamada para copiar un recurso o subrecurso, esta llamada se pone en cola en el búfer de comandos.

Si la aplicación intenta asignar el recurso de almacenamiento provisional que era el destino de la llamada de copia antes de que se haya vaciado el búfer de comandos, se producirá una detención de canalización, ya que no solo es necesario ejecutar la llamada al método Copy, pero también deben ejecutarse todos los demás comandos almacenados en búfer de comandos. Esto hará que la GPU y la CPU se sincronicen porque la CPU esperará a acceder al recurso de almacenamiento provisional mientras la GPU está vacíando el búfer de comandos y, por último, rellenando el recurso que necesita la CPU. Una vez que la GPU finalice la copia, la CPU comenzará a acceder al recurso de almacenamiento provisional, pero durante este tiempo, la GPU estará inactiva.

Al hacerlo con frecuencia en tiempo de ejecución, se degradará gravemente el rendimiento. Por ese motivo, la asignación de recursos creados con el uso predeterminado debe realizarse con cuidado. La aplicación debe esperar lo suficiente para vaciar el búfer de comandos y, por tanto, hacer que todos esos comandos terminen de ejecutarse antes de intentar asignar el recurso de almacenamiento provisional correspondiente.

¿Cuánto tiempo debe esperar la aplicación? Al menos dos fotogramas porque esto permitirá que el paralelismo entre las CPU y la GPU se aprovechen al máximo. La forma en que funciona la GPU es que mientras la aplicación procesa el marco N mediante el envío de llamadas al búfer de comandos, la GPU está ocupada ejecutando las llamadas desde el marco anterior, N-1.

Por lo tanto, si una aplicación quiere asignar un recurso que se origina en la memoria de vídeo y copia un recurso en el marco N, esta llamada comenzará a ejecutarse en el marco N+1, cuando la aplicación envíe llamadas para el siguiente fotograma. La copia debe finalizar cuando la aplicación está procesando el marco N+2.

Frame Estado de GPU/CPU
N
  • Los problemas de CPU representan llamadas para el marco actual.
N+1
  • GPU que ejecuta llamadas enviadas desde la CPU durante el marco N.
  • Los problemas de CPU representan llamadas para el marco actual.
N+2
  • La GPU finalizó la ejecución de llamadas enviadas desde la CPU durante el fotograma N. Resultados listos.
  • GPU que ejecuta llamadas enviadas desde la CPU durante el marco N+1.
  • Los problemas de CPU representan llamadas para el marco actual.
N+3
  • La GPU finalizó la ejecución de llamadas enviadas desde la CPU durante el fotograma N+1. Resultados listos.
  • GPU que ejecuta llamadas enviadas desde la CPU durante el fotograma N+2.
  • Los problemas de CPU representan llamadas para el marco actual.
N+4 ...

 

Recursos