Share via


Cambios de Direct3D 10

Esta sección solo se aplica a Windows 7 y versiones posteriores, y Windows Server 2008 R2 y versiones posteriores del sistema operativo Windows.

En las secciones siguientes se describe cómo Direct3D 11 ha cambiado de Direct3D 10.

Funciones de devolución de llamada del controlador para Kernel-Mode Services

Las funciones de devolución de llamada específicas del dispositivo que proporciona el tiempo de ejecución de la versión 11 de Direct3D en la estructura D3DDDI_DEVICECALLBACKS cuando el tiempo de ejecución llama a la función CreateDevice(D3D10) del controlador de pantalla del modo de usuario aísla el controlador de identificadores de kernel y las firmas de función del kernel. El tiempo de ejecución de Direct3D versión 11 cambia la semántica de devolución de llamada y, por lo tanto, la implementación de las funciones de devolución de llamada para admitir un modo de operación sin subprocesos, mientras que los entornos de ejecución anteriores de la versión de Direct3D no admitieron un modo de operación libre. Las reglas para la operación de modo de subproceso libre se aplican después de que el controlador indique que admite el modo de subproceso libre (D3D11DDICAPS_FREETHREADED); de lo contrario, se aplican las reglas con restricciones elevadas anteriores. Para obtener información sobre cómo el controlador indica la compatibilidad con el modo de subproceso libre, vea Subprocesos y listas de comandos. Las restricciones siguientes siguen existiendo para direct3D versión 11:

  • Solo un único subproceso puede funcionar con un HCONTEXT a la vez. Las funciones de devolución de llamada existentes que actualmente usan HCONTEXT son pfnPresentCb, pfnRenderCb, pfnEscapeCb, pfnDestroyContextCb, pfnWaitForSynchronizationObjectCb y pfnSignalSynchronizationObjectCb. Por lo tanto, si más de un subproceso llama a estas funciones de devolución de llamada y usan el mismo HCONTEXT, el controlador debe sincronizar las llamadas a las funciones de devolución de llamada. Satisfacer este requisito es bastante natural porque es probable que se llame a estas funciones de devolución de llamada solo desde el subproceso que manipula el contexto inmediato.

  • El controlador debe llamar a las siguientes funciones de devolución de llamada solo durante las llamadas a las siguientes funciones de controlador mediante los mismos subprocesos que llamaron a esas funciones de controlador:

  • La función de devolución de llamada pfnDeallocateCb merece una mención especial porque el controlador no es necesario para llamar a pfnDeallocateCb antes de que el controlador vuelva de su función DestroyResource(D3D10) para la mayoría de los tipos de recursos. Dado que DestroyResource(D3D10) es una función de subproceso libre, el controlador debe aplazar la destrucción del objeto hasta que el controlador pueda garantizar eficazmente que no permanezca ninguna referencia de contexto inmediata existente (es decir, el controlador debe llamar a pfnRenderCb antes de pfnDeallocateCb). Esta restricción se aplica incluso a los recursos compartidos o a cualquier otra función de devolución de llamada que use HRESOURCE para complementar el uso de HRESOURCE con pfnAllocateCb. Sin embargo, esta restricción no se aplica a las principales. Para obtener más información sobre las excepciones principales, vea Excepciones principales. Dado que algunas aplicaciones pueden requerir la apariencia de destrucción sincrónica, el controlador debe asegurarse de que llama a pfnDeallocateCb para los recursos compartidos destruidos anteriormente durante una llamada a su función Flush(D3D10). Un controlador también debe limpiar los objetos destruidos previamente (solo aquellos que no detenerseán la canalización) durante una llamada a su función Flush(D3D10); El controlador debe hacerlo para asegurarse de que el tiempo de ejecución llama a Flush(D3D10) como mecanismo oficial para limpiar objetos destruidos diferidos para esas pocas aplicaciones que podrían requerir este mecanismo. Para obtener más información sobre este mecanismo, vea Destrucción diferida y Vaciado(D3D10). El controlador también debe asegurarse de que los objetos para los que se aplaza la destrucción se destruyen completamente antes de que la función DestroyDevice(D3D10) del controlador devuelva durante la limpieza.

Dejar en desuso la capacidad de permitir la modificación de Free-Threaded DDIs

Para Direct3D versión 11, el concepto de nivel de API de un dispositivo de pantalla y un contexto inmediato siguen agrupados en el nivel DDI por el concepto heredado de un dispositivo de pantalla. Esta agrupación del dispositivo de pantalla y el contexto inmediato maximiza la compatibilidad con los DDIs de versión anterior (por ejemplo, la versión 10 DDI de Direct3D) y reduce la renovación de controladores al admitir varias versiones de LAS API a través de varias versiones de DDIs. Sin embargo, esta agrupación del dispositivo de pantalla y el contexto inmediato da como resultado una DDI más confusa porque los dominios de subproceso no son extremadamente explícitos. En su lugar, para comprender los requisitos de subproceso de varias interfaces y las funciones dentro de esas interfaces, los desarrolladores de controladores deben consultar la documentación.

Una característica principal de la API de Direct3D versión 11 es que permite que varios subprocesos entren en las funciones de creación y destrucción simultáneamente. Esta característica no es compatible con permitir que el controlador intercambie los punteros de tabla de funciones para crear y destruir, ya que se permite la semántica de DDI de Direct3D versión 10 para funciones especificadas en D3D10DDI_DEVICEFUNCS y D3D10_1DDI_DEVICEFUNCS permitidas. Por lo tanto, después de que el controlador devuelva los punteros de función para crea (CreateDevice(D3D10)), el controlador no debe intentar cambiar el comportamiento modificando estos punteros de función concretos cuando el controlador se ejecuta bajo la DDI de direct3D versión 11 y mientras el controlador admite subprocesos DDI. Esta restricción se aplica a todas las funciones de dispositivo que comienzan por pfnCreate, pfnOpen, pfnDestroy, pfnCalcPrivate y pfnCheck. Todas las demás funciones del dispositivo están fuertemente asociadas al contexto inmediato. Dado que un único subproceso manipula el contexto inmediato a la vez, está bien definido para seguir permitiendo que el controlador intercambie entradas de tabla de funciones de contexto inmediatas de intercambio en caliente.

pfnRenderCb frente a pfnPerformAmortizedProcessingCb

Las funciones de API de Direct3D versión 10 enlazaban la función de devolución de llamada de kernel pfnRenderCb del entorno de ejecución de Direct3D para realizar el procesamiento amortizado (es decir, en lugar de ejecutar determinadas operaciones para cada llamada de función de API, el controlador realizó operaciones amortizadas para cada tantas llamadas a funciones de API). Normalmente, la API usa esta oportunidad para recortar las marcas de agua altas y vaciar su cola de destrucción de objetos diferida, entre otras cosas.

Para permitir que las funciones de devolución de llamada del kernel sean lo más libres posible para el controlador, la API de Direct3D ya no usa pfnRenderCb cuando el controlador admite la DDI de direct3D versión 11. Por lo tanto, los controladores que admiten la DDI de la versión 11 de Direct3D deben llamar manualmente a la función de devolución de llamada del kernel pfnPerformAmortizedProcessingCb desde el mismo subproceso que escribió la función DDI del controlador después de que el controlador envíe un búfer de comandos en el contexto inmediato (o frecuencia similar). Dado que la operación debe recortar las marcas de agua altas, sería ventajoso hacerlo antes de que el controlador genere preámbulos de búfer de comandos al aprovechar las funciones de devolución de llamada DDI de actualización de estado.

Además, el controlador debe tener en cuenta el problema de amortización de la API e intentar equilibrar la frecuencia con la que usa la función de devolución de llamada del kernel pfnPerformAmortizedProcessingCb . En un extremo, el controlador puede provocar un procesamiento excesivo. Por ejemplo, si el controlador siempre llamó a pfnPerformAmortizedProcessingCb dos veces (back-to-back), posiblemente debido al uso de varios motores, sería más eficaz que el controlador llame a pfnPerformAmortizedProcessingCb solo una vez. En el otro extremo, es posible que el controlador no permita que la API de Direct3D realice ningún trabajo para un fotograma completo si el controlador nunca llamó a pfnPerformAmortizedProcessingCb, posiblemente debido a un diseño de representación de fotogramas alternado. El controlador no es necesario para llamar a pfnPerformAmortizedProcessingCb con más frecuencia de lo que lo haría naturalmente, ya que eso es sobrekill (por ejemplo, si el controlador no llamó a pfnPerformAmortizedProcessingCb en un período de 1 milisegundos, debe ser el momento de bombear la API). El controlador solo debe determinar cuál de las llamadas pfnRenderCb existentes debe ir acompañada de pfnPerformAmortizedProcessingCb y, naturalmente, cumplir la semántica de subprocesamiento de la operación.

En el caso de los controladores que admiten listas de comandos, esos controladores también deben llamar a pfnPerformAmortizedProcessingCb desde contextos diferidos siempre que esos controladores se agoten de espacio (una frecuencia similar a cada vaciado de contexto inmediato). El entorno de ejecución de Direct3D versión 11 espera, al menos, recortar sus marcas de agua altas durante esta operación. Dado que la semántica de subprocesos relacionada con pfnRenderCb se ha relajado para la versión 11 de Direct3D, los problemas de simultaneidad deben resolverse para permitir que Direct3D versión 11 siga enlazando pfnRenderCb, sin restricciones.

Nuevo código de error de DDI

El código de error D3DDDIERR_APPLICATIONERROR se crea para permitir que los controladores participen en la validación en la que la API de Direct3D versión 11 no lo hizo. Anteriormente, si el controlador devolvía el código de error E_INVALIDARG, provocaría que la API genere una excepción. La presencia de la capa de depuración provocaría la salida de depuración e indicaría que el controlador había devuelto un error interno. La salida de depuración sugeriría al desarrollador que el controlador tenía un error. Si el controlador devuelve D3DDDIERR_APPLICATIONERROR, la capa de depuración determina que la aplicación está en error, en su lugar.

Requerir de forma retroactiva Free-Threaded CalcPrivate DDIs

La versión 11 de Direct3D requiere funciones de controlador que comienzan con pfnCalcPrivate en las funciones DDI de direct3D versión 10 para liberar subprocesos. Este requisito retroactivo coincide con el comportamiento de la DDI de direct3D versión 11 para requerir siempre las funciones pfnCalcPrivate* y pfnCalcDeferredContextHandleSize que se liberen, incluso si el controlador indica que no admite subprocesos DDI. Para obtener más información sobre este requisito retroactivo, vea Requerir retroactivamente Free-Threaded CalcPrivate DDIs.

Destrucción diferida y vaciado D3D10

Dado que todas las funciones de destrucción ahora están libres de subprocesos, el tiempo de ejecución de Direct3D no puede vaciar un búfer de comandos durante la destrucción. Por lo tanto, las funciones de destrucción deben aplazar la destrucción real de un objeto hasta que el controlador pueda asegurarse de que el subproceso que manipula el contexto inmediato ya no depende de ese objeto para sobrevivir. Cada método de contexto inmediato discreto no puede utilizar de forma eficaz la sincronización para resolver este problema de destrucción; por lo tanto, el controlador debe usar la sincronización solo cuando vacía un búfer de comandos. El tiempo de ejecución de Direct3D también usa este mismo diseño cuando debe tratar problemas similares.

Debido a la ratificación de la destrucción diferida, el tiempo de ejecución de Direct3D defiende que las aplicaciones que no toleran soluciones alternativas de destrucción diferida en su lugar usan mecanismos explícitos. Por lo tanto, el controlador debe procesar su cola de destrucción diferida durante las llamadas a su función Flush(D3D10) (incluso si el búfer de comandos está vacío) para asegurarse de que estos mecanismos funcionen realmente.

Las aplicaciones que requieren una forma de destrucción sincrónica deben usar uno de los siguientes patrones, según el peso pesado que requieran una destrucción:

  • Una vez que la aplicación garantiza que todas las dependencias de ese objeto se libere (es decir, listas de comandos, vistas, software intermedio, etc.), la aplicación usa el siguiente patrón:

    Object::Release(); // Final release
    ImmediateContext::ClearState(); // Remove all ImmediateContext references as well.
    ImmediateContext::Flush(); // Destroy all objects as quickly as possible.
    
  • El siguiente patrón es una destrucción más pesada:

    Object::Release(); // Final release
    ImmediateContext::ClearState(); // Remove all ImmediateContext references as well.
    ImmediateContext::Flush();
    ImmediateContext::End( EventQuery );
    while( S_FALSE == ImmediateContext::GetData( EventQuery ) ) ;
    ImmediateContext::Flush(); // Destroy all objects, completely.
    

Excepciones principales

Las principales son los recursos que el tiempo de ejecución crea en llamadas a la función CreateResource(D3D11) del controlador. El tiempo de ejecución crea un elemento principal estableciendo el miembro pPrimaryDesc de la estructura D3D11DDIARG_CREATERESOURCE en un puntero válido en una estructura DXGI_DDI_PRIMARY_DESC . Las principales tienen las siguientes excepciones importantes en lo que respecta a los cambios anteriores de Direct3D 10 a Direct3D 11:

  • Las funciones CreateResource(D3D11) y DestroyResource(D3D10) del controlador para las principales no son subprocesos libres y comparten el dominio de subproceso de contexto inmediato. La simultaneidad todavía puede existir con funciones que comienzan por pfnCreate y pfnDestroy, que incluye CreateResource(D3D11) y DestroyResource(D3D10). Sin embargo, la simultaneidad no puede existir con CreateResource(D3D11) y DestroyResource(D3D10) para las principales. Por ejemplo, el controlador puede detectar que una llamada a su función CreateResource(D3D11) o DestroyResource(D3D10) es para una función principal y, por tanto, determinar que puede usar o tocar de forma segura la memoria de contexto inmediata mientras dure la llamada a la función.

  • El tiempo de ejecución de Direct3D no puede aplazar la destrucción principal y el controlador debe llamar a la función pfnDeallocateCb correctamente dentro de una llamada a la función DestroyResource(D3D10) del controlador.