\\ Home : Articoli : Stampa
Lost Device
Di RobyDx (del 27/01/2007 @ 12:40:41, in DirectX9, linkato 1877 volte)

Un fattore molto importante nei giochi fullscreen è la stabilità. Situazioni come la pressione del tasto windows, la riduzione ad icona della finestra o la presa di possesso dello schermo da parte di un'altra applicazione possono interrompere la modalità fullscreen e generare errori. Questo non è il comportamento di un programma serio. Non potete costringere il giocatore a dover ricominciare per un banale errore e tanto meno non potete obbligare il giocatore ad uscire dal gioco perchè deve scaricare un'istante la posta. In definitiva dovete permettere al giocatore di ridurre ad icona il gioco fullscreen senza che questi generi errori. Questa situazione è chiamata Lost Device.

Il device si considera perso quando avviene una delle seguenti situazioni:

  • Fullscreen ridotto ad icona
  • Due applicazioni attivano il fullscreen
  • un programma directX in finestra subisce un cambio impostazioni dello schermo

    La situazione di lostdevice è un errore che genera il device durante l'esecuzione dell'istruzione present

    Try
     device.Present()
    Catch e As DeviceLostException
    'qui il device è perso
    End Try

    Quando l'istruzione solleva l'eccezione di tipo DeviceLostException significa che è avvenuta una delle situazioni descritte. Grazie alla gestione degli errori il nostro programma continuerà a girare tranquillamente e ogni volta salterà la presentazione della scena. Questo non risolve però tutti i problemi perchè nel momento in cui riaprirete la finestra si genererà un altro errore di tipo differente che bloccherà il programma. Il motivo di questo è che con la perdita del device abbiamo perso tutti i settaggi inseriti rendendo inutilizzabile ogni istruzione di rendering. Occorrerà quindi eseguire un'istruzione chiamata reset che distruggerà tutte le impostazioni e le reinizializzerà.

     
    Reset device


    Innanzitutto una bella critica a chi ha progettato le DirectX9:


      1. poteva prevedere una gestione più semplice del problema
      2. poteva spiegare per bene come risolvere il problema in managed DirectX


    Infatti per la particolare struttura date alle classi occorre ridefinire gli eventi generati dal device dichiarandoli nel codice. Aggiungete alla creazione del device questi handler. Questi servono per dichiarare gli eventi in una classe. In questo caso il Me significa che l'evento verrà scritta nel form (perchè dichiarato lì) ma potrete definire il codice dove volete.

    AddHandler device.DeviceLost, AddressOf
    Me.InvalidateDeviceObjects
    AddHandler device.DeviceReset, AddressOf Me.RestoreDeviceObjects
    AddHandler device.Disposing, AddressOf Me.DeleteDeviceObjects
    AddHandler device.DeviceResizing, AddressOf Me.EnvironmentResized

    e nel form dichiarate questi eventi

    Public Sub EnvironmentResized(ByVal sender As Object, ByVal e As_
    System.ComponentModel.CancelEventArgs)
    'ridimensionamento device
        'annullare l'evento per evitare tentativi da parte di DirectX di reinizializzare
        e.Cancel = True
    End Sub 'EnvironmentResized
    Sub deleteDeviceObjects(ByVal sender As Object, ByVal e As EventArgs)
    'qui va inserito il codice per cancellare tutto
    End Sub
    Sub restoreDeviceObjects(ByVal sender As Object, ByVal e As EventArgs)
    'qui quello per reinizializzare
    End Sub
    Sub invalidateDeviceObjects(ByVal sender As Object, ByVal e As EventArgs)
    '
    End Sub

    Questi eventi vengono chiamati da directX quando crea o distrugge uno stato (quindi anche in inizializzazione). Nell'evento delete dovrete mettere il codice per distruggere il materiale non gestito (dopo ci arrivo), in restore il codice per ricaricare i settaggi e invalidate quello che deve verificarsi quando il device non è valido. La prima è quella più importante: l'environmentResize si verifica quando il device viene questo viene ridimensionato in seguito ad un reset. Se si è generata l'eccezione device lost allora occorre verificare se il device è pronto per tornare operativo tramite un'istruzione di reset.

    Try
       device.TestCooperativeLevel()
    Catch e As DeviceLostException
    'nulla
    Catch e As DeviceNotResetException
    'resettiamo
       device.Reset(settaggio)
    End Try

    L'operazione TestCooperativeLevel fa un test del device e genera due tipi di eccezione:
    DeviceLostException che indica la permanenza dello stato di DeviceLost
    DeviceNotResetException che indica che il device è pronto per un reset.
    In questo caso eseguiamo l'istruzione Reset del device

    device.Reset(settaggio)

    Il parametro settaggio è un PresentParameters, lo stesso che abbiamo usato per creare il device. Da questo momento il device ritorna operativo e funzionale ma ha perso molti dati che dobbiamo ripristinare.

      3. Matrici world, view e projection
      4. Settaggi per texture e renderState
      5. Stato degli shader
      6. Luci
      7. Oggetti non gestiti

    L'ultimo è il problema principale. Quando creiamo texture, mesh e superfici settiamo sempre il parametro POOL. Questo indica la posizione in memoria (se della scheda video o della RAM) in cui verranno depositati i dati. Tutto quello inserito in memoria video è persa e nell'evento delete dovrà essere distrutto e ricaricato nell'evento restore. Per questo il settaggio migliore è Managed che terrà una copia di sicurezza in RAM e non dovrà quindi essere distrutta e ricreata. Testo, shader e tutto ciò che non ha settaggi di gestione POOL non devono essere ricreati. Tenete quindi in memoria i settaggi in modo da recuperarli velocemente.
    Il device è ora di nuovo pronto a tutto.

    Cambi di risoluzione

    L'istruzione reset può essere usata non solo per reimpostare il device ma anche per cambiare risoluzione dello schermo. Se la usate inserendo un settaggio differente (purchè valido ovviamente) potrete cambiare al volo la risoluzione del gioco (cosa che molti giochi famosi neanche fanno). Questo è molto utile quando nello schermo dello opzioni volete impostare le opzioni come ad esempio alcune opzioni di risoluzione o la possibilità di scegliere o meno l'antialiasing.

    In finestra

    Il reset deve essere chiamato anche quando la finestra viene ridimensionata. In questo modo l'immagine non scomparirà o non perderà definizione (a secondo del modello di scheda video) quando allargherete la finestra. Non vi rimane che fare pratica.
    Ecco l'esempio.

    Esempio - VB.Net

    Esempio 1 - C#

    Esempio 2 - C#