Partilhar via


Melhorar o desempenho das aplicações Direct2D

Embora Direct2D seja acelerado por hardware e se destine a alto desempenho, você deve usar os recursos corretamente para maximizar a taxa de transferência. As técnicas que mostramos aqui são derivadas do estudo de cenários comuns e podem não se aplicar a todos os cenários de aplicativos. Portanto, uma compreensão cuidadosa do comportamento do aplicativo e das metas de desempenho pode ajudar a alcançar os resultados desejados.

Utilização de recursos

Um recurso é uma alocação de algum tipo, seja em vídeo ou na memória do sistema. Bitmaps e pincéis são exemplos de recursos.

No Direct2D, os recursos podem ser criados tanto em software como em hardware. A criação e exclusão de recursos no hardware são operações caras porque exigem muita sobrecarga para se comunicar com a placa de vídeo. Vamos ver como o Direct2D renderiza o conteúdo para um alvo.

No Direct2D, todos os comandos de renderização são incluídos entre uma chamada para BeginDraw e uma chamada para EndDraw. Essas chamadas são feitas para um alvo de renderização. Você deve chamar o método BeginDraw antes de realizar operações de renderização. Depois de chamar BeginDraw , um contexto normalmente cria um lote de comandos de renderização, mas atrasa o processamento desses comandos até que uma destas instruções seja verdadeira:

  • EndDraw ocorreu. Quando EndDraw é chamado, ele faz com que todas as operações de desenho em lote sejam concluídas e retorna o status da operação.
  • Você faz uma chamada explícita para Flush: O método Flush faz com que o lote seja processado e todos os comandos pendentes sejam emitidos.
  • O buffer que contém os comandos de renderização está cheio. Se este buffer se encher antes que as duas condições anteriores sejam atendidas, os comandos de renderização são esvaziados.

Até que as primitivas sejam liberadas, o Direct2D mantém referências internas aos recursos correspondentes, como bitmaps e pincéis.

Reutilizar recursos

Como já mencionado, a criação e exclusão de recursos é cara em hardware. Por isso, reutilize os recursos sempre que possível. Tomemos o exemplo da criação de bitmap no desenvolvimento de jogos. Normalmente, os bitmaps que compõem uma cena em um jogo são todos criados ao mesmo tempo com todas as diferentes variações que são necessárias para renderização posterior quadro a quadro. No momento da renderização e rerenderização da cena real, esses bitmaps são reutilizados em vez de recriados.

Observação

Não é possível reutilizar recursos para a operação de redimensionamento de janelas. Quando uma janela é redimensionada, alguns recursos dependentes de escala, como destinos de renderização compatíveis e, possivelmente, alguns recursos de camada devem ser recriados porque o conteúdo da janela precisa ser redesenhado. Isso pode ser importante para manter a qualidade geral da cena renderizada.

 

Restrinja o uso de escoamento

Como o método Flush faz com que os comandos de renderização em lote sejam processados, recomendamos que você não o use. Para os cenários mais comuns, deixe o gerenciamento de recursos para o Direct2D.

Bitmaps

Como mencionado anteriormente, a criação e exclusão de recursos são operações muito caras em hardware. Um bitmap é um tipo de recurso que é usado com frequência. Criar bitmaps na placa de vídeo é caro. Reutilizá-los pode ajudar a tornar o aplicativo mais rápido.

Criar bitmaps grandes

As placas de vídeo normalmente têm um tamanho mínimo de alocação de memória. Se for solicitada uma alocação menor do que isso, um recurso desse tamanho mínimo será alocado e a memória excedente será desperdiçada e indisponível para outras coisas. Se você precisar de muitos bitmaps pequenos, uma técnica melhor é alocar um bitmap grande e armazenar todo o conteúdo de bitmap pequeno nesse bitmap grande. Em seguida, as subáreas do bitmap maior podem ser lidas onde os bitmaps menores são necessários. Muitas vezes, você deve incluir preenchimento (pixels pretos transparentes) entre os pequenos bitmaps para evitar qualquer interação entre as imagens menores durante as operações. Isso também é conhecido como um atlas, e reduz a sobrecarga na criação de bitmaps e o desperdício de memória em pequenas alocações de bitmap. Recomendamos que você mantenha a maioria dos bitmaps em pelo menos 64 KB e limite o número de bitmaps menores que 4 KB.

Criar um atlas de bitmaps

Existem alguns cenários comuns para os quais um atlas de bitmap pode servir muito bem. Pequenos bitmaps podem ser armazenados dentro de um bitmap grande. Esses pequenos bitmaps podem ser retirados do bitmap maior quando você precisar deles, especificando o retângulo de destino. Por exemplo, um aplicativo tem que desenhar vários ícones. Todos os bitmaps associados aos ícones podem ser carregados em um bitmap grande antecipadamente. E no momento da renderização, podem ser recuperados do grande bitmap.

Observação

Um bitmap Direct2D criado na memória de vídeo é limitado ao tamanho máximo de bitmap suportado pelo adaptador no qual ele está armazenado. Criar um bitmap maior do que isso pode resultar em um erro.

 

Observação

A partir do Windows 8, o Direct2D inclui um efeito Atlas que pode facilitar esse processo.

 

Criar bitmaps compartilhados

A criação de bitmaps compartilhados permite que chamadores avançados criem objetos de bitmap Direct2D que são apoiados diretamente por um objeto existente, já compatível com o destino de renderização. Isso evita a criação de várias superfícies e ajuda a reduzir a sobrecarga de desempenho.

Observação

Os bitmaps compartilhados geralmente são limitados a destinos de software ou a destinos interoperáveis com DXGI. Use os métodos CreateBitmapFromDxgiSurface, CreateBitmapFromWicBitmape CreateSharedBitmap para criar bitmaps partilhados.

 

Copiando bitmaps

Criar uma superfície DXGI é uma operação cara, portanto, reutilize as superfícies existentes quando puder. Mesmo em software, se um bitmap estiver principalmente na forma que você deseja, exceto por uma pequena parte, é melhor atualizar essa parte do que jogar todo o bitmap fora e recriar tudo. Embora você possa usar CreateCompatibleRenderTarget para obter os mesmos resultados, a renderização geralmente é uma operação muito mais cara do que a cópia. Isso ocorre porque, para melhorar a localidade do cache, o hardware não armazena um bitmap na mesma ordem de memória em que o bitmap é endereçado. Em vez disso, o bitmap pode ser reorganizado. O swizzling é ocultado da CPU, ou pelo driver (que é lento e usado apenas em componentes de gama baixa), ou pelo gestor de memória na GPU. Devido a restrições sobre como os dados são gravados num alvo de renderização durante a renderização, os alvos de renderização geralmente não são enredados ou são enredados de uma maneira menos ideal do que pode ser alcançada se souberes que nunca precisas de renderizar para a superfície. Portanto, os métodos CopyFrom* são fornecidos para copiar retângulos de uma origem para o bitmap Direct2D.

CopyFrom pode ser usado em qualquer uma das suas três formas:

Utilizar bitmap em mosaico em vez de tracejar

Renderizar uma linha tracejada é uma operação muito cara devido à alta qualidade e precisão do algoritmo subjacente. Para a maioria dos casos que não envolvem geometrias retilíneas, o mesmo efeito pode ser gerado mais rapidamente usando bitmaps em mosaico.

Diretrizes gerais para renderizar conteúdo estático complexo

Armazene o conteúdo em cache se renderizar o mesmo quadro de conteúdo frame a frame, especialmente conforme a cena for complexa.

Há três técnicas de cache que você pode usar:

  • Cache de cena completo usando um bitmap colorido.
  • Por cache primitivo utilizando um bitmap A8 e o método FillOpacityMask .
  • Cache per-primitivo usando implementações de geometria.

Vejamos cada um deles com mais detalhes.

Cacheamento completo de cena usando um mapa de bits colorido

Ao renderizar conteúdo estático, em cenários como animação, crie outro bitmap colorido em vez de gravar diretamente no bitmap da tela. Salve o destino atual, defina o destino para o bitmap intermediário e renderize o conteúdo estático. Em seguida, volte para o bitmap da tela original e desenhe o bitmap intermediário nele.

Aqui está um exemplo:

// Create a bitmap.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_B8G8R8A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &sceneBitmap);

// Preserve the pre-existing target.
ComPtr<ID2D1Image> oldTarget;
m_d2dContext->GetTarget(&oldTarget);

// Render static content to the sceneBitmap.
m_d2dContext->SetTarget(sceneBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Render sceneBitmap to oldTarget.
m_d2dContext->SetTarget(oldTarget.Get());
m_d2dContext->DrawBitmap(sceneBitmap.Get());

Este exemplo usa bitmaps intermediários para armazenamento em cache e alterna para o bitmap ao qual o contexto do dispositivo aponta quando renderiza. Isso evita a necessidade de criar um destino de renderização compatível para a mesma finalidade.

Por cache primitivo usando um bitmap A8 e o método FillOpacityMask

Quando a cena completa não é estática, mas consiste em elementos como geometria ou texto que são estáticos, pode-se usar uma técnica de cache por elemento primitivo. Esta técnica preserva as características de suavização de serrilhado do primitivo que está sendo armazenado em cache e trabalha com a mudança de tipos de pincel. Ele usa um bitmap A8 onde A8 é um tipo de formato de pixel que representa um canal alfa com 8 bits. Os bitmaps A8 são úteis para desenhar geometria/texto como uma máscara. Quando você deve manipular a opacidade do conteúdo estático, em vez de manipular o conteúdo em si, você pode traduzir, girar, distorcer ou dimensionar a opacidade da máscara.

Aqui está um exemplo:

// Create an opacity bitmap.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

// Preserve the pre-existing target.
ComPtr<ID2D1Image> oldTarget;
m_d2dContext->GetTarget(&oldTarget);

// Render to the opacityBitmap.
m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Call the FillOpacityMask method
// Note: for this call to work correctly the anti alias mode must be D2D1_ANTIALIAS_MODE_ALIASED. 
m_d2dContext->SetTarget(oldTarget.Get());
m_d2dContext->FillOpacityMask(
    opacityBitmap.Get(),
    m_contentBrush().Get(),
    D2D1_OPACITY_MASK_CONTENT_GRAPHICS);

Cache por primitiva usando realizações de geometria

Outra técnica de cache para cada primitiva, chamada de implementações de geometria, fornece maior flexibilidade ao lidar com geometria. Quando desejas desenhar repetidamente geometrias aliased ou anti-aliased, é mais rápido convertê-las em representações de geometria e desenhar repetidamente as representações do que desenhar repetidamente as próprias geometrias. As realizações de geometria também geralmente consomem menos memória do que as máscaras de opacidade (especialmente para grandes geometrias), e são menos sensíveis a mudanças de escala. Para obter mais informações, consulte Visão geral das realizações de geometria .

Aqui está um exemplo:

    // Compute a flattening tolerance based on the scales at which the realization will be used.
    float flatteningTolerance = D2D1::ComputeFlatteningTolerance(...);

    ComPtr<ID2D1GeometryRealization> geometryRealization;

    // Create realization of the filled interior of the geometry.
    m_d2dDeviceContext1->CreateFilledGeometryRealization(
        geometry.Get(),
        flatteningTolerance,
        &geometryRealization
        );

    // In your app's rendering code, draw the geometry realization with a brush.
    m_d2dDeviceContext1->BeginDraw();
    m_d2dDeviceContext1->DrawGeometryRealization(
        geometryRealization.Get(),
        m_brush.Get()
        );
    m_d2dDeviceContext1->EndDraw();

Renderização de geometria

Usar uma primitiva de desenho específica em vez de geometria de desenho

Use chamadas de primitivas mais específicas de desenho, como DrawRectangle sobre chamadas genéricas DrawGeometry. Isso ocorre porque com DrawRectangle, a geometria já é conhecida, então a renderização é mais rápida.

Renderização de geometria estática

Em cenários onde a geometria é estática, use as técnicas de cache por primitiva explicadas acima. Máscaras de opacidade e realizações de geometria podem melhorar muito a velocidade de renderização de cenas que contêm geometria estática.

Usar um contexto de dispositivo multifiado

As aplicações que esperam renderizar quantidades significativas de conteúdo geométrico complexo devem considerar especificar o sinalizador de D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTI_THREADED_OPTIMIZATIONS ao criar um contexto de dispositivo Direct2D . Quando esse sinalizador é especificado, o Direct2D distribuirá a renderização em todos os núcleos lógicos presentes no sistema, o que pode diminuir significativamente o tempo de renderização geral.

Observações:

  • A partir do Windows 8.1, esse sinalizador afeta apenas a renderização da geometria do caminho. Ele não tem impacto em cenas que contêm apenas outros tipos primitivos (como texto, bitmaps ou realizações de geometria).
  • Este sinalizador também não tem impacto ao renderizar em software (ou seja, ao renderizar com um dispositivo Direct3D WARP). Para controlar o multithreading de software, os chamadores devem usar o sinalizador D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS ao criar o dispositivo Direct3D WARP.
  • Especificar esse sinalizador pode aumentar o conjunto de trabalho de pico durante a renderização e também pode aumentar a contenção de threads em aplicativos que já aproveitam o processamento multithreaded.

Desenho de texto com Direct2D

A funcionalidade de renderização de texto Direct2D é oferecida em duas partes. A primeira parte, exposta como o método ID2D1RenderTarget::DrawText e o método ID2D1RenderTarget::DrawTextLayout, permite que um chamador passe uma cadeia de caracteres e parâmetros de formatação ou um objeto de layout de texto DWrite para formatos múltiplos. Isso deve ser adequado para a maioria dos interlocutores. A segunda maneira de renderizar texto, apresentada como o método ID2D1RenderTarget::DrawGlyphRun , fornece rasterização para clientes que já sabem a posição dos glifos que desejam renderizar. As duas regras gerais a seguir podem ajudar a melhorar o desempenho do texto ao desenhar em Direct2D.

DrawTextLayout Vs. DrawText

Tanto DrawText quanto DrawTextLayout permitem que um aplicativo renderize facilmente texto formatado pela DirectWrite API. DrawTextLayout desenha um objeto DWriteTextLayout existente no RenderTarget, e DrawText constrói um layout DirectWrite para o chamador, com base nos parâmetros que são passados. Se o mesmo texto tiver que ser renderizado várias vezes, use DrawTextLayout em vez de DrawText, porque DrawText cria um layout sempre que é chamado.

Escolhendo o modo de renderização de texto correto

Defina o modo antialias de texto para D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE explicitamente. A qualidade da renderização de texto em tons de cinza é comparável ao ClearType, mas é muito mais rápida.

Armazenamento em cache

Use a cena completa ou por cache de bitmap primitivo, como com o desenho de outras primitivas.

Recortar uma forma arbitrária

A figura aqui mostra o resultado da aplicação de um clipe a uma imagem.

uma imagem que mostra um exemplo de uma imagem antes e depois de um clipe.

Você pode obter esse resultado usando camadas com uma máscara de geometria ou o método FillGeometry com um pincel de opacidade.

Aqui está um exemplo que usa uma camada:

// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
    D2D1::LayerParameters(
        boundsRect,
        geometricMask));

Aqui está um exemplo que usa o método FillGeometry:

// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
    D2D1::BitmapBrushProperties(),
    D2D1::BrushProperties(),
    &bitmapBrush);

// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry( 
    clipGeometry.Get(),
    brush.Get(),
    opacityBrush.Get()); 

Neste exemplo de código, quando você chama o método PushLayer, você não passa em uma camada criada pelo aplicativo. O Direct2D cria uma camada para você. O Direct2D é capaz de gerenciar a alocação e a destruição desse recurso sem qualquer envolvimento do aplicativo. Isso permite que o Direct2D reutilize camadas internamente e aplique otimizações de gerenciamento de recursos.

No Windows 8, muitas otimizações foram feitas para o uso de camadas e recomendamos que você tente usar APIs de camada em vez de FillGeometry sempre que possível.

PushLayer no Windows 8

A interface ID2D1DeviceContext é derivada da interface ID2D1RenderTarget e é fundamental para exibir conteúdo Direct2D no Windows 8, para mais informações sobre esta interface, consulte Devices and Device Contexts. Com a interface de contexto do dispositivo, pode ignorar a chamada do método CreateLayer e, em seguida, passar NULL para o método ID2D1DeviceContext::PushLayer. O Direct2D gerencia automaticamente o recurso de camada e pode compartilhar recursos entre camadas e gráficos de efeitos.

Clipes alinhados ao eixo

Se a região a ser cortada estiver alinhada ao eixo da superfície de desenho, em vez de arbitrária. Este estojo é adequado para usar um retângulo de clipe em vez de uma camada. O ganho de desempenho é maior para geometria com aliasing do que para geometria com antialiasing. Para saber mais sobre clipes alinhados por eixo, veja o tópico PushAxisAlignedClip.

Interoperabilidade DXGI: evite switches frequentes

O Direct2D pode interoperar perfeitamente com superfícies Direct3D. Isso é muito útil para criar aplicativos que renderizam uma mistura de conteúdo 2D e 3D. Mas cada alternância entre desenhar conteúdo Direct2D e Direct3D afeta o desempenho.

Ao renderizar em uma superfície DXGI, o Direct2D salva o estado dos dispositivos Direct3D durante a renderização e o restaura quando a renderização é concluída. Toda vez que um lote de renderização Direct2D é concluído, o custo desse salvamento e restauração e o custo de liberar todas as operações 2D são pagos e, no entanto, o dispositivo Direct3D não é liberado. Portanto, para aumentar o desempenho, limite o número de opções de renderização entre Direct2D e Direct3D.

Conheça o seu formato de pixel

Ao criar um destino de renderização, você pode usar a estrutura D2D1_PIXEL_FORMAT especificar o formato de pixel e o modo alfa usados pelo destino de renderização. Um canal alfa faz parte do formato de pixel que especifica o valor de cobertura ou as informações de opacidade. Se um destino de renderização não usar o canal alfa, ele deve ser criado utilizando o modo alfa D2D1_ALPHA_MODE_IGNORE. Isso poupa o tempo gasto na renderização de um canal alfa que não é necessário.

Para obter mais informações sobre formatos de pixel e modos alfa, consulte Formatos de pixel suportados e modos alfa.

Complexidade da Cena

Quando se analisam pontos críticos de desempenho em uma cena que será renderizada, saber se a cena está limitada pela taxa de preenchimento ou pelo número de vértices pode fornecer informações úteis.

  • Taxa de preenchimento: A taxa de preenchimento refere-se ao número de pixels que uma placa gráfica pode renderizar e gravar na memória de vídeo por segundo.
  • Vertex Bound: Uma cena é limitada por vértices quando contém uma grande quantidade de geometria complexa.

Compreender a complexidade da cena

Você pode analisar a complexidade da cena alterando o tamanho do destino de renderização. Se os ganhos de desempenho forem visíveis para uma redução proporcional no tamanho do destino de renderização, então a aplicação está limitada pela taxa de preenchimento. Caso contrário, a complexidade da cena é o gargalo de desempenho.

Quando uma cena está limitada à taxa de preenchimento, reduzir o tamanho do destino de renderização pode melhorar o desempenho. Isso ocorre porque o número de pixels a serem renderizados será reduzido proporcionalmente com o tamanho do destino de renderização.

Quando uma cena é limitada ao vértice, reduza a complexidade da geometria. Mas lembre-se que isso é feito às custas da qualidade da imagem. Portanto, uma decisão de troca cuidadosa deve ser tomada entre a qualidade desejada e o desempenho que é necessário.

Melhorar o desempenho de aplicações de impressão Direct2D

Direct2D oferece compatibilidade com impressão. Você pode enviar os mesmos comandos de desenho Direct2D (na forma de listas de comandos Direct2D) para o controle de impressão Direct2D para impressão, se não souber para quais dispositivos está desenhando ou como o desenho é traduzido para impressão.

Você pode ajustar ainda mais o seu uso do Direct2D controle de impressão e dos seus comandos de desenho Direct2D para obter resultados de impressão com melhor desempenho.

O controle de impressão Direct2D emite mensagens de depuração quando vê um padrão de código Direct2D que leva a uma qualidade de impressão ou desempenho mais baixos (como padrões de código listados posteriormente neste tópico) para lembrá-lo de onde você pode evitar problemas de desempenho. Para ver essas mensagens de depuração, necessita habilitar Camada de Depuração Direct2D em seu código. Consulte Debug Messages para obter instruções sobre como ativar a saída de mensagens de depuração.

Defina os valores de propriedade corretos ao criar o controle de impressão D2D

Há três propriedades que você pode definir ao criar o controle de impressão Direct2D. Duas dessas propriedades afetam como o controle de impressão Direct2D lida com determinados comandos Direct2D e, por sua vez, afetam o desempenho geral.

  • Modo de subconjunto de fontes: o controle de impressão Direct2D subdefine os recursos de fonte usados em cada página antes de enviar a página a ser impressa. Este modo reduz o tamanho dos recursos de página necessários para imprimir. Dependendo do uso de fontes na página, você pode escolher diferentes modos de subconjunto de fontes para obter o melhor desempenho.
    • D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT proporciona o melhor desempenho de impressão na maioria dos casos. Quando definido para esse modo, o controle de impressão Direct2D usa uma estratégia heurística para decidir quando subdefinir fontes.
    • Para trabalhos de impressão curtos com 1 ou 2 páginas, recomendamos D2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE, onde o controlo de impressão Direct2D cria subconjuntos e incorpora recursos de fontes em cada página e, em seguida, descarta esse subconjunto de fontes após a impressão da página. Essa opção garante que cada página possa ser impressa imediatamente após ser gerada, mas aumenta ligeiramente o tamanho dos recursos de página necessários para impressão (com subconjuntos de fontes geralmente grandes).
    • Para trabalhos de impressão com muitas páginas de textos e tamanhos de fonte pequenos (como 100 páginas de texto que usa uma única fonte), recomendamos D2D1_PRINT_FONT_SUBSET_MODE_NONE, onde o controle de impressão Direct2D não subdefine recursos de fonte; em vez disso, ele envia os recursos de fonte originais junto com a página que primeiro usa a fonte e reutiliza os recursos de fonte para páginas posteriores sem reenviá-los.
  • DPI de rasterização: quando o controle de impressão Direct2D precisa rasterizar comandos Direct2D durante Direct2D-XPS conversão, ele usa esse DPI para rasterização. Em outras palavras, se a página não tiver nenhum conteúdo rasterizado, definir qualquer DPI não mudará o desempenho e a qualidade. Dependendo do uso de rasterização na página, você pode escolher diferentes DPIs de rasterização para o melhor equilíbrio entre fidelidade e desempenho.
    • 150 é o valor padrão se você não especificar um valor ao criar o controle de impressão Direct2D, que é o melhor equilíbrio entre qualidade de impressão e desempenho de impressão na maioria dos casos.
    • Valores de DPI mais altos geralmente resultam em melhor qualidade de impressão (como em mais detalhes preservados), mas menor desempenho devido aos bitmaps maiores que gera. Não recomendamos nenhum valor de DPI superior a 300, uma vez que isso não introduzirá informações extras visualmente percetíveis pelos olhos humanos.
    • DPI mais baixo pode significar melhor desempenho, mas também pode produzir menor qualidade.

Evite usar determinados padrões de desenho Direct2D

Há diferenças entre o que o Direct2D pode representar visualmente e o que o subsistema de impressão pode manter e transportar ao longo de todo o pipeline de impressão. O controle de impressão Direct2D preenche essas lacunas aproximando ou rasterizando primitivas Direct2D que o subsistema de impressão não suporta nativamente. Essa aproximação geralmente resulta em menor fidelidade de impressão, menor desempenho de impressão ou ambos. Portanto, mesmo que um cliente possa usar os mesmos padrões de desenho para renderização de tela e impressão, isso não é ideal em todos os casos. É melhor não usar tais primitivas e padrões Direct2D tanto quanto possível para o processo de impressão, ou fazer a sua própria rasterização onde tem controlo total sobre a qualidade e o tamanho das imagens rasterizadas.

Aqui está uma lista de casos em que o desempenho e a qualidade de impressão não serão ideais e você pode querer considerar variar o caminho do código para um desempenho de impressão ideal.

  • Evite utilizar um modo de mistura primitivo que não seja D2D1_PRIMITIVE_BLEND_SOURCEOVER.
  • Evite usar os Modos de Composição ao desenhar uma imagem, a não ser D2D1_COMPOSITE_MODE_SOURCE_OVER e D2D1_COMPOSITE_MODE_DESTINATION_OVER.
  • Evite desenhar um Metaficheiro GDI.
  • Evite empurrar um recurso de camada que copia o fundo de origem (chamando PushLayer passando D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND para a estrutura D2D1_LAYER_PARAMETERS1).
  • Evite criar Pincel de Bitmap ou Pincel de Imagem com D2D1_EXTEND_MODE_CLAMP. Recomendamos que use D2D1_EXTEND_MODE_MIRROR se não se importar de pixels fora dos limites da imagem (por exemplo, a imagem associada ao pincel é conhecida por ser maior do que a região alvo preenchida).
  • Evite desenhar bitmaps com transformações de perspetiva .

Desenhar texto de forma direta e clara

O Direct2D tem várias otimizações ao renderizar textos para exibição para melhor desempenho e/ou melhor qualidade visual. Mas nem todas as otimizações melhoram o desempenho e a qualidade de impressão, uma vez que a impressão em papel geralmente está em um DPI muito mais alto, e a impressão não precisa acomodar cenários como animação. Portanto, recomendamos que você desenhe o texto original ou glifos diretamente e evite qualquer uma das seguintes otimizações ao criar a lista de comandos para impressão.

  • Evite desenhar texto com o método FillOpacityMask.
  • Evite desenhar texto no Modo Serrilhado.

Desenhe os bitmaps originais quando possível

Se o bitmap de destino for um JPEG, PNG, TIFF ou JPEG-XR, você poderá criar um bitmap WIC a partir de um arquivo de disco ou de um fluxo na memória e, em seguida, criar um bitmap Direct2D a partir desse bitmap WIC usando ID2D1DeviceContext::CreateBitmapFromWicBitmape, finalmente, passar diretamente esse bitmap Direct2D para o controle de impressão Direct2D sem manipulação adicional. Ao fazer isso, o controle de impressão Direct2D é capaz de reutilizar o fluxo de bitmap, o que geralmente leva a um melhor desempenho de impressão (ignorando a codificação e decodificação de bitmap redundante) e melhor qualidade de impressão (quando os metadados, como perfis de cores, no bitmap serão preservados).

Desenhar o bitmap original fornece o seguinte benefício para aplicativos.

  • Em geral, Direct2D preserva as informações originais (sem perda ou ruído) até tarde no processo, especialmente quando as aplicações não sabem (ou não desejam saber) os detalhes do processo de impressão (como em qual impressora está a imprimir, qual DPI é a impressora de destino e assim por diante).
  • Em muitos casos, atrasar a rasterização de bitmap significa melhor desempenho (como ao imprimir uma foto de 96dpi em uma impressora de 600dpi).
  • Em certos casos, passar as imagens originais é a única maneira de honrar a alta fidelidade (como perfis de cores incorporados).

No entanto, você não pode optar por essa otimização porque:

  • Ao interrogar as informações da impressora e efetuar a rasterização antecipadamente, é possível rasterizar o conteúdo em si com controle total sobre a aparência final no papel.
  • Em certos casos, a rasterização antecipada pode realmente melhorar o desempenho de ponta a ponta de um aplicativo (como imprimir fotos do tamanho de carteiras).
  • Em certos casos, a manipulação dos bitmaps originais requer alterações significativas na arquitetura do código existente, como no caso do carregamento tardio de imagens e dos processos de atualização de recursos encontrados em determinados aplicativos.

Conclusão

Embora o Direct2D seja acelerado por hardware e se destine a alto desempenho, você deve usar os recursos corretamente para maximizar a taxa de transferência. As técnicas que analisamos aqui são derivadas do estudo de cenários comuns e podem não se aplicar a todos os cenários de aplicativos.