Condividi tramite


Miglioramento delle prestazioni delle app Direct2D

Anche se Direct2D è accelerato dall'hardware ed è destinato a prestazioni elevate, è necessario usare correttamente le funzionalità per ottimizzare la velocità effettiva. Le tecniche illustrate di seguito sono derivate dallo studio di scenari comuni e potrebbero non essere applicabili a tutti gli scenari di app. Pertanto, un'attenta comprensione del comportamento delle app e degli obiettivi di prestazioni può aiutare a ottenere i risultati desiderati.

Utilizzo delle risorse

Una risorsa è un'allocazione di qualche tipo, in memoria video o di sistema. Bitmap e pennelli sono esempi di risorse.

In Direct2D le risorse possono essere create sia nel software che nell'hardware. La creazione e l'eliminazione delle risorse nell'hardware sono operazioni costose perché richiedono un sovraccarico elevato per la comunicazione con la scheda video. Vediamo come Direct2D renderizza il contenuto in una destinazione.

In Direct2D tutti i comandi di rendering sono racchiusi tra una chiamata a BeginDraw e una chiamata a EndDraw. Queste chiamate vengono effettuate a un target di rendering. È necessario chiamare il metodo BeginDraw prima di chiamare le operazioni di rendering. Dopo aver chiamato BeginDraw , un contesto in genere crea un batch di comandi di rendering, ma ritarda l'elaborazione di questi comandi fino a quando una di queste istruzioni non è vera:

  • EndDraw è avvenuto. Quando viene chiamato EndDraw, le operazioni di disegno in batch vengono completate e restituisce lo stato dell'operazione.
  • Si effettua una chiamata esplicita a Flush: il metodo Flush fa sì che il batch venga elaborato e che vengano eseguiti tutti i comandi in sospeso.
  • Il buffer che contiene i comandi di rendering è pieno. Se questo buffer diventa pieno prima che vengano soddisfatte le due condizioni precedenti, i comandi di rendering vengono scaricati.

Finché le primitive non vengono eliminate, Direct2D mantiene riferimenti interni alle risorse corrispondenti, ad esempio bitmap e pennelli.

Riutilizzare le risorse

Come già accennato, la creazione e l'eliminazione delle risorse sono costose sull'hardware. Riutilizzare quindi le risorse quando possibile. Prendiamo l'esempio di creazione bitmap nello sviluppo di giochi. In genere, le bitmap che costituiscono una scena in un gioco vengono create contemporaneamente con tutte le diverse varianti necessarie per il rendering da fotogramma a fotogramma successivo. Al momento del rendering effettivo e del ri-rendering della scena, queste bitmap vengono riutilizzate anziché ricreate.

Nota

Non è possibile riutilizzare le risorse per l'operazione di ridimensionamento della finestra. Quando una finestra viene ridimensionata, alcune risorse dipendenti dalla scalabilità, ad esempio le destinazioni di rendering compatibili e possibilmente alcune risorse di livello devono essere ricreate perché il contenuto della finestra deve essere ridisegnato. Questo può essere importante per mantenere la qualità complessiva della scena sottoposta a rendering.

 

Limitare l'uso dello sciacquone

Poiché il metodo Flush fa sì che i comandi di rendering in batch vengano elaborati, è consigliabile non usarlo. Per gli scenari più comuni, lasciare direct2D per la gestione delle risorse.

Bitmap

Come accennato in precedenza, la creazione e l'eliminazione delle risorse sono operazioni molto costose nell'hardware. Una bitmap è un tipo di risorsa usata spesso. La creazione di bitmap sulla scheda video è costosa. Il riutilizzo può aiutare a velocizzare l'applicazione.

Creare bitmap di grandi dimensioni

Le schede video hanno in genere dimensioni minime di allocazione della memoria. Se viene richiesta un'allocazione inferiore a questa, viene allocata una risorsa di questa dimensione minima e la memoria in eccedenza viene sprecata e non disponibile per altri elementi. Se sono necessarie molte bitmap di piccole dimensioni, una tecnica migliore consiste nell'allocare una bitmap di grandi dimensioni e archiviare tutto il contenuto di bitmap di piccole dimensioni in questa bitmap di grandi dimensioni. È quindi possibile leggere le sottoaree della bitmap più grande in cui sono necessarie le bitmap più piccole. Spesso, è consigliabile includere spaziatura interna (pixel neri trasparenti) tra le piccole bitmap per evitare qualsiasi interazione tra le immagini più piccole durante le operazioni. Questa operazione è nota anche come atlas e offre il vantaggio di ridurre il sovraccarico di creazione delle bitmap e lo spreco di memoria di allocazioni di bitmap di piccole dimensioni. È consigliabile mantenere la maggior parte delle bitmap almeno 64 KB e limitare il numero di bitmap inferiori a 4 KB.

Creare un atlas di bitmap

Esistono alcuni scenari comuni per cui un atlas bitmap può essere usato molto bene. Le bitmap di piccole dimensioni possono essere archiviate all'interno di una bitmap di grandi dimensioni. Queste piccole bitmap possono essere estratte dalla bitmap più grande quando sono necessarie specificando il rettangolo di destinazione. Ad esempio, un'applicazione deve disegnare più icone. Tutte le bitmap associate alle icone possono essere caricate in una bitmap di grandi dimensioni in primo piano. E in fase di rendering, possono essere recuperati dalla bitmap di grandi dimensioni.

Nota

Una bitmap Direct2D creata in memoria video è limitata alle dimensioni massime della bitmap supportate dalla scheda in cui è archiviata. La creazione di una bitmap più grande di quella potrebbe generare un errore.

 

Nota

A partire da Windows 8, Direct2D include un effetto atlas che può semplificare questo processo.

 

Creare bitmap condivise

La creazione di bitmap condivise consente ai chiamanti avanzati di creare oggetti bitmap Direct2D supportati direttamente da un oggetto esistente, già compatibile con la destinazione di rendering. In questo modo si evita di creare più superfici e di ridurre il sovraccarico delle prestazioni.

Nota

Le bitmap condivise sono in genere limitate a destinazioni software o a destinazioni interoperabili con DXGI. Usare CreateBitmapFromDxgiSurface, CreateBitmapFromWicBitmape i metodi createSharedBitmap per creare bitmap condivise.

 

Copiare bitmap

La creazione di una superficie DXGI è un'operazione costosa, quindi riutilizzare le superfici esistenti quando è possibile. Anche nel software, se una bitmap è principalmente nel formato desiderato, ad eccezione di una piccola parte, è preferibile aggiornare tale parte piuttosto che rigenerare l'intera bitmap e ricreare tutto. Sebbene sia possibile usare CreateCompatibleRenderTarget per ottenere gli stessi risultati, il rendering è in genere un'operazione molto più costosa rispetto alla copia. Ciò è dovuto al fatto che, per migliorare la località della cache, l'hardware non archivia effettivamente una bitmap nello stesso ordine di memoria a cui viene indirizzata la bitmap. Al contrario, la bitmap potrebbe essere swizzled. La trasformazione è celata alla CPU dal driver (che è lento e utilizzato solo per prodotti di fascia bassa) o dal gestore della memoria sulla GPU. A causa dei vincoli sulla modalità di scrittura dei dati in una destinazione di rendering durante il rendering, le destinazioni di rendering in genere non vengono riorganizzate (swizzled) o vengono riorganizzate in modo meno ottimale di quanto si potrebbe ottenere se si sa che non sarà mai necessario eseguire il rendering sulla superficie. Pertanto, i metodi CopyFrom* vengono forniti per copiare rettangoli da un'origine alla bitmap Direct2D.

CopyFrom può essere usato in una delle tre forme seguenti:

Usare bitmap affiancate su dashing

Il rendering di una linea tratteggiata è un'operazione molto costosa a causa dell'elevata qualità e accuratezza dell'algoritmo sottostante. Per la maggior parte dei casi che non coinvolgono geometrie rectilineari, lo stesso effetto può essere generato più velocemente usando bitmap affiancate.

Linee guida generali per il rendering di contenuto statico complesso

Memorizza nella cache il contenuto se esegui il rendering dello stesso contenuto fotogramma dopo fotogramma, soprattutto quando la scena è complessa.

Esistono tre tecniche di memorizzazione nella cache che è possibile usare:

  • Memorizzazione completa nella cache di una scena usando una bitmap a colori.
  • Per primitiva memorizzazione nella cache usando una bitmap A8 e il metodo FillOpacityMask.
  • Memorizzazione nella cache per primitiva usando le realizzazioni geometriche.

Esaminiamo ognuno di questi dettagli in modo più dettagliato.

Caching completo della scena con una bitmap a colori

Quando si esegue il rendering di contenuto statico, in scenari come l'animazione, creare un'altra bitmap a colori intero anziché scrivere direttamente nella bitmap dello schermo. Salvare la destinazione corrente, impostare la destinazione sulla bitmap intermedia ed eseguire il rendering del contenuto statico. Tornare quindi alla bitmap dello schermo originale e disegnare la bitmap intermedia.

Ecco un esempio:

// 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());

Questo esempio utilizza bitmap intermedie per la memorizzazione nella cache e commuta la bitmap a cui fa riferimento il contesto del dispositivo durante il rendering. In questo modo si evita la necessità di creare una destinazione di rendering compatibile per lo stesso scopo.

Cache primitivo utilizzando una bitmap A8 e il metodo FillOpacityMask

Quando la scena completa non è statica, ma è costituita da elementi statici come la geometria o il testo, è possibile utilizzare una tecnica di caching per ciascun elemento primitivo. Questa tecnica mantiene le caratteristiche antialiasing della primitiva memorizzata nella cache e funziona con la modifica dei tipi di pennello. Usa una bitmap A8 in cui A8 è un tipo di formato pixel che rappresenta un canale alfa con 8 bit. Le bitmap A8 sono utili per disegnare geometria/testo come maschera. Quando è necessario modificare l'opacità del contenuto statico, anziché modificare il contenuto stesso, è possibile traslare, ruotare, inclinare o ridimensionare la maschera.

Ecco un esempio:

// 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);

Memorizzazione nella cache per singola primitiva utilizzando le realizzazioni geometriche

Un'altra tecnica di memorizzazione nella cache per le primitive, denominata realizzazione della geometria, offre maggiore flessibilità quando si lavora con la geometria. Quando si desidera disegnare ripetutamente geometrie aliased o anti-alias, è più veloce convertirle in realizzazioni geometriche e disegnare ripetutamente queste realizzazioni rispetto a disegnare ripetutamente le geometrie stesse. Le realizzazioni geometriche consumano in genere meno memoria rispetto alle maschere di opacità (soprattutto per le geometrie di grandi dimensioni) e sono meno sensibili alle modifiche in scala. Per altre informazioni, vedere Cenni preliminari sulla realizzazione della geometria.

Ecco un esempio:

    // 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();

Rendering della geometria

Usare una primitiva di disegno specifica invece della geometria grafica

Usare chiamate di disegno più specificheprimitive, come DrawRectangle, anziché chiamate DrawGeometry generiche. Ciò avviene perché con DrawRectangle, la geometria è già nota in modo che il rendering sia più veloce.

Rendering della geometria statica

Negli scenari in cui la geometria è statica, usare le tecniche di caching per primitiva illustrate in precedenza. Le maschere di opacità e le realizzazione della geometria possono migliorare notevolmente la velocità di rendering delle scene che contengono geometria statica.

Usare un contesto di dispositivo multithreading

Le applicazioni che prevedono di eseguire il rendering di quantità significative di contenuto geometrico complesso devono prendere in considerazione la possibilità di specificare il flag di D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTI_THREADED_OPTIMIZATIONS durante la creazione di un contesto di dispositivo Direct2D. Quando si specifica questo flag, Direct2D distribuirà il rendering in tutti i core logici presenti nel sistema, riducendo significativamente il tempo di rendering complessivo.

Note:

  • A partire da Windows 8.1, questo flag influisce solo sul rendering della geometria del percorso. Non impatta le scene che contengono solo altri tipi primitivi, come testo, bitmap o realizzazioni geometriche.
  • Questo flag non ha alcun impatto anche quando si esegue il rendering nel software (ad esempio quando si esegue il rendering con un dispositivo Direct3D WARP). Per controllare il multithreading software, i chiamanti dovrebbero usare il flag D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS durante la creazione del dispositivo Direct3D WARP.
  • La specifica di questo flag può aumentare il picco di lavoro durante il rendering e può anche aumentare la contesa di thread nelle applicazioni che sfruttano già l'elaborazione multithreading.

Disegno di testo con Direct2D

La funzionalità di rendering del testo Direct2D è disponibile in due parti. La prima parte, esposta come ID2D1RenderTarget::DrawText e ID2D1RenderTarget::DrawTextLayout, consente al chiamante di passare un parametro di stringa e formattazione oppure un oggetto di layout di testo DWrite per supportare più formati. Questo deve essere adatto per la maggior parte dei chiamanti. Il secondo modo per eseguire il rendering del testo, esposto come metodo ID2D1RenderTarget::D rawGlyphRun, fornisce la rasterizzazione per i clienti che già conoscono la posizione dei glifi di cui vogliono eseguire il rendering. Le due regole generali seguenti consentono di migliorare le prestazioni del testo quando si disegna in Direct2D.

DrawTextLayout contro DrawText

Sia DrawText che DrawTextLayout consentono a un'applicazione di eseguire facilmente il rendering del testo formattato dall'API directWrite. DrawTextLayout disegna un oggetto DWriteTextLayout esistente nel RenderTarget, e DrawText costruisce un layout DirectWrite per il chiamante, basandosi sui parametri passati. Se è necessario eseguire il rendering dello stesso testo più volte, utilizzare DrawTextLayout anziché DrawText, perché DrawText crea un layout ogni volta che viene chiamato.

Scelta della modalità di rendering del testo corretta

Impostare la modalità antialias di testo su D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE in modo esplicito. La qualità del rendering del testo in scala di grigi è paragonabile a ClearType, ma è molto più veloce.

Memorizzazione nella cache

Utilizzare la memorizzazione nella cache bitmap a livello di scena completa o per ogni primitiva, come avviene per il disegno di altre primitive.

Ritaglio di una forma arbitraria

La figura mostra il risultato dell'applicazione di una clip a un'immagine.

un'immagine che mostra un esempio di un'immagine prima e dopo una clip.

È possibile ottenere questo risultato usando i livelli con una maschera geometrica o il metodo FillGeometry con un pennello di opacità.

Ecco un esempio che usa un livello:

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

Di seguito è riportato un esempio che usa il metodo 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()); 

In questo esempio di codice, quando chiami il metodo PushLayer, non passi un livello creato dall'app. Direct2D crea automaticamente un livello. Direct2D è in grado di gestire l'allocazione e la distruzione di questa risorsa senza alcun coinvolgimento dell'app. In questo modo Direct2D può riutilizzare i livelli internamente e applicare ottimizzazioni di gestione delle risorse.

In Windows 8 sono state apportate molte ottimizzazioni all'utilizzo dei livelli e ti consigliamo di provare a usare le API di livello invece di FillGeometry quando possibile.

PushLayer in Windows 8

L'interfacciaID2D1DeviceContextè derivata dall'interfacciaID2D1RenderTargete rappresenta la chiave per visualizzare il contenuto Direct2D in Windows 8. Per altre informazioni su questa interfaccia, vedere Dispositivi e contesti di dispositivo. Con l'interfaccia del contesto di dispositivo, è possibile ignorare la chiamata al metodoCreateLayere quindi passare NULL al metodo ID2D1DeviceContext::PushLayer. Direct2D gestisce automaticamente la risorsa livello e può condividere le risorse tra i livelli e i grafici degli effetti.

Clip allineate agli assi

Se l'area da ritagliare è allineata all'asse della superficie di disegno, anziché arbitraria. Questo caso è adatto all'uso di un rettangolo di ritaglio anziché di un livello. Il miglioramento delle prestazioni è maggiore per la geometria con alias che per la geometria antialiased. Per ulteriori informazioni sulle clip allineate sull'asse, vedi l'argomento PushAxisAlignedClip.

Interoperabilità DXGI: evitare cambi frequenti

Direct2D può interagire perfettamente con le superfici Direct3D. Questo è molto utile per la creazione di applicazioni che eseguono il rendering di una combinazione di contenuto 2D e 3D. Tuttavia, ogni passaggio tra il disegno di contenuto Direct2D e Direct3D influisce sulle prestazioni.

Quando si esegue il rendering in una superficie DXGI, Direct2D salva lo stato dei dispositivi Direct3D durante il rendering e lo ripristina al termine del rendering. Ogni volta che viene completato un batch di rendering Direct2D, il costo di questo salvataggio e ripristino e il costo dello svuotamento di tutte le operazioni 2D viene pagato e, tuttavia, il dispositivo Direct3D non viene svuotato. Pertanto, per migliorare le prestazioni, limitare il numero di commutatori di rendering tra Direct2D e Direct3D.

Informarsi sul formato dei pixel

Quando si crea una destinazione di rendering, è possibile usare la struttura D2D1_PIXEL_FORMAT specificare il formato pixel e la modalità alfa usati dalla destinazione di rendering. Un canale alfa fa parte del formato pixel che specifica il valore di copertura o le informazioni sull'opacità. Se una destinazione di rendering non usa il canale alfa, deve essere creata usando la modalità D2D1_ALPHA_MODE_IGNORE alfa. Ciò consente di risparmiare tempo per il rendering di un canale alfa non necessario.

Per altre informazioni sui formati pixel e sulle modalità alfa, vedere Formati pixel supportati e modalità alfa.

Complessità della scena

Analizzando i punti critici delle prestazioni in una scena che verrà renderizzata, sapere se la scena è vincolata dal tasso di riempimento o dai vertici può fornire informazioni utili.

  • Frequenza di riempimento: la frequenza di riempimento fa riferimento al numero di pixel di cui una scheda grafica può eseguire il rendering e la scrittura nella memoria video al secondo.
  • Limite del vertice: una scena è vincolata ai vertici quando contiene molta geometria complessa.

Comprendere la complessità della scena

È possibile analizzare la complessità della scena modificando le dimensioni della destinazione di rendering. Se i miglioramenti delle prestazioni sono visibili per una riduzione proporzionale delle dimensioni della destinazione di rendering, allora l'applicazione è limitata dal fill-rate. Altrimenti, la complessità della scena può costituire un collo di bottiglia per le prestazioni.

Quando una scena è limitata dalla frequenza di riempimento, ridurre le dimensioni della destinazione di rendering può migliorare le prestazioni. Ciò è dovuto al fatto che il numero di pixel di cui eseguire il rendering verrà ridotto proporzionalmente con le dimensioni della destinazione di rendering.

Quando una scena è vincolata dai vertici, ridurre la complessità della geometria. Ma ricorda che questo è fatto a scapito della qualità dell'immagine. Pertanto, è necessario prendere una attenta decisione di compromesso tra la qualità desiderata e le prestazioni necessarie.

Miglioramento delle prestazioni per le app di stampa Direct2D

Direct2D offre compatibilità con la stampa. È possibile inviare gli stessi comandi di disegno Direct2D (sotto forma di elenchi di comandi Direct2D) al controllo di stampa Direct2D per la stampa, se non si conoscono i dispositivi a cui si sta disegnando o il modo in cui il disegno viene convertito nella stampa.

È possibile ottimizzare ulteriormente l'utilizzo del Direct2D controllo di stampa e dei comandi di disegno Direct2D per offrire risultati di stampa migliori.

Il Direct2D il controllo di stampa restituisce messaggi di debug quando vede un modello di codice Direct2D che porta a una qualità o prestazioni di stampa inferiori (ad esempio, modelli di codice elencati più avanti in questo argomento) per ricordare dove è possibile evitare problemi di prestazioni. Per visualizzare i messaggi di debug, è necessario abilitare livello di debug Direct2D nel codice. Per istruzioni su come abilitare l'output dei messaggi di debug, vedere Debug Messages.

Impostare i valori di proprietà corretti quando si crea il controllo di stampa D2D

Sono disponibili tre proprietà che è possibile impostare quando si crea il controllo di stampa Direct2D. Due di queste proprietà influiscono sul modo in cui il controllo di stampa Direct2D gestisce determinati comandi Direct2D e a sua volta influisce sulle prestazioni complessive.

  • Modalità subset di tipi di carattere: il controllo di stampa Direct2D crea sottoinsiemi delle risorse di font utilizzate in ogni pagina prima di inviare la pagina alla stampa. Questa modalità riduce le dimensioni delle risorse di pagina necessarie per la stampa. A seconda dell'utilizzo dei tipi di carattere nella pagina, è possibile scegliere diverse modalità di subset dei tipi di carattere per ottenere prestazioni ottimali.
    • D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT offre le migliori prestazioni di stampa nella maggior parte dei casi. Quando è impostato su questa modalità, il controllo di stampa Direct2D utilizza una strategia euristica per decidere quando suddividere i font.
    • Per i lavori di stampa brevi con 1 o 2 pagine, è consigliabile D2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE , dove il controllo di stampa Direct2D crea un subset e incorpora le risorse dei tipi di carattere in ogni pagina, e successivamente elimina quel subset di caratteri dopo il completamento della stampa della pagina. Questa opzione assicura che ogni pagina possa essere stampata immediatamente dopo la generazione, ma aumenta leggermente le dimensioni delle risorse di pagina necessarie per la stampa (con sottoinsiemi di caratteri di grandi dimensioni).
    • Per un processo di stampa con molte pagine di testo e dimensioni di carattere ridotte (ad esempio 100 pagine di testo che usano un singolo tipo di carattere), è consigliabile D2D1_PRINT_FONT_SUBSET_MODE_NONE, dove il controllo di stampa Direct2D non suddivide le risorse dei caratteri; invia invece le risorse originali del tipo di carattere insieme alla pagina che usa prima il tipo di carattere, e riutilizza le risorse per le pagine successive senza inviarle di nuovo.
  • DPI di rasterizzazione: quando il controllo di stampa Direct2D deve rasterizzare i comandi Direct2D durante la conversione Direct2D-XPS, usa questo valore DPI per la rasterizzazione. In altre parole, se la pagina non contiene contenuti rasterizzati, l'impostazione di valori DPI non cambierà le prestazioni e la qualità. A seconda dell'utilizzo della rasterizzazione nella pagina, è possibile scegliere diversi DPI di rasterizzazione per un migliore equilibrio tra fedeltà e prestazioni.
    • 150 è il valore predefinito se non si specifica un valore quando si crea il controllo Direct2D stampa, che rappresenta il miglior equilibrio tra qualità di stampa e prestazioni di stampa nella maggior parte dei casi.
    • I valori DPI più elevati comportano in genere una migliore qualità di stampa (come in dettagli più conservati) ma prestazioni inferiori a causa delle bitmap più grandi generate. Non è consigliabile alcun valore DPI maggiore di 300 perché non introduce informazioni aggiuntive visivamente percepibili dagli occhi umani.
    • Un valore DPI inferiore può comportare prestazioni migliori, ma può anche produrre una qualità inferiore.

Evitare di usare determinati modelli di disegno Direct2D

Esistono differenze tra ciò che Direct2D può rappresentare visivamente e ciò che il sottosistema di stampa può gestire e trasportare lungo l'intera pipeline di stampa. Il controllo di stampa Direct2D consente di colmare tali lacune tramite un'approssimazione o la rasterizzazione di primitive Direct2D che il sottosistema di stampa non supporta in modo nativo. Tale approssimazione comporta in genere una fedeltà di stampa inferiore, prestazioni di stampa inferiori o entrambe. Pertanto, anche se un cliente può usare gli stessi modelli di disegno sia per il rendering dello schermo che per la stampa, non è ideale in tutti i casi. È consigliabile non usare tali primitive e modelli Direct2D il più possibile per il percorso di stampa o per eseguire la rasterizzazione in cui si ha il controllo completo della qualità e delle dimensioni delle immagini rasterizzate.

Di seguito è riportato un elenco di casi in cui le prestazioni di stampa e la qualità non saranno ideali e si potrebbe voler prendere in considerazione la variazione del percorso del codice per ottenere prestazioni di stampa ottimali.

  • Evitare di usare una modalità di fusione primitiva che sia differente da D2D1_PRIMITIVE_BLEND_SOURCEOVER.
  • Evitare di usare le modalità di composizione quando si disegna un'immagine diversa da D2D1_COMPOSITE_MODE_SOURCE_OVER e D2D1_COMPOSITE_MODE_DESTINATION_OVER.
  • Evitare di disegnare un meta file GDI.
  • Evitare di eseguire il push di una risorsa di livello che copia lo sfondo di origine (chiamando PushLayer e passando D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND allo struct D2D1_LAYER_PARAMETERS1).
  • Evitare di creare un pennello bitmap o un pennello immagine con D2D1_EXTEND_MODE_CLAMP. Ti consigliamo di usare D2D1_EXTEND_MODE_MIRROR se non ti interessa affatto i pixel al di fuori dell'immagine associata (ad esempio, l'immagine associata al pennello è nota per essere più grande dell'area di destinazione riempita).
  • Evitare di disegnare bitmap con trasformazioni prospettiche .

Disegnare testo in modo diretto e semplice

Direct2D offre diverse ottimizzazioni durante il rendering dei testi da visualizzare per ottenere prestazioni migliori e/o una migliore qualità visiva. Ma non tutte le ottimizzazioni migliorano le prestazioni di stampa e la qualità poiché la stampa su carta è in genere in un dpi molto più elevato e la stampa non deve soddisfare scenari come l'animazione. Pertanto, è consigliabile disegnare direttamente il testo o i glifi originali ed evitare le ottimizzazioni seguenti durante la creazione dell'elenco dei comandi per la stampa.

  • Evitare di disegnare testo con il metodo FillOpacityMask.
  • Evitare di disegnare testo in modalità con alias.

Disegnare le bitmap originali, quando possibile

Se la bitmap di destinazione è una bitmap JPEG, PNG, TIFF o JPEG-XR, è possibile creare una bitmap WIC da un file disco o da un flusso in memoria, quindi creare una bitmap Direct2D da tale bitmap WIC usando ID2D1DeviceContext::CreateBitmapFromWicBitmape infine passare direttamente la bitmap Direct2D al controllo di stampa Direct2D senza ulteriori modifiche. In questo modo, il controllo di stampa Direct2D è in grado di riutilizzare il flusso bitmap, che in genere porta a prestazioni di stampa migliori (ignorando la codifica e decodifica bitmap ridondanti) e una migliore qualità di stampa (quando i metadati, ad esempio i profili di colore, nella bitmap verranno mantenuti).

Il disegno della bitmap originale offre il vantaggio seguente per le applicazioni.

  • In generale, Direct2D stampa mantiene le informazioni originali (senza perdita o rumore) fino alla fine della pipeline, soprattutto quando le app non conoscono (o non vogliono sapere) i dettagli della pipeline di stampa (ad esempio la stampante su cui sta stampando, qual è la stampante di destinazione e così via).
  • In molti casi, ritardare la rasterizzazione bitmap significa prestazioni migliori (ad esempio quando si stampa una foto 96dpi in una stampante da 600dpi).
  • In alcuni casi, il passaggio delle immagini originali è l'unico modo per rispettare l'alta fedeltà (come i profili di colore incorporati).

Tuttavia, non è possibile optare per tale ottimizzazione perché:

  • Eseguendo query sulle informazioni sulla stampante e sulla rasterizzazione anticipata, è possibile rasterizzare il contenuto stesso con il controllo completo dell'aspetto finale su carta.
  • In alcuni casi, la rasterizzazione anticipata potrebbe effettivamente migliorare le prestazioni end-to-end di un'app (ad esempio la stampa di foto di dimensioni portafogli).
  • In alcuni casi, il passaggio delle bitmap originali richiede una modifica significativa dell'architettura del codice esistente ,ad esempio il ritardo del caricamento delle immagini e i percorsi di aggiornamento delle risorse presenti in determinate applicazioni.

Conclusione

Anche se Direct2D è accelerato dall'hardware ed è destinato a prestazioni elevate, è necessario usare correttamente le funzionalità per ottimizzare la velocità effettiva. Le tecniche esaminate sono derivate dallo studio di scenari comuni e potrebbero non essere applicabili a tutti gli scenari applicativi.