Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Esta seção se aplica somente ao Windows 7 e posterior e ao Windows Server 2008 R2 e versões posteriores do sistema operacional Windows.
As seções a seguir descrevem como o Direct3D 11 foi alterado do Direct3D 10.
Funções de callback de driver para serviços de Kernel-Mode
As funções de retorno de chamada específicas do dispositivo que o runtime do Direct3D versão 11 fornece na estrutura D3DDDI_DEVICECALLBACKS, quando o runtime chama a função CreateDevice(D3D10) do driver de exibição em modo de usuário, isolam o driver dos identificadores e assinaturas de funções do kernel. O runtime do Direct3D versão 11 altera a semântica de retorno de chamada e, portanto, a implementação das funções de retorno de chamada para dar suporte a um modo de operação com thread livre, enquanto os runtimes de versão anteriores do Direct3D não dão suporte a um modo de operação com thread livre. As regras para a operação de modo de thread livre se aplicam depois que o driver indica que ele dá suporte ao modo de thread livre (D3D11DDICAPS_FREETHREADED); caso contrário, as regras anteriores fortemente restritas se aplicam. Para obter informações sobre como o driver indica suporte para o modo de thread livre, consulte Threading e Listas de Comandos. As seguintes restrições ainda existem para o Direct3D versão 11:
Somente uma única thread pode trabalhar com um HCONTEXT por vez. As funções de retorno de chamada existentes que atualmente usam um HCONTEXT são pfnPresentCb, pfnRenderCb, pfnEscapeCb, pfnDestroyContextCb, pfnWaitForSynchronizationObjectCb e pfnSignalSynchronizationObjectCb. Portanto, se mais de um thread chamar essas funções de retorno de chamada e usar o mesmo HCONTEXT, o driver deverá sincronizar as chamadas para as funções de retorno de chamada. Atender a esse requisito é bastante natural porque essas funções de retorno de chamada provavelmente serão chamadas apenas do thread que manipula o contexto imediato.
O driver deve chamar as seguintes funções de retorno de chamada somente durante chamadas para as seguintes funções de driver usando os mesmos threads que chamaram essas funções de driver:
pfnAllocateCb: o driver deve chamar pfnAllocateCb no thread que chamou a função CreateResource(D3D11) do driver quando recursos compartilhados são criados. As alocações não compartilhadas regulares com o dispositivo são totalmente sem thread.
pfnPresentCb: O driver deve chamar pfnPresentCb somente durante chamadas para a função PresentDXGI do driver.
pfnSetDisplayModeCb: o driver deve chamar pfnSetDisplayModeCb somente durante chamadas para a função SetDisplayModeDXGI do driver.
pfnRenderCb: O driver deve chamar pfnRenderCb no thread que chamou a função Flush(D3D10) do driver. Essa restrição é bastante natural devido às restrições de HCONTEXT.
A função callback pfnDeallocateCb merece uma menção especial porque o driver não precisa chamá-la antes de retornar de sua função DestroyResource(D3D10) para a maioria dos tipos de recursos. Como DestroyResource(D3D10) é uma função de multithreading, o driver deve adiar a destruição do objeto até que o driver possa garantir com eficiência que nenhuma referência de contexto imediato existente permaneça (ou seja, o driver deve chamar o pfnRenderCb antes do pfnDeallocateCb). Essa restrição se aplica até mesmo a recursos compartilhados, primárias compartilhadas ou a qualquer outra função de retorno de chamada que use HRESOURCE para complementar o uso de HRESOURCE com pfnAllocateCb. Essa restrição não se aplica às primárias. Para obter mais informações sobre exceções primárias, consulte Exceções Primárias. Como alguns aplicativos podem exigir a aparência de destruição síncrônica, o driver deve garantir que chame pfnDeallocateCb para recursos compartilhados anteriormente destruídos durante uma chamada para sua função Flush(D3D10). Um driver também deve limpar todos os objetos destruídos anteriormente (somente aqueles que não param o pipeline) durante uma chamada para sua função Flush(D3D10). o driver deve fazer isso para garantir que o runtime chame Flush(D3D10) como um mecanismo oficial para limpar objetos destruídos adiados para esses poucos aplicativos que podem exigir esse mecanismo. Para obter mais informações sobre esse mecanismo, consulte Deferred Destruction and Flush(D3D10). O driver também deve garantir que todos os objetos para os quais a destruição foi adiada sejam totalmente destruídos antes que a função DestroyDevice(D3D10) do driver retorne durante a limpeza.
Descontinuar a capacidade de modificar DDIs Free-Threaded
Para o Direct3D versão 11, o conceito de nível de API de um dispositivo de apresentação e de um contexto imediato continuam a ser combinados no nível DDI pelo conceito legado de um dispositivo de apresentação. Esse agrupamento de dispositivo de exibição e contexto imediato maximiza a compatibilidade com DDIs de versão anterior (como o Direct3D versão 10 DDI) e reduz a rotatividade do driver ao dar suporte a várias versões de APIs por meio de várias versões de DDIs. No entanto, esse agrupamento de dispositivo de tela e contexto imediato resulta em uma DDI mais confusa porque os domínios de execução não são extremamente explícitos. Em vez disso, para entender os requisitos de threading de várias interfaces e as funções dentro dessas interfaces, os desenvolvedores de drivers devem se referir à documentação.
Um recurso principal da API do Direct3D versão 11 é que ele permite que vários threads insiram criar e destruir funções simultaneamente. Esse recurso é incompatível com permitir que o driver altere os ponteiros da tabela de funções para criar e destruir, como permitia a semântica do DDI do Direct3D versão 10 para as funções especificadas em D3D10DDI_DEVICEFUNCS e D3D10_1DDI_DEVICEFUNCS. Portanto, depois que o driver devolve os ponteiros de função para criação (CreateDevice(D3D10)), o driver não deve tentar alterar o comportamento modificando esses ponteiros de função específicos quando o driver é executado sob a versão 11 do DDI do Direct3D e enquanto o driver suporta o threading do DDI. Essa restrição se aplica a todas as funções de dispositivo que começam com pfnCreate, pfnOpen, pfnDestroy, pfnCalcPrivate e pfnCheck. Todas as demais funções do dispositivo estão fortemente associadas ao contexto imediato. Como um único thread manipula o contexto imediato de cada vez, ele é bem definido para continuar permitindo que o driver troque as entradas da tabela de funções de contexto imediato.
pfnRenderCb versus pfnPerformAmortizedProcessingCb
As funções de API do Direct3D versão 10 se conectaram à função de retorno de chamada do kernel pfnRenderCb do Runtime Direct3D para realizar processamento amortizado (ou seja, em vez de executar determinadas operações a cada chamada de função de API, o driver realizou operações amortizadas a cada certo número de chamadas de função de API). A API normalmente usa essa oportunidade para ajustar limites superiores e liberar a fila de destruição de objetos adiada, entre outras atividades.
Para permitir que as funções de callback do kernel sejam o mais livres possíveis para o driver, a API Direct3D não usa mais pfnRenderCb quando o driver dá suporte à DDI do Direct3D versão 11. Portanto, os drivers que dão suporte à DDI do Direct3D versão 11 devem chamar manualmente a função de retorno de chamada do kernel pfnPerformAmortizedProcessingCb a partir da mesma thread que entrou na função DDI do driver, após o driver enviar um buffer de comando no contexto imediato (ou em uma frequência semelhante). Como a operação deve cortar marcas d'água altas, seria vantajoso fazer isso antes que o driver gere preâmbulos de buffer de comando ao aproveitar as funções de retorno de chamada DDI de atualização de estado.
Além disso, o driver deve ter ciência do problema de amortização da API e tentar equilibrar a frequência de uso da função de retorno de chamada do kernel pfnPerformAmortizedProcessingCb. Em um extremo, o driver pode causar processamento excessivo. Por exemplo, se o driver sempre chamou pfnPerformAmortizedProcessingCb duas vezes consecutivamente, possivelmente devido ao uso de múltiplos motores, seria mais eficiente para o driver chamar pfnPerformAmortizedProcessingCb apenas uma vez. No outro extremo, o driver pode não permitir que a API Direct3D realize qualquer processamento para um quadro inteiro se ele nunca tiver chamado pfnPerformAmortizedProcessingCb, possivelmente devido a um design de renderização por quadros alternados. Não é necessário que o driver chame pfnPerformAmortizedProcessingCb mais frequentemente do que naturalmente faria, pois isso é um exagero (por exemplo, se o driver não chamou pfnPerformAmortizedProcessingCb dentro de um intervalo de 1 milissegundo, deve ser hora de estimular a API). O driver precisa apenas determinar quais das chamadas pfnRenderCb existentes devem ser acompanhadas por pfnPerformAmortizedProcessingCb e, naturalmente, respeitar a semântica de execução simultânea da operação.
Para drivers que dão suporte a listas de comandos, esses drivers também devem chamar pfnPerformAmortizedProcessingCb de contextos adiados sempre que esses drivers ficam sem espaço (uma frequência semelhante à de cada liberação de contexto imediata). O tempo de execução do Direct3D versão 11 espera, pelo menos, reduzir suas marcas altas durante essa operação. Como a semântica de threading relacionada ao pfnRenderCb foi relaxada para o Direct3D versão 11, os problemas de simultaneidade devem ser resolvidos para permitir que o Direct3D versão 11 continue a conectar o pfnRenderCb, sem restrições.
Novo código de erro DDI
O código de erro D3DDDIERR_APPLICATIONERROR é criado para permitir que os drivers participem da validação em que a API do Direct3D versão 11 não participou. Anteriormente, se o driver retornasse o código de erro E_INVALIDARG, isso faria com que a API gerasse uma exceção. A presença da camada de debug causaria resultados de depuração, indicando que o driver retornou um erro interno. A saída de depuração sugeriria ao desenvolvedor que o driver tem um bug. Se o driver retornar D3DDDIERR_APPLICATIONERROR, a camada de depuração determinará que o problema está no aplicativo.
Exigir retroativamente DDIs CalcPrivate livres de threads
O Direct3D versão 11 requer retroativamente funções de driver que começam com pfnCalcPrivate nas funções DDI do Direct3D versão 10 para serem encadeadas gratuitamente. Esse requisito retroativo corresponde ao comportamento do DDI do Direct3D versão 11 para sempre exigir que as funções pfnCalcPrivate* e pfnCalcDeferredContextHandleSize sejam encadeadas gratuitamente, mesmo que o driver indique que não dá suporte ao threading DDI. Para obter mais informações sobre esse requisito retroativo, consulte Exigência retroativa de DDIs CalcPrivate Free-Threaded.
Destruição adiada e descarga D3D10
Como todas as funções de destruição agora estão em thread livre, o runtime do Direct3D não pode liberar um buffer de comando durante a destruição. Portanto, as funções de destruição devem adiar a destruição real de um objeto até que o driver possa garantir que o thread que manipula o contexto imediato não dependa mais desse objeto para sobreviver. Cada método discreto de contexto imediato não consegue usar a sincronização de forma eficiente para resolver o problema de destruição; portanto, o driver deve usar a sincronização somente quando descarrega um buffer de comando. O runtime do Direct3D também usa esse mesmo design quando deve lidar com problemas semelhantes.
Devido à confirmação da destruição diferida, o runtime do Direct3D defende que os aplicativos que não podem tolerar soluções alternativas para destruição diferida optem por mecanismos explícitos. Portanto, o driver deve processar sua fila de destruição adiada durante chamadas para sua função Flush (D3D10) (mesmo que o buffer de comando esteja vazio) para garantir que esses mecanismos realmente funcionem.
Esses aplicativos que exigem uma forma de destruição síncrona devem usar um dos seguintes padrões, dependendo de quão pesada é a destruição necessária:
Depois que o aplicativo garante que todas as dependências desse objeto sejam liberadas (ou seja, listas de comandos, exibições, middle ware e assim por diante), o aplicativo usa o seguinte padrão:
Object::Release(); // Final release ImmediateContext::ClearState(); // Remove all ImmediateContext references as well. ImmediateContext::Flush(); // Destroy all objects as quickly as possible.O seguinte padrão é uma destruição mais intensa:
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.
Exceções primárias
As primárias são recursos que o runtime cria em chamadas para a função CreateResource(D3D11) do driver. O runtime cria um primário definindo o membro pPrimaryDesc da estrutura D3D11DDIARG_CREATERESOURCE como um ponteiro válido para uma estrutura de DXGI_DDI_PRIMARY_DESC . As primárias compartilhadas seguem as regras para todos os recursos compartilhados. As primárias não compartilhadas têm as seguintes exceções notáveis em relação às alterações anteriores do Direct3D 10 para o Direct3D 11:
As funções CreateResource(D3D11) e DestroyResource(D3D10) do driver para os primários não são 'free-threaded' e compartilham o domínio de processamento de contexto imediato. A simultaneidade ainda pode existir com funções que começam com pfnCreate e pfnDestroy, que incluem CreateResource(D3D11) e DestroyResource(D3D10). No entanto, não é possível existir simultaneidade com CreateResource(D3D11) e DestroyResource(D3D10) para primários. Por exemplo, o driver pode detectar que uma chamada para sua função CreateResource(D3D11) ou DestroyResource(D3D10) é para um recurso primário e, assim, determinar que ele pode acessar a memória de contexto imediata com segurança durante a chamada da função.
A destruição primária não pode ser adiada pelo tempo de execução do Direct3D, e o driver deve chamar a função pfnDeallocateCb de forma adequada dentro de uma chamada para a função DestroyResource(D3D10) do driver.