La gpu_mem_object è la classe base di gestione degli oggetti di memoria creati su un context OpenCL: da essa derivano tutte le classi di i/o di dati verso i kernel; gpu_mem_object gestisce alcune proprietà comuni e definisce le funzioni virtuali, che possono essere riscritte per le classi derivate.
Perchè questa classe?
la definizione del passaggio di parametri ad un kernel può essere particolarmente complesso, dovendo spesso trasferire e/o ricevere dati la cui sequenza può essere onerosa da gestire; le classi derivate da gpu_mem_object sono state progettate per standardizzare le modalità di i/o su un kernel, quando le informazioni gestite dalle classi sono usate frequentemente in molti differenti kernel; ad esempio la classe gpu_lut_rgb definisce un modo standardizzato per trasferire ad un kernel tutte le informazioni (in questo caso numero di elementi nella lut, numero di indici e dimensioni degli elementi); Vedremo che il trasferimento al kernel viene effettuato attraverso una funzione virtuale Push_kernel, prima dell’esecuzione dello stesso. Basterà quindi, per ciascuna classe derivata riscrivere questa funzione e documentarne la sequenza di parametri generata nel commento.
/** \brief classe prototipo di tutti gli oggetti memoria di opencl */ class AFX_EXT_CLASS gpu_mem_object { public: gpu_mem_object ( ); virtual ~gpu_mem_object ( ); /** assegna l'handler opencl */ void Set_id ( cl_mem _cl_mem ); /** rimanda l'handler opencl */ cl_mem Get_id ( ); void Set_kernel ( class gpu_kernel *kernel ); gpu_kernel *Get_kernel ( ); /** \brief definisce i flag di modalità memoria gpu gestita \details CL_MEM_READ_ONLY.. etc */ bool Set_mem_flags ( cl_mem_flags mode ); /** \brief rimanda i flag di modalità memoria gpu gestita */ cl_mem_flags Get_mem_flags ( ); /** \brief rimanda il puntatore alla memoria allocata nella CPU */ virtual void *Ptr ( ); /** quantità di memoria assegnata al puntatore */ virtual size_t Bytes ( ); /** \brief trasferisce i dati dell'oggetto al kernel \details la funzione è virtuale e deve essere ridefinita per ciascun oggetto derivato il kernel che riceve la strutturà sarà ovviamente scritto in modo da intercettare correttamente i parametri passati per ciascuna classe. Fare riferimento alla descrizione di ciascuna classe derivata per la conoscenza dei parametri trasferiti al kernel \param kernel se ==0 trasferisce è il kernel dove trasferire, altrimenti usa il kernel assegnato \return true se informazione da trasferire correttamente definita */ virtual bool Push_kernel(gpu_kernel *kernel=0); public: _gpu_object_code c_gpu_mem; // codice oggetto memoria assegnato __use_private_struct };
Set_id e Get_id
Le due funzioni permettono di assegnare e ottenere l’handle cl_mem ottenuto da OpenCL quando viene creato un oggetto di memoria (buffer, immagine etc) ; ricordiamo che un oggetto di memoria è sempre creato e assegnato a un gpu_context ; in particolare la funzione Set_Id() è usata internamente dalla gpu_context quando viene richiesta la creazione di un qualunque oggetto gpu_mem_object, pertanto non deve essere normalmente utilizzato dalle classi derivate.
Set_kernel
Definisce il gpu_kernel al quale sarà trasferito l’elemento gpu_mem_object. Vedremo in un prossimo articolo come e dove utilizzare questa funzione.
Il kernel assegnato con questa funzione è quello di default; vedremo che comunque sarà possibile passare l’oggetto gpu_mem_object a più kernel da eseguire in parallelo.
Get_kernel
rimanda la classe gpu_kernel che è stata assegnata di default;
Set_mem_flags e Get_mem_flags
Le due funzioni, gestite internamente al gpu_context definiscono le modalità di gestione dell’oggetto passato al kernel; i valori sono quelli assegnabili al tipo enumerato cl_mem_flags (CL_MEM_READ_ONLY CL_MEM_WRITE_ONLY.. etc). Per una lista completa dei valori dei tipi enumerati di OpenCL leggere qui.
virtual void *Ptr
virtual size_t Bytes
Rimanda la quantità in bytes allocata con il puntatore rimandato da Ptr(); Come la funzione Ptr(), anche la Bytes() può essere usata per accedere, quando necessario, alla memoria di i/o sul kernel; ad esempio si può accedere alla memoria di un oggetto modificato dal kernel (ad esempio la memoria di in oggetto IMAGE passato al kernel utilizzando la gpu_image_2d..)
virtual bool Push_kernel
La funzione, riscritta per ciascuna classe derivata da gpu_mem_object, ha il compito di trasferire le immagini nella coda del kernel; vedremo in seguito un esempio di costruzione di questa funzione; Notare che il kernel di esecuzione passato alla funzione può essere diverso da quello dichiarato di default; in questo caso ci si aspetta che il nuovo kernel (o i nuovi..) sia in parallelo con quello di default;
Il kernel passato per default è stato definito per semplificare la scrittura dei programmi da eseguire su OpenCL: il gpu_context di allocazione dei gpu_mem_object deve necessariamente essere lo stesso per tutti i kernel, quindi verrà ricavato dalla prima assegnazione, ricavandolo dal primo gpu_kernel. Il più delle volte succederà di definire programmi che usano un solo kernel o li usano in modo sequenziale; in questo caso vedremo che questa strategia di scrittura favorisce la concisione, nascondendo molti passaggi e chiamate a funzioni OpenCL che altrimenti dovrebbero comunque essere effettuate.