Melhorando o desempenho de aplicativos Direct2D
Embora Direct2D seja acelerada por hardware e seja destinada 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 aplicativo. Portanto, uma compreensão cuidadosa do comportamento do aplicativo e das metas de desempenho pode ajudar a alcançar os resultados desejados.
- Uso de recursos
- Restringir o uso da liberação
- Bitmaps
- Usar bitmap em bloco sobre traço
- Diretrizes gerais para renderizar conteúdo estático complexo
- Cache por primitivo usando realizações de geometria
- Renderização de geometria
- Desenho de texto com Direct2D
- Recortar uma forma arbitrária
- Interoperabilidade de DXGI: evitar comutadores frequentes
- Conheça seu formato de pixel
- Complexidade da cena
- Melhorando o desempenho para aplicativos de impressão Direct2D
- Conclusão
Uso 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.
Em Direct2D, os recursos podem ser criados tanto em software quanto em hardware. A criação e a exclusão de recursos no hardware são operações caras porque exigem muita sobrecarga para se comunicar com o vídeo cartão. Vamos ver como Direct2D renderiza o conteúdo para um destino.
Em Direct2D, todos os comandos de renderização são colocados entre uma chamada para BeginDraw e uma chamada para EndDraw. Essas chamadas são feitas para um destino de renderização. Você deve chamar o método BeginDraw antes de chamar as 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 dessas 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 esse buffer ficar cheio antes que as duas condições anteriores sejam atendidas, os comandos de renderização serão liberados.
Até que os primitivos sejam liberados, Direct2D mantém referências internas a recursos correspondentes, como bitmaps e pincéis.
Reutilizar recursos
Como já mencionado, a criação e a exclusão de recursos são caras no hardware. Portanto, reutilize os recursos quando possível. Veja o exemplo de criação de bitmap no desenvolvimento de jogos. Normalmente, bitmaps que compõem uma cena em um jogo são criados ao mesmo tempo com todas as diferentes variações necessárias para renderização de quadro a quadro posterior. No momento da renderização e renderização de cena reais, esses bitmaps são reutilizados em vez de recriados.
Observação
Não é possível reutilizar recursos para a operação de redimensionamento da janela. 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.
Restringir o uso da liberação
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 cenários mais comuns, deixe o gerenciamento de recursos para Direct2D.
Bitmaps
Conforme mencionado anteriormente, a criação e a exclusão de recursos são operações muito caras no hardware. Um bitmap é um tipo de recurso que é usado com frequência. Criar bitmaps no vídeo cartão é 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 que essa, 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 será alocar um bitmap grande e armazenar todo o conteúdo de bitmap pequeno neste bitmap grande. Em seguida, subáreas do bitmap maior podem ser lidas onde os bitmaps menores são necessários. Muitas vezes, você deve incluir o preenchimento (pixels pretos transparentes) entre os bitmaps pequenos para evitar qualquer interação entre as imagens menores durante as operações. Isso também é conhecido como atlas e tem o benefício de reduzir a sobrecarga de criação de bitmap e o desperdício de memória de pequenas alocações de bitmap. Recomendamos que você mantenha a maioria dos bitmaps para pelo menos 64 KB e limite o número de bitmaps menores que 4 KB.
Criar um atlas de bitmaps
Há alguns cenários comuns para os quais um atlas de bitmap pode servir muito bem. Bitmaps pequenos podem ser armazenados dentro de um bitmap grande. Esses bitmaps pequenos podem ser retirados do bitmap maior quando você precisa deles especificando o retângulo de destino. Por exemplo, um aplicativo precisa desenhar vários ícones. Todos os bitmaps associados aos ícones podem ser carregados em um bitmap grande na frente. E no momento da renderização, eles podem ser recuperados do bitmap grande.
Observação
Um bitmap Direct2D criado na memória de vídeo é limitado ao tamanho máximo de bitmap com suporte pelo adaptador no qual ele é armazenado. Criar um bitmap maior do que isso pode resultar em um erro.
Observação
A partir de Windows 8, 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 Direct2D objetos bitmap que são apoiados diretamente por um objeto existente, já compatíveis 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, CreateBitmapFromWicBitmap e CreateSharedBitmap para criar bitmaps compartilhados.
Copiar bitmaps
Criar uma superfície DXGI é uma operação cara para reutilizar superfícies existentes quando possível. Mesmo no software, se um bitmap estiver principalmente na forma desejada, 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 copiar. Isso ocorre porque, para melhorar a localidade do cache, o hardware não armazena realmente um bitmap na mesma ordem de memória que o bitmap é endereçado. Em vez disso, o bitmap pode ser girado. O swizzling é oculto da CPU pelo driver (que é lento e usado apenas em partes inferiores) ou pelo gerenciador de memória na GPU. Devido a restrições sobre como os dados são gravados em um destino de renderização durante a renderização, os destinos de renderização normalmente não são girados ou girados de uma maneira menos ideal do que pode ser obtida se você sabe que nunca precisa renderizar na 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 de suas três formas:
Usar bitmap em bloco sobre traço
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 retilineares, o mesmo efeito pode ser gerado mais rapidamente usando bitmaps em bloco.
Diretrizes gerais para renderizar conteúdo estático complexo
Armazenar conteúdo em cache se você renderizar o mesmo quadro de conteúdo por quadro, especialmente quando a cena for complexa.
Há três técnicas de cache que você pode usar:
- Cache de cena completo usando um bitmap de cor.
- Por cache primitivo usando um bitmap A8 e o método FillOpacityMask .
- Cache por primitivo usando realizações de geometria.
Vamos examinar cada uma delas com mais detalhes.
Cache de cena completo usando um bitmap de cor
Ao renderizar conteúdo estático, em cenários como animação, crie outro bitmap de cor completa 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 de tela original e desenhe o bitmap intermediário nele.
Veja 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 cache e alterna o bitmap para o qual o contexto do dispositivo aponta quando ele é renderizado. 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 estático, você pode usar uma técnica de cache por primitivo. Essa técnica preserva as características de suavização do primitivo que está sendo armazenado em cache e funciona com a alteração de tipos de pincel. Ele usa um bitmap A8 em que o A8 é uma espécie 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ê precisa manipular a opacidade do conteúdo estático , em vez de manipular o próprio conteúdo, é possível traduzir, girar, distorcer ou dimensionar a opacidade da máscara.
Veja 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 primitivo usando realizações de geometria
Outra técnica de cache por primitivo, chamada de realizações de geometria, fornece maior flexibilidade ao lidar com geometria. Quando você deseja desenhar repetidamente geometrias aliased ou anti-aliased, é mais rápido convertê-las em realizações de geometria e desenhar repetidamente as realizações do que desenhar repetidamente as geometrias em si. As realizações de geometria também geralmente consomem menos memória do que máscaras de opacidade (especialmente para geometrias grandes) e são menos sensíveis a alterações em escala. Para obter mais informações, consulte Visão geral de realizações de geometria.
Veja 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 um desenho primitivo específico sobre a geometria de desenho
Use chamadasprimitivas de desenho mais específicas, como DrawRectangle , em chamadas genéricas drawGeometry . Isso ocorre porque, com DrawRectangle, a geometria já é conhecida, portanto, a renderização é mais rápida.
Renderizando geometria estática
Em cenários em que a geometria é estática, use as técnicas de cache por primitivo 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 multithread
Os aplicativos que esperam renderizar quantidades significativas de conteúdo geométrico complexo devem considerar especificar o sinalizador D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTI_THREADED_OPTIMIZATIONS ao criar um Direct2D contexto do dispositivo. Quando esse sinalizador for especificado, 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 de Windows 8.1, esse sinalizador afeta apenas a renderização de 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).
- Esse sinalizador também não tem impacto ao renderizar no software (ou seja, ao renderizar com um dispositivo WARP Direct3D). Para controlar o multithreading de software, os chamadores devem usar o sinalizador D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS ao criar o dispositivo WARP Direct3D.
- Especificar esse sinalizador pode aumentar o conjunto de trabalho de pico durante a renderização e também pode aumentar a contenção de thread em aplicativos que já aproveitam o processamento multithread.
Desenho de texto com Direct2D
Direct2D funcionalidade de renderização de texto é oferecida em duas partes. A primeira parte, exposta como o método ID2D1RenderTarget::D rawText e ID2D1RenderTarget::D rawTextLayout , permite que um chamador passe uma cadeia de caracteres e parâmetros de formatação ou um objeto de layout de texto DWrite para vários formatos. Isso deve ser adequado para a maioria dos chamadores. A segunda maneira de renderizar texto, exposta como o método ID2D1RenderTarget::D rawGlyphRun , 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 Direct2D.
DrawTextLayout Vs. DrawText
DrawText e DrawTextLayout permitem que um aplicativo renderize facilmente o texto formatado pela API DirectWrite. DrawTextLayout desenha um objeto DWriteTextLayout existente para o RenderTarget e DrawText constrói um layout DirectWrite para o chamador, com base nos parâmetros passados. Se o mesmo texto precisar ser renderizado várias vezes, use DrawTextLayout em vez de DrawText, pois DrawText cria um layout sempre que é chamado.
Escolhendo o modo de renderização de texto correto
Defina o modo de suavização de texto como D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE explicitamente. A qualidade da renderização do texto em escala de cinza é comparável ao ClearType, mas é muito mais rápida.
Cache
Use o cache de cena completa ou por bitmap primitivo, como com o desenho de outros primitivos.
Recortar uma forma arbitrária
A figura aqui mostra o resultado da aplicação de um clipe a uma imagem.
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));
Veja 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, ao chamar o método PushLayer, você não passa uma camada criada pelo aplicativo. Direct2D cria uma camada para você. Direct2D é capaz de gerenciar a alocação e a destruição desse recurso sem qualquer envolvimento do aplicativo. Isso permite que Direct2D reutilizem camadas internamente e apliquem otimizações de gerenciamento de recursos.
Em 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 Direct2D conteúdo em Windows 8, para obter mais informações sobre essa interface, consulte Dispositivos e contextos de dispositivo. Com a interface de contexto do dispositivo, você pode ignorar a chamada do método CreateLayer e, em seguida, passar NULL para o método ID2D1DeviceContext::P ushLayer . Direct2D gerencia automaticamente o recurso de camada e pode compartilhar recursos entre camadas e grafos de efeito.
Clipes alinhados ao eixo
Se a região a ser recortada estiver alinhada ao eixo da superfície de desenho, em vez de arbitrária. Esse caso é adequado para usar um retângulo de clipe em vez de uma camada. O ganho de desempenho é mais para geometria de alias do que geometria suavizada. Para obter mais informações sobre clipes alinhados ao eixo, consulte o tópico PushAxisAlignedClip .
Interoperabilidade de DXGI: evitar comutadores frequentes
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 opção entre o desenho Direct2D e o conteúdo do Direct3D afeta o desempenho.
Ao renderizar em uma superfície DXGI, Direct2D salva o estado dos dispositivos Direct3D durante a renderização e restaura-o quando a renderização é concluída. Toda vez que um lote de Direct2D renderização é concluído, o custo dessa economia e restauração e o custo de liberação de 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 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 deverá ser criado usando 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 com suporte e modos alfa.
Complexidade da cena
Quando você analisa pontos de acesso de desempenho em uma cena que será renderizada, saber se a cena está associada à taxa de preenchimento ou associar vértice pode fornecer informações úteis.
- Taxa de preenchimento: a taxa de preenchimento refere-se ao número de pixels que um gráfico cartão pode renderizar e gravar na memória de vídeo por segundo.
- Vértice Associado: uma cena é associada ao vértice quando contém muita geometria complexa.
Entender a complexidade da cena
Você pode analisar a complexidade da cena alterando o tamanho do destino de renderização. Se os ganhos de desempenho estiverem visíveis para uma redução proporcional no tamanho do destino de renderização, o aplicativo será associado à taxa de preenchimento. Caso contrário, a complexidade da cena é o gargalo de desempenho.
Quando uma cena é associada à 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 é associada ao vértice, reduza a complexidade da geometria. Mas lembre-se de que isso é feito às custas da qualidade da imagem. Portanto, uma decisão cuidadosa de compensação deve ser tomada entre a qualidade desejada e o desempenho necessário.
Melhorando o desempenho para aplicativos de impressão Direct2D
Direct2D oferece compatibilidade com impressão. Você pode enviar os mesmos comandos de desenho Direct2D (na forma de Direct2D listas de comandos) para o controle de impressão Direct2D para impressão, se não souber para quais dispositivos você está desenhando ou como o desenho é traduzido para impressão.
Você pode ajustar ainda mais o uso do controle de impressão Direct2D e seus comandos de desenho Direct2D para fornecer resultados de impressão com melhor desempenho.
O controle de impressão Direct2D gera mensagens de depuração quando vê um padrão de código Direct2D que leva a menor qualidade de impressão ou desempenho (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, você precisa habilitar Direct2D Camada de Depuração em seu código. Consulte Depurar Mensagens para obter instruções para habilitar a saída da mensagem de depuração.
Definir 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 manipula determinados comandos Direct2D e, por sua vez, afetam o desempenho geral.
- Modo de Subconjunto de Fonte: o Direct2D controle de impressão subconjuntos de recursos de fonte usados em cada página antes de enviar a página para ser impressa. Esse modo reduz o tamanho dos recursos de página necessários para imprimir. Dependendo do uso da fonte na página, você pode escolher diferentes modos de subconjunto de fonte para obter o melhor desempenho.
- D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT fornece 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 subconjuntar fontes.
- Para trabalhos de impressão curta com 1 ou 2 páginas, recomendamos D2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE , em que o Direct2D imprime subconjuntos de controle e insira recursos de fonte em cada página e descarte esse subconjunto de fonte 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 fonte 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 usam uma única fonte), recomendamos D2D1_PRINT_FONT_SUBSET_MODE_NONE, em que o controle de impressão Direct2D não subconjunta 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 reenviar.
- DPI de rasterização: quando o controle de impressão Direct2D precisa rasterizar comandos Direct2D durante a conversão Direct2D-XPS, 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 alterará o desempenho e a qualidade. Dependendo do uso de rasterização na página, você pode escolher DPIs de rasterização diferentes para obter 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 de 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 gerados por ele. Não recomendamos nenhum valor de DPI maior que 300, pois isso não introduzirá informações extras visualmente perceptíveis por olhos humanos.
- A DPI mais baixa pode significar melhor desempenho, mas também pode produzir uma qualidade mais baixa.
Evite usar determinados padrões de desenho Direct2D
Há diferenças entre o que 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 abre essas lacunas aproximando ou rasterizando primitivos Direct2D que o subsistema de impressão não dá suporte nativo. 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, ele não é ideal em todos os casos. É melhor não usar tais Direct2D primitivos e padrões tanto quanto possível para o caminho de impressão, ou para fazer sua rasterização onde você tem controle total da qualidade e do tamanho das imagens rasterizadas.
Aqui está uma lista de casos em que o desempenho e a qualidade da impressão não serão ideais e talvez você queira considerar a variação do caminho do código para o desempenho de impressão ideal.
- Evite usar o modo de combinação primitiva diferente de D2D1_PRIMITIVE_BLEND_SOURCEOVER.
- Evite usar modos de composição ao desenhar uma imagem diferente de D2D1_COMPOSITE_MODE_SOURCE_OVER e D2D1_COMPOSITE_MODE_DESTINATION_OVER.
- Evite desenhar um arquivo meta GDI.
- Evite enviar por push um recurso de camada que copie o plano de fundo de origem (chamando PushLayer com a passagem de D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND para o struct D2D1_LAYER_PARAMETERS1 ).
- Evite criar Pincel de Bitmap ou Pincel de Imagem com D2D1_EXTEND_MODE_CLAMP. Recomendamos que você use D2D1_EXTEND_MODE_MIRROR se não se importar com pixels fora da imagem associada (por exemplo, a imagem anexada ao pincel é conhecida por ser maior que a região de destino preenchida).
- Evite desenhar Bitmaps com transformações de perspectiva.
Desenhar texto de maneira direta e simples
Direct2D tem várias otimizações ao renderizar textos a serem exibidos para melhor desempenho e/ou melhor qualidade visual. Mas nem todas as otimizações melhoram o desempenho e a qualidade da impressão, pois a impressão no papel geralmente está em um DPI muito maior, e a impressão não precisa acomodar cenários como animação. Portanto, recomendamos que você desenhe diretamente o texto ou os glifos originais e evite qualquer uma das otimizações a seguir ao criar a lista de comandos para impressão.
- Evite desenhar texto com o método FillOpacityMask .
- Evite desenhar texto no Modo Aliased.
Desenhar os bitmaps originais quando possível
Se o bitmap de destino for um JPEG, PNG, TIFF ou JPEG-XR, você pode criar um bitmap WIC de um arquivo de disco ou de um fluxo na memória e, em seguida, criar um bitmap Direct2D desse bitmap WIC usando ID2D1DeviceContext::CreateBitmapFromWicBitmap e, por fim, 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 a decodificação de bitmap redundantes) e melhor qualidade de impressão (quando metadados, como perfis de cor, no bitmap serão preservados).
Desenhar o bitmap original oferece o seguinte benefício para aplicativos.
- Em geral, Direct2D impressão preserva as informações originais (sem perda ou ruído) até o final do pipeline, especialmente quando os aplicativos não sabem (ou não querem saber) os detalhes do pipeline de impressão (como em qual impressora ele está imprimindo, 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 96dpi em uma impressora 600dpi).
- Em determinados casos, passar as imagens originais é a única maneira de honrar a alta fidelidade (como perfis de cores inseridos).
No entanto, um que você não pode optar por essa otimização porque:
- Ao consultar informações da impressora e rasterização antecipada, você pode rasterizar o conteúdo por conta própria com controle total da aparência final no papel.
- Em certos casos, a rasterização precoce pode realmente melhorar o desempenho de ponta a ponta de um aplicativo (como imprimir fotos do tamanho de carteiras).
- Em determinados casos, passar os bitmaps originais exige uma alteração significativa da arquitetura de código existente (como o carregamento de atraso de imagem e os caminhos de atualização de recursos encontrados em determinados aplicativos).
Conclusão
Embora Direct2D seja acelerada por hardware e seja destinada a alto desempenho, você deve usar os recursos corretamente para maximizar a taxa de transferência. As técnicas que examinamos aqui são derivadas do estudo de cenários comuns e podem não se aplicar a todos os cenários de aplicativo.