Este artigo foi traduzido por máquina.

Windows com C++

Apresentando o Direct2D

Kenny Kerr

Esta coluna se baseia em uma versão de pré-lançamento do Windows 7. Detalhes estão sujeitos a alterações.

Conteúdo

Arquitetura E objetos
Fábricas E recursos
Processar destinos
Pincéis E comandos de desenho

Com a introdução do Windows Vista há alguns anos, era claro que a era do the Windows interface gráfica de dispositivo (GDI) foi vindo para um fim. GDI, mesmo com a ajuda do GDI +, tinha sido mostrando sua idade especialmente quando comparado a recursos gráficos superiores do Windows Presentation Foundation (WPF). Como se que não foram suficientes, GDI perdeu seu aceleração de hardware enquanto WPF aproveitou abundância do Direct3D de aceleração de hardware.

No entanto, se você quiser desenvolver aplicativos comerciais de alto desempenho e alta qualidade, você ainda verá C++ e código nativo para oferecer esse poder. É por isso que excitar algumas coisas que me mais sobre o Windows 7 que a introdução do Direct2D e DirectWrite. Direct2D é um totalmente novo gráficos 2D API projetado para dar suporte os aplicativos da área de trabalho mais exigentes e visualmente sofisticados com o melhor desempenho possível. DirectWrite também é uma nova API que complementa Direct2D e fornece texto acelerada por hardware, quando usado com Direct2D e layout de texto de alta qualidade e processamento com suporte avançado para as fontes OpenType tipografia e processamento de texto ClearType.

Neste artigo, VOU explorar essas novas tecnologias e dar uma idéia de por que ele é importante e como você pode iniciar a usá-los hoje.

Arquitetura E objetos

No Windows XP, GDI e Direct3D tinham standing igual que diz respeito o sistema operacional foi. As partes do modo de usuário do GDI e Direct3D interfaced diretamente com suas contrapartes de modo kernel. Como resultado, ambos podem ser diretamente hardware acelerado, determinado drivers de vídeo adequado. Com o Windows Vista, Microsoft delegado a responsabilidade de controlar o hardware de vídeo exclusivamente para Direct3D. GDI, de repente, tornou-se os elementos gráficos API que tinha suporte predominantemente através de processamento baseados em software na parte superior do Direct3D herdados.

Portanto, GDI está inativo e Direct3D está no futuro, mas em que isso deixe nos e como faz isso todos relacionados ao Direct2D e WPF? Bem, a primeira coisa a observar é que o Direct3D é efetivamente a unidade de processamento de elementos gráficos do Windows (GPU) API, se você deseja processar elementos gráficos ou hotwire sua GPU para adicionado potência de computação. Ignorar OpenGL (que há ainda suporte), o Direct3D é o pipeline gráfica de nível mais baixo para controlar diretamente um adaptador de exibição de elementos gráficos de um aplicativo de modo de usuário.

O Direct3D é o que é conhecido como um gráfico de modo imediato API. Isso simplesmente significa que a API fornece uma camada fina sobre qualquer hardware de gráficos, fornecendo acesso a recursos de hardware ao preencher, em alguns dos espaços em branco, o hardware deve ser limitado de alguma maneira. Sempre que você deseja processar ou atualizar a exibição, você efetivamente precisará informar Direct3D que você está prestes a processar, fornecer o pipeline Direct3D com tudo que ele precisa para processar um quadro e, em seguida, informe-que terminar, e isso causará a exibição a ser atualizado. Embora o Direct3D forneça muitas funções 3D avançadas, é cabe a você para controlar todos eles diretamente e tem poucas primitivos 3D. Não é necessário dizer que isso não é uma tarefa trivial.

Anteriores ao Windows Vista, o Direct3D também incluído um nível mais alto mantidos-modo gráfico API que foi criado no topo da API imediata do modo. Essa API fornecido suporte direto para manipulação de objetos 3D, chamados cenas — uma hierarquia de quadros com objetos e luminosidade. Ele foi chamado modo retido como a API mantém uma cópia do gráfico inteiro cena, por assim dizer. Aplicativos simplesmente atualizar a cena, e a API automaticamente cuida de processamento e atualizar a exibição. O problema, naturalmente, é que tudo isso tem um custo; se o custo é muito alto ou as abstrações bastante não atender às suas necessidades, você ter que descartar esta técnica totalmente, contar com o modo imediato API diretamente e fornecem seus próprios algoritmos de geometria.

Se você estiver totalmente familiarizado com o WPF, em seguida, a descrição anterior de um gráfico mantidos-modo API deve parecer familiar bastante. Embora o Direct3D descontinuados sua API mantidos-modo, o WPF inclui seu próprio interno mantido-modo API, conhecido como MIL (camada de integração com o Media). MIL fica entre WPF e do Direct3D e mantém uma cópia do gráfico cena definido pelo WPF, permitindo que o código gerenciado interagir com objetos visuais enquanto permanece em segundo plano, coordenação com MIL para garantir que as alterações são refletidas no gráfico cena que ela mantém. Isso permite que o WPF proporcionar uma experiência muito sofisticada e interativa para os desenvolvedores, mas ele vem com um preço.

Tendo posto tudo isso, deve ser bastante óbvio aí que entra Direct2D. Direct2D fornece suporte de processamento sofisticados para geometrias simples e complexas, bitmaps e texto embutido diretamente no início da gráficos modo imediata do Direct3D API para desempenho inigualáveis. O resultado é uma abordagem de alto desempenho e baixa sobrecarga para produzir conteúdo de elementos gráficos de alta qualidade para seus aplicativos. Ele fornece uma API significativamente mais simples para produzir conteúdo 2D em comparação ao uso Direct3D diretamente ao adicionar pouca sobrecarga na maioria dos casos. Na verdade, com exceção de algumas operações específicas, como cada primitivo suavização de serrilhado, você poderia ser difícil pressionada para desempenho Direct2D com Direct3D. Direct2D também facilmente deve reduz os likes de MIL e Quartz2DE.

Como se que não foram suficientes, ele vai ainda mais e oferece muitos recursos adicionais, como processamento remoto sobre protocolo RDP (Remote Desktop), software fallback para processamento do lado do servidor ou para compensar a falta de hardware, suporte para processamento de texto ClearType e a interoperabilidade inigualáveis com GDI e Direct3D. Digamos apenas que não há nenhum deste bobagem "airspace" do WPF.

Agora vamos para baixo para escrever algum código! Para manter os exemplos concentra-se, vou usar a ATL (Active Template Library) e a biblioteca de modelos Windows (WTL) para tratar de todo o código de janelas clichê para mim. Lembre-se, Direct2D é sobre o processamento. Se você deseja que ele para processar a uma janela, você ainda precisará gerenciar essa janela. Se você quiser entrada do mouse, você ainda precisa responder a mensagens de janela como de costume. Você obtém a idéia. a Figura 1 contém um esqueleto de uma janela que eu irá preencher durante o restante deste artigo.

A Figura 1 esqueleto de janela

#define HR(_hr_expr) { hr = _hr_expr; if (FAILED(hr)) return hr; }
class Window : public CWindowImpl<Window, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW>>
{
public:
    BEGIN_MSG_MAP(Window)
        MSG_WM_DESTROY(OnDestroy)
    END_MSG_MAP()

    HRESULT Create()
    {
        VERIFY(__super::Create(0)); // top-level
        VERIFY(SetWindowText(L"Direct2D Sample"));

        VERIFY(SetWindowPos(0, // z-order
                            100, // x
                            100, // y
                            600, // pixel width,
                            400, // pixel height,
                            SWP_NOZORDER | SWP_SHOWWINDOW));

        VERIFY(UpdateWindow());
        return S_OK;
    }
private:
    void OnDestroy()
    {
        ::PostQuitMessage(1);
    }
};

Fábricas E recursos

Como ocorre com várias outras APIs como Direct3D e XmlLite, Direct2D usa uma versão simples da especificação de COM para gerenciar a vida útil de objeto através de interfaces derivada de IUnknown. Não há nenhuma necessidade de inicializar o tempo de COM execute e preocupar compartimentos ou proxies. É apenas uma convenção para simplificar o gerenciamento de recursos e permitem que APIs e aplicativos para expor e consumir objetos de maneira bem definida. Tenha em mente que só porque Direct2D usa interfaces COM não significa que você pode fornecer suas próprias implementações dessas interfaces. Salvo indicação em contrário, Direct2D funcionará somente com suas próprias implementações. Sugiro que você use CComPtr ponteiro inteligente classe do ATL para gerenciar os ponteiros de interface, como que faz nos exemplos deste artigo.

Cada aplicativo Direct2D começa criando um objeto de fábrica. A função D2D1CreateFactory retorna uma implementação da interface ID2D1Factory:

CComPtr<ID2D1Factory> factory;
HR(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory));

Obviamente, antes de pode usar qualquer um desses tipos, você precisa incluir d2d1.h, o arquivo de cabeçalho Direct2D, que declara diversas interfaces de Direct2D, estruturas e constantes bem como a função D2D1CreateFactory. O arquivo d2d1.lib é fornecido para importar a função D2D1CreateFactory. O arquivo de cabeçalho d2d1helper.h também fornece uma ótima muitas funções úteis e classes para simplesmente o uso de Direct2D do C++. Eu normalmente incluem Direct2D em um projeto adicionando as seguintes diretivas no cabeçalho pré-compilada do projeto:

#include <d2d1.h>
#include <d2d1helper.h>
#pragma comment(lib, "d2d1.lib")

Como mencionei, Direct2D não depende de COM, mas o primeiro parâmetro para D2D1CreateFactory pode levá-lo a acreditar caso contrário. A enumeração D2D1_FACTORY_TYPE define constantes D2D1_FACTORY_TYPE_SINGLE_THREADED e D2D1_FACTORY_TYPE_MULTI_THREADED, mas esses não têm nada a ver com compartimentos e não pense nenhuma afinidade de thread. A constante D2D1_FACTORY_TYPE_SINGLE_THREADED simplesmente Especifica que o objeto de fábrica, bem como qualquer e todos os objetos raiz em que fábrica, pode ser acessado por apenas um único segmento em uma hora. Objetos criados dessa maneira fornecerá o melhor desempenho para acesso de single-threaded, evitando qualquer serialização desnecessária dentro e fora das chamadas de processamento. A constante D2D1_FACTORY_TYPE_MULTI_THREADED, por outro lado, especifica que o objeto de fábrica, bem como qualquer e todos os objetos raiz em que fábrica, podem ser acessados por vários threads simultaneamente. Direct2D fornece a sincronização necessária com contagem de referência interligada. Isso é útil para processamento para destinos diferentes simultaneamente enquanto compartilham determinados recursos. Manter em se importa em que esse paralelismo é específico para a CPU e instruções enviadas para a GPU ainda podem ser serializado e, em última análise, parallelized independentemente.

OK, então, que é o objeto de fábrica usado? Bem, ele é responsável por criar todos os recursos de independente de dispositivo, predominantemente geometrias, bem como criar processar destinos que representa os dispositivos. O destino de processamento, em seguida, tem a responsabilidade de criação de recursos dependentes de dispositivo. A diferença entre recursos dependentes de dispositivo e independente de dispositivo é essencial para usando Direct2D corretamente. Um dos benefícios de um gráficos mantidos-modo API como o WPF é que a camada intermediária entre o hardware e o modelo de programação geralmente se encarrega de cenários nos quais o dispositivo de vídeo pode ser perdido. Isso pode acontecer por vários motivos. A resolução pode alterar no plano de fundo, um adaptador de vídeo pode ser removido como quando um usuário desencaixa um laptop, uma sessão de conexão de área de trabalho remota pode ser perdida, e assim por diante. Um gráfico imediata modo API como Direct2D precisa levar em conta esses eventos. Obviamente, a vantagem é que os recursos usados para processar a um dispositivo específico podem ser fisicamente presente no dispositivo e, portanto, fornecer muito melhor desempenho.

Por esses motivos, é recomendável para separar claramente a criação de recursos independentes de dispositivo dos recursos dependentes de dispositivo. Para acomodar isso, na Figura 2 adicionar que esses dois métodos para a janela de classe de Figura 1 .

A Figura 2 Criar independente de dispositivos e recursos dependentes de dispositivo separadamente

HRESULT CreateDeviceIndependentResources()
{
    HRESULT hr;
    HR(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_factory));
    // TODO: Create device-independent resources here
    return S_OK;
}
HRESULT CreateDeviceResources()
{
    HRESULT hr;
    // TODO: Create device resources here
    return S_OK;
}

Vai criá-los nas próximas seções algumas, mas por enquanto, você pode chamar CreateDeviceIndependentResources partir o método Create da classe Window porque recursos independentes de dispositivo precisam ser criados apenas uma vez. CreateDeviceResources será, no entanto, ser chamado por demanda para criar recursos do dispositivo, conforme necessário. Também convém adicionar a variável de membro de m_factory da seguinte maneira:

CComPtr<ID2D1Factory> m_factory;

Processar destinos

Um alvo processado é usado para representar um dispositivo e é dependente do dispositivo subjacente. Com um destino de processamento, você pode criar vários recursos, como pincéis e executar as operações de desenho reais. Direct2D oferece suporte a vários tipos diferentes de destinos de processamento. Se você estiver criando um aplicativo Direct2D do zero, você pode criar um alvo processado para processar conteúdo em uma janela (HWND). Você também pode criar um alvo processado para processar para um contexto para dispositivo GDI (DC) ou para uma superfície de infra-estrutura de elementos gráficos do DirectX (DXGI) para uso em um aplicativo Direct3D. Você pode até mesmo criar um alvo de processamento de vários tipos de recursos de bitmap para processamento de fora da tela.

Vários métodos de fábrica são fornecidos para criar os diferentes tipos de destinos de processamento. Os métodos próprios são bem óbvios. Por exemplo, o método CreateHwndRenderTarget cria um alvo de processamento de janela, e o método CreateDxgiSurfaceRenderTarget cria um alvo de processamento de superfície DXGI. Para processar para a janela, você vai precisar atualizar o método de CreateDeviceResources para criar o destino de processamento de janela. No mínimo, ele pode parecer com a Figura 3 . Mantenha em mente que esse exemplo não é com reconhecimento de DPI, mas que é um tópico para outro artigo.

Figura 3 criar o destino de processamento de janela

HRESULT CreateDeviceResources()
{
    HRESULT hr;
    if (0 == m_target)
    {
        CRect rect;
        VERIFY(GetClientRect(&rect));
        D2D1_SIZE_U size = D2D1::SizeU(rect.Width(), rect.Height());
        HR(m_factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
                        D2D1::HwndRenderTargetProperties(m_hWnd, size), &m_target));
    }
    return S_OK;
}

Também convém adicionar a variável de membro m_target:

CComPtr<ID2D1HwndRenderTarget> m_target;

O método de CreateDeviceResources cria os recursos de dispositivo somente se o alvo processado ainda não tiver sido criado ou, como você verá em breve, se o dispositivo é perdido e o destino do processamento precisa ser recriado.

Primeiro parâmetro o método de CreateHwndRenderTarget, na verdade, é do tipo D2D1_RENDER_TARGET_PROPERTIES. Este parâmetro é comum a todas as processamento destino criação de funções. A função RenderTargetProperties é na verdade, uma função de auxiliar definida no arquivo de cabeçalho d2d1helper.h. Ele representa um padrão comum para inicializar as estruturas de dados usadas pelo Direct2D muitas e ajuda a simplificar drasticamente o seu código. A função de auxiliar RenderTargetProperties tem parâmetros com valores padrão para conta para a inicialização mais comuns da estrutura resultante. Você pode substituir esses valores para ajustar o formato de pixel e informações de PPP, bem como características adicionais de destino processamento, como se deseja forçar baseada em hardware ou software de processamento e suporte à interoperabilidade GDI.

Da mesma forma, o segundo parâmetro do CreateHwndRenderTarget é na verdade, uma estrutura de D2D1_HWND_RENDER_TARGET_PROPERTIES maiúsculas de minúsculas e fornece informações específicas para a janela.

Ter criado o alvo processado, agora pode fazer algum processamento real. Para fazer isso, adicione um método de processamento para a classe de janela com a estrutura básica mostrada na Figura 4 .

A Figura 4 processamento

void Render()
{
    if (SUCCEEDED(CreateDeviceResources()))
    {
        if (0 == (D2D1_WINDOW_STATE_OCCLUDED & m_target->CheckWindowState()))
        {
            m_target->BeginDraw();
            m_target->SetTransform(D2D1::Matrix3x2F::Identity());
            m_target->Clear(D2D1::ColorF(D2D1::ColorF::Red));
            // TODO: add drawing code here

            if (D2DERR_RECREATE_TARGET == m_target->EndDraw())
            {
                DiscardDeviceResources();
            }
        }
    }
}

A lógica aqui é muito importante porque possibilita atualizar muito eficiente, graças à reutilização de recursos do dispositivo e porque ele deve prever perda do dispositivo. O método de processamento inicia, chamando o método de CreateDeviceResources que acabei de descrever. Obviamente ele não terá que fazer nada se os recursos de dispositivo estão disponíveis ainda. Como uma otimização verificar o estado de janela para garantir que ele não é occluded, que é apenas um termo especial que indica a janela é obstruída do modo de exibição e qualquer pintura apenas seria uma perda de recursos de CPU e GPU preciosa. Embora isso raramente acontece quando o DWM (Gerenciador de janela da área de trabalho) está manipulando a composição de área de trabalho, ele não prejudicar e é uma otimização de BOM quando composição da área de trabalho está desabilitada.

Desenho real deve ser sandwiched entre as chamadas para métodos de BeginDraw e EndDraw o destino de processamento. Maioria dos métodos do destino processamento ter um tipo de retorno void. Desde que operações de desenho são loteadas, as falhas serão detectadas apenas quando as operações de desenho são liberadas e processadas para o dispositivo. O método de EndDraw, portanto, tem um tipo de retorno HRESULT. Ele usa a constante D2DERR_RECREATE_TARGET para indicar que o destino de processamento foi invalidado e deve ser recriado. Em seguida, ele chama DiscardDeviceResources, que devem liberar todos os recursos de dispositivo.

void DiscardDeviceResources()
{
    m_target.Release();
}

Também apenas DEVO mencionar as chamadas para o destino de processamento SetTransform e limpar métodos. Nesse caso SetTransform Especifica que quaisquer operações de desenho subseqüentes devem ser transformadas usando uma matriz de identidade. É claro, uma matriz de identidade não é realmente nenhuma conversão, para que isso apenas garante que operações de desenho usam o espaço de coordenadas literal em pixels independentes de dispositivo. No entanto, você pode chamar SetTransform repetidamente durante o processamento para alterar a transformação rapidamente. O método Clear simplesmente limpa a área de desenho para operações de desenho subseqüentes e nesse caso torna vermelho.

Obviamente, se você criar a janela neste momento, você deve observar que a janela permanece branca. Algo ainda precisa chamar o método de processamento para atualizar a exibição. Para isso, você pode adicionar manipuladores de mensagem para as mensagens de janela WM_PAINT e WM_DISPLAYCHANGE. Você pode fazer isso adicionando o seguinte ao mapa da mensagem:

MSG_WM_PAINT(OnPaint)
MSG_WM_DISPLAYCHANGE(OnDisplayChange)

Responder a WM_PAINT é óbvio, mas tratamento WM_DISPLAYCHANGE é igualmente importante garantir que a janela é redesenhada corretamente deve a resolução de vídeo ou profundidade de cor alterar (consulte a A Figura 5 ).

Figura 5 redesenho

void OnPaint(CDCHandle /*dc*/)
{
    PAINTSTRUCT paint;
    VERIFY(BeginPaint(&paint));
    Render();
    EndPaint(&paint);
}
void OnDisplayChange(UINT /*bpp*/, CSize /*resolution*/)
{
    Render();
}

Observe que o controlador de domínio retornado pelo BeginPaint não é usado em todos os. Criar a janela agora resultará em uma janela com um fundo vermelho, conforme o esperado. Redimensionar o janela será no entanto, revele alguns cintilação. O que está acontecendo é que o plano de fundo janela será ainda sendo desmarcado automaticamente usando o Pincel de plano de fundo de classe de janela devido ao tratamento padrão de mensagem WM_ERASEBKGND. Para evitar isso, simplesmente manipular esta mensagem e retornar TRUE no método OnEraseBackground para indicar que você irá se encarregar de limpeza de plano de fundo de janela. Agora você pode redimensionar a janela ao evitar qualquer cintilação.

Enquanto você estivê-la, você provavelmente desejará manipular o redimensionamento da janela. Para fazer isso, adicione um manipulador de mensagem para a mensagem em janela WM_SIZE, da seguinte maneira:

MSG_WM_SIZE(OnSize)

O identificador OnSize e precisa apenas informar o destino de processamento que o tamanho foi alterado:

void OnSize(UINT /*type*/, CSize size)
{
    if (0 != m_target)
    {
        if (FAILED(m_target->Resize(D2D1::SizeU(size.cx, size.cy))))
        {
            DiscardDeviceResources();
            VERIFY(Invalidate(FALSE));
        }
    }
}

Se ele falhar redimensionar, você simplesmente descartar os recursos de dispositivo, e eles serão automaticamente recriados na próxima vez que a janela é processada. Observe como o método de redimensionamento aceita o novo tamanho em pixels de dispositivo desde que a mensagem WM_SIZE comunica-se o tamanho da área cliente em pixels. Embora Direct2D utilize um sistema de coordenadas independentes de dispositivo, o destino de processamento de janela sabe que ele basicamente precisa mapear para o dispositivo pixels.

Pincéis E comandos de desenho

Para fazer qualquer desenho significativo, convém criar alguns pincéis. Você precisará pincéis para pintar diversas formas geométricas, bem como textos. Pincéis estão na categoria de recursos dependentes de dispositivo, portanto, sua criação deve ir no método CreateDeviceResources. Como você pode esperar, Direct2D fornece sólida e bitmap brushes, bem como lineares e radiais pincéis gradientes. Para criar um pincel de cor sólida, você pode adicionar a seguinte chamada do método imediatamente após criar o alvo processado. Dessa forma, ele é recriado somente quando o destino de processamento é recriado.

HR(m_target->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_brush));

Lembre-se também liberar o Pincel no método DiscardDeviceResources da seguinte maneira:

m_brush.Release();

Também convém adicionar a variável de membro de m_brush da seguinte maneira:

CComPtr<ID2D1SolidColorBrush> m_brush;

fig02.gif

A Figura 7 desenho básico

Agora você pode adicionar alguns comandos de desenho básicos para o método processamento entre os métodos não criptografado e EndDraw. O código na Figura 6 produz um círculo com uma linha diagonal através dele. Embora deixarei uma discussão completa sobre de pincéis para um artigo futuro, vale a pena mencionar que Direct2D permite alterar com eficiência a cor de um pincel durante o processamento, obviating a necessidade de criar vários pincéis para cores diferentes.

A Figura 6 círculo com linha diagonal

m_target->DrawLine(D2D1::Point2(10.0f, 10.0f), // start
                   D2D1::Point2(200.0f, 200.0f), // end
                   m_brush,
                   10.0f); // stroke width

const D2D1_POINT_2F center = D2D1::Point2(105.0f, 105.0f);

const D2D1_ELLIPSE ellipse = D2D1::Ellipse(center,
                                           95.0f, // radius X
                                           95.0f); // radius Y

m_target->DrawEllipse(&ellipse,
                      m_brush,
                      5.0f); // stroke width

Como já mencionei, Direct2D usa um independente de dispositivo sistema de coordenadas para as coordenadas expressas necessariamente não mapeiam para exibir pixels mas em vez disso, obedecem a configuração de PPP para o dispositivo de destino. a Figura 7 mostra o resultado dos comandos de desenho.

Embora eu tenha usado somente com um pincel opaco, você também pode especificar um valor de alfa quando criando o Pincel e alfa combinar ao conteúdo de seu coração.

Infelizmente, eu já completamente executar fora do espaço, mas agora você deve ter uma boa idéia da possibilidade de que Direct2D e DirectWrite terá em aplicativos nativos no futuro. Há muitas razões mais a adorar essas novas tecnologias que espero Examine em uma coluna futura, incluindo geometrias ricos e operações bem como todos os recursos da DirectWrite. Enquanto isso, inicie testando com Direct2D. Tenho certeza de que você encontrará ele impressionantes.

Idéias: processamento de Direct2D

muitas pessoas será tentadas comparar o desempenho de aplicativos Direct2D e Direct3D. Isso é algo de um aplica-se a comparação de laranjas Direct2D fornece um conjunto de primitivos muito mais comparável ao outro processamento 2D APIs como GDI/GDI + ou WPF. Ele também é muito mais simples de usar. No entanto, talvez seja surpreendente para alguns clientes que Direct2D pode out-perform, na verdade, um aplicativo de Direct3D simples, ou naïve, em um número de cenários diferentes. Por exemplo, Direct2D pode reduz um aplicativo Direct3D naïve ao desenhar grandes números de linhas com cores diferentes ou quando mistura repetidamente a partir de um bitmap.

A chave para como Direct2D faz isso é a perceber que Direct2D não mantém uma relação 1: 1 entre uma solicitação de desenho emitida para ele e os primitivos que emite a Direct3D. Na verdade, Direct2D tenta agregar suas solicitações para Direct3D em um número de maneiras diferentes.

Mapeamento de buffer de vértice reduzida

Considere um aplicativo Direct3D naïve. Ele cria um buffer de vértices, mapeia a ele, grava sua geometria no buffer, un-mapas-lo e desenha-lo. O problema com essa abordagem é que se o buffer vértice está ainda sendo usado pela GPU quando a próxima solicitação mapa, a CPU será necessário vaga até que a GPU é feita com ela, e, em seguida, ele só pode ser mapeado volta para a memória de aplicativo. Isso pode diminuir significativamente o desempenho do aplicativo.

Direct2D resolve esse problema, deixando o buffer de vértices mapeado na memória e acumular geometria dos primitivos sucessivas muitos nela. Somente quando o buffer vértice estiver cheio, ou o aplicativo chama liberação ou EndDraw, Direct2D e envia o desenho chama para baixo o Direct3D. Isso minimiza o número de vagas GPU porque o número de chamadas de mapa e cancelar o mapa é bastante reduzido.

Unindo chamadas de desenho

Mesmo depois geometrias têm permissão para se acumulam no buffer de vértice, um aplicativo Direct3D naïve teria que emita uma chamada de desenho para Direct3D para a maioria das chamadas Direct2D desenhar. Considere os dois retângulos diferentes processados com cores diferentes, cada cor pode requerem dados de constantes de sombreador diferentes escrita para representá-lo. Sempre que os dados de constantes de sombreador são atualizados, uma chamada de desenho diferente precisa ser emitido.

Desde que outras constantes não são alterados. Por exemplo, o mesmo tipo de pincel é usado consecutivamente. Ou, se um pincel de bitmap, o bitmap de entrada mesmo é usado consistentemente. Direct2D pode usar seus sombreadores de vértice para continuar a acumular dados de constantes de sombreador e, em seguida, emita uma chamada Direct3D desenhar para um grande número de chamadas Direct2D desenhar.

Fora de ordem de processamento de texto

O pipeline de processamento de texto Direct2D é executado inteiramente no hardware, através de três estágios. O primeiro estágio grava os glifos em uma textura para o próximo estágio baixo exemplos desses glifos e o estágio final executa uma operação de filtragem de tipo não criptografado para transferir o texto para o alvo processado. Um aplicativo naïve deve processar cada estágio seqüencialmente, alterando o alvo processado três vezes e emissão de um desenho chamada para mover os dados entre cada textura. Direct2D processará os primitivos de texto fora de ordem com outros primitivos. Ele primeiro será acumular um grande número de glifos. Em seguida, para baixo exemplos deles e combina o conjunto final de glifos na ordem com os outros primitivos geométricos emitidos para Direct2D. Coalescing o processamento de texto dessa maneira reduz o número de vezes que as alterações de destino de processamento, bem como o número de alterações de estado de dispositivo Direct3D gerais para processar o texto, mesmo se outros primitivos estiverem intercalados com o texto Direct2D processar chamadas.

Combinando lotes de buffer de vértice, coalescing de chamada de desenho e processamento de fora de ordem do texto, Direct2D é capaz de atingir o desempenho de processamento que exigiria abrangente quantidade de esforço de desenvolvimento para corresponder ao se o aplicativo em vez disso, foram diretamente direcionamento Direct3D.

--Mark Lawrence, sênior engenheiro de desenvolvimento de software, Microsoft.

Envie suas dúvidas e comentários para mmwincpp@Microsoft.com

Kenny Kerr é um profissional de fabricação de software especializado no desenvolvimento de software para o Windows. Ele adora escrever e ensinar aos desenvolvedores sobre design de programação e software. Você pode acessar Kenny em weblogs.asp. NET/kennykerr.