DOMANDA Programmare in C C++ con GPU

Pubblicità
In qualunque sistema operativo in cui lo spazio utente è in modalità protetta non puoi accedere direttamente alla memoria video (VRAM) ma devi utilizzare qualche livello intermedio che chiamerà qualche servizio in spazio kernel (API). Ad esempio: Xorg (X11 con xlib), GLUT (OpenGL) ecc. Dato che hai menzionato anche C++, puoi dare uno sguardo ad SFML.
 
In qualunque sistema operativo in cui lo spazio utente è in modalità protetta non puoi accedere direttamente alla memoria video (VRAM) ma devi utilizzare qualche livello intermedio che chiamerà qualche servizio in spazio kernel (API). Ad esempio: Xorg (X11 con xlib), GLUT (OpenGL) ecc. Dato che hai menzionato anche C++, puoi dare uno sguardo ad SFML.
dunque.. qunque... ho trovato questa bellissima guida :
Linux Assembly Tutorial - Step-by-Step Guide
e sono riuscito ad istallare nasm dal software manager di linux mint.

ho compilato e linkato il programma hello_kitty.asm e .... funziona :luxhello:

a questo punto se posso utilizzare gli interrupt provo a "scassare" direttamente la vga attraverso l'int 13h :asd:
 
dunque.. qunque... ho trovato questa bellissima guida :
Linux Assembly Tutorial - Step-by-Step Guide
e sono riuscito ad istallare nasm dal software manager di linux mint.

ho compilato e linkato il programma hello_kitty.asm e .... funziona :luxhello:

a questo punto se posso utilizzare gli interrupt provo a "scassare" direttamente la vga attraverso l'int 13h :asd:
Bello :ok:
Immagino con DosBox o quale altro?
 
Bello :ok:
Immagino con DosBox o quale altro?
Insomma è tutto da sperimentare... :asd:
se il linux mi dà accesso alle routines del bios dovrebbe essere quasi possibile.

Comunque sono riuscito ad istallare il freeglut3 openGL
https://it.wikipedia.org/wiki/Freeglut

Ecco un breve promemoria per far funzionare il programma :

Solo da linux mint17.1 su hard disk .... no dvd-rom live !

Prima di tutto bisogna andare nel menù ed avviare il Software manager con internet connesso,
quindi bisogna scaricare il tools freeglut3-dev

poi bisogna creare un file testo sul Desktop con l'editor e nominarlo filec.c
e ricopirare con il copia incolla il programma del sito :

https://www.opengl.org/wiki/Programming_OpenGL_in_Linux:_GLX_and_Xlib

modificando gli include con il percorso degli header.h di openGL

#include </usr/include/X11/X.h>
#include </usr/include/X11/Xlib.h>
#include </usr/include/GL/gl.h>
#include </usr/include/GL/glx.h>
#include </usr/include/GL/glu.h>

poi si apre il Terminal di comando e si compila con :

$ gcc -o filec filec.c -lX11 -lGL -lGLU

eseguire con :

$ ./filec

funziona ! :luxhello:

- - - Updated - - -

comunque mi sembra troppo complesso per scrivere un paio di pixel. :sisi:

- - - Updated - - -

Riporto qui il programma casomai il sito del link si estingue o non e' raggiungibile :sisi:

Codice:
// -- Written in C -- //

#include<stdio.h>
#include<stdlib.h>
#include<X11/X.h>
#include<X11/Xlib.h>
#include<GL/gl.h>
#include<GL/glx.h>
#include<GL/glu.h>

Display                 *dpy;
Window                  root;
GLint                   att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
XVisualInfo             *vi;
Colormap                cmap;
XSetWindowAttributes    swa;
Window                  win;
GLXContext              glc;
XWindowAttributes       gwa;
XEvent                  xev;

void DrawAQuad() {
 glClearColor(1.0, 1.0, 1.0, 1.0);
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 glOrtho(-1., 1., -1., 1., 1., 20.);

 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluLookAt(0., 0., 10., 0., 0., 0., 0., 1., 0.);

 glBegin(GL_QUADS);
  glColor3f(1., 0., 0.); glVertex3f(-.75, -.75, 0.);
  glColor3f(0., 1., 0.); glVertex3f( .75, -.75, 0.);
  glColor3f(0., 0., 1.); glVertex3f( .75,  .75, 0.);
  glColor3f(1., 1., 0.); glVertex3f(-.75,  .75, 0.);
 glEnd();
} 
 
int main(int argc, char *argv[]) {

 dpy = XOpenDisplay(NULL);
 
 if(dpy == NULL) {
 	printf("\n\tcannot connect to X server\n\n");
        exit(0);
 }
        
 root = DefaultRootWindow(dpy);

 vi = glXChooseVisual(dpy, 0, att);

 if(vi == NULL) {
	printf("\n\tno appropriate visual found\n\n");
        exit(0);
 } 
 else {
	printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */
 }


 cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);

 swa.colormap = cmap;
 swa.event_mask = ExposureMask | KeyPressMask;
 
 win = XCreateWindow(dpy, root, 0, 0, 600, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);

 XMapWindow(dpy, win);
 XStoreName(dpy, win, "VERY SIMPLE APPLICATION");
 
 glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
 glXMakeCurrent(dpy, win, glc);
 
 glEnable(GL_DEPTH_TEST); 
 
 while(1) {
 	XNextEvent(dpy, &xev);
        
        if(xev.type == Expose) {
        	XGetWindowAttributes(dpy, win, &gwa);
                glViewport(0, 0, gwa.width, gwa.height);
        	DrawAQuad(); 
                glXSwapBuffers(dpy, win);
        }
                
	else if(xev.type == KeyPress) {
        	glXMakeCurrent(dpy, None, NULL);
 		glXDestroyContext(dpy, glc);
 		XDestroyWindow(dpy, win);
 		XCloseDisplay(dpy);
 		exit(0);
        }
    } /* this closes while(1) { */
} /* this is the } which closes int main(int argc, char *argv[]) { */
 
Ultima modifica:
Insomma è tutto da sperimentare... :asd:
se il linux mi dà accesso alle routines del bios dovrebbe essere quasi possibile.
Le routine del BIOS non vengono più utilizzate né tantomeno rese accessibili nei SO moderni forse da decenni per diverse ragioni; l'unico interrupt che Linux gestisce ancora è lo 0x80, ad esempio
Codice:
movq  rax, 1
xorq  rbx, rbx
int 80h
che chiama sys/exit con 0. È comunque caldamente sconsigliato contrariamente a sysenter (AMD) o syscall (Intel). Sempre che non parliamo di emulatori tipo DosBox per MS-DOS.

comunque mi sembra troppo complesso per scrivere un paio di pixel.
Anche a me, ma non saprei dirti cosa migliorare... Considera, comunque, che si tratta di API che dialogano direttamente col server grafico (nel caso di xlib) e/o driver video (OpenGL). Infatti tipicamente vuoi scrivere librerie sopra questi per semplificare il lavoro, come Qt e GTK+.
 
Le routine del BIOS non vengono più utilizzate né tantomeno rese accessibili nei SO moderni forse da decenni per diverse ragioni; l'unico interrupt che Linux gestisce ancora è lo 0x80, ad esempio
Codice:
movq  rax, 1
xorq  rbx, rbx
int 80h
che chiama sys/exit con 0. È comunque caldamente sconsigliato contrariamente a sysenter (AMD) o syscall (Intel). Sempre che non parliamo di emulatori tipo DosBox per MS-DOS.
Ma le routine del bios (non uefi) devono stare da qualche parte o no ? :grat:
mi sembra che l'int 10h VGA e' residente nella flashrom.
https://en.wikipedia.org/wiki/INT_10H

effettivamente se lo sono chiesto in molti :asd:
Linux Assembler int 10h - For Beginners - GameDev.net
https://forums.freebsd.org/threads/drawing-a-single-pixel-without-x.40462/
assembly - Interrupt 10h not working - Stack Overflow

comunque ho capito che bisogna passare per le "scatole cinesi" :ciaociao:

Anche a me, ma non saprei dirti cosa migliorare... Considera, comunque, che si tratta di API che dialogano direttamente col server grafico (nel caso di xlib) e/o driver video (OpenGL). Infatti tipicamente vuoi scrivere librerie sopra questi per semplificare il lavoro, come Qt e GTK+.

In pratica il sistema operativo si riserva l'accesso della memoria video,
e quindi anche se istallo freeBSD non risolvo nulla. :ciaociao:

- - - Updated - - -

Ma potrei fare lo switch da modo protetto a modo reale in asm utilizzando CR0 ? :grat:

Transition from Protected Mode to Real Mode
https://en.wikipedia.org/wiki/Protected_mode
https://en.wikipedia.org/wiki/Control_register

Mannaggia a wikipedia, quando scarico il pdf mi si "mangia" le tabelle dei flags del CR0 complimenti ! :asd:

Registro CR0

Codice:
[TABLE="class: wikitable"]
[TR]
[TD]31[/TD]
[TD]PG[/TD]
[TD]Paging[/TD]
[TD]If 1, enable paging and use the CR3 register, else disable paging[/TD]
[/TR]
[TR]
[TD]30[/TD]
[TD]CD[/TD]
[TD][URL="https://en.wikipedia.org/wiki/CPU_cache"]Cache[/URL] disable[/TD]
[TD]Globally enables/disable the memory cache[/TD]
[/TR]
[TR]
[TD]29[/TD]
[TD]NW[/TD]
[TD]Not-write through[/TD]
[TD]Globally enables/disable write-through caching[/TD]
[/TR]
[TR]
[TD]18[/TD]
[TD]AM[/TD]
[TD]Alignment mask[/TD]
[TD]Alignment check enabled if AM set, AC flag (in [URL="https://en.wikipedia.org/wiki/FLAGS_register_%28computing%29"]EFLAGS[/URL] register) set, and privilege level is 3[/TD]
[/TR]
[TR]
[TD]16[/TD]
[TD]WP[/TD]
[TD]Write protect[/TD]
[TD]When set, the CPU can't write to read-only pages when privilege level is 0[/TD]
[/TR]
[TR]
[TD]5[/TD]
[TD]NE[/TD]
[TD]Numeric error[/TD]
[TD]Enable internal [URL="https://en.wikipedia.org/wiki/X87"]x87[/URL] floating point error reporting when set, else enables PC style x87 error detection[/TD]
[/TR]
[TR]
[TD]4[/TD]
[TD]ET[/TD]
[TD]Extension type[/TD]
[TD]On the 386, it allowed to specify whether the external math coprocessor was an [URL="https://en.wikipedia.org/wiki/80287"]80287[/URL] or [URL="https://en.wikipedia.org/wiki/80387"]80387[/URL][/TD]
[/TR]
[TR]
[TD]3[/TD]
[TD]TS[/TD]
[TD]Task switched[/TD]
[TD]Allows saving x87 task context upon a task switch only after x87 instruction used[/TD]
[/TR]
[TR]
[TD]2[/TD]
[TD]EM[/TD]
[TD]Emulation[/TD]
[TD]If set, no x87 [URL="https://en.wikipedia.org/wiki/Floating_point_unit"]floating point unit[/URL] present, if clear, x87 FPU present[/TD]
[/TR]
[TR]
[TD]1[/TD]
[TD]MP[/TD]
[TD]Monitor co-processor[/TD]
[TD]Controls interaction of WAIT/FWAIT instructions with TS flag in CR0[/TD]
[/TR]
[TR]
[TD]0[/TD]
[TD]PE[/TD]
[TD][B]Protected Mode Enable[/B][/TD]
[TD]If 1, system is in [URL="https://en.wikipedia.org/wiki/Protected_mode"]protected mode[/URL], else system is in [URL="https://en.wikipedia.org/wiki/Real_mode"]real mode[/URL][/TD]
[/TR]
[/TABLE]


Modifica del registro CR0 in asm.

Codice:
; set PE bit
mov eax, cr0
or eax, 1
[B]mov cr0, eax[/B]

; far jump (cs = selector of code segment)
jmp cs:@pm

@pm:
; Now we are in PM.

- - - Updated - - -

Oppure provo a scrivere direttamente sulle porte I/O del DAC della VGA ? :grat:
forse forse le porte di I/O restano accessibili anche in modo protetto, e anche da linux C ? :grat:

( tentare di "scassinare" la vga dai registri I/O del DAC non ha prezzo :asd: )

- - - Updated - - -

Proviamo ! :ciaociao:
 
Ultima modifica:
Mmm, interessante. A quanto vedo nell'iniziazione di Linux per x86, disponibile qui, al registro cr0 viene effettivamente abilitato il primo bit e viene fatto il jump in protected mode:
Codice:
       movl    %cr0, %edx
       orb     $X86_CR0_PE, %dl        # Protected mode
       movl    %edx, %cr0

dove X86_CR0_PE è una macro che espande ad un'altra macro che shifta di N bit in base ad un certo valore. In questo caso espande a 1 << 0, ossia 1, proprio il bit riportato da Wikipedia. Ho scritto un modulo per Linux che riporta lo status di cr0:
Codice:
#include <linux/module.h>   
#include <linux/kernel.h>   
#include <linux/string.h>


MODULE_LICENSE("GPL");


static int  kernel_init(void)
{
    unsigned long mode = 0; 
    __asm__ __volatile__ (
                            "movq %%cr0, %%rax \n\t"
                            "movq %%rax, %0    \n\t"
                            : "=a"(mode)
                          );


    char buf[64];
    snprintf(buf, sizeof(buf), "%lu", mode);


    printk(KERN_INFO "rc0 = %lu\n", buf);
    if ( mode & 1 )
        printk(KERN_INFO "Protected mode enabled.\n");
    else 
        printk(KERN_INFO "Protected mode disabled.\n");


    return 0;
}


static void kernel_exit(void)
{}


module_init(kernel_init);
module_exit(kernel_exit);
e sembra funzionare correttamente. Immaginavo fosse necessario entrare in kernel space ma ho comunque provato ad eseguirlo in userspace, fallendo con un general protection fault.
Non ho una VM, quindi preferisco evitare di impostarlo a 0 e vedere cosa succede perché suppongo farebbe crashare il sistema...

Anche perché, una volta entrato, sai cosa dovrai fare?
Sui passaggi effettuati nel bootstrap x86 da Linux
 
Ultima modifica:
dunque.. sembra pero' che le "nuove" VESA includono anche il modo protetto :
https://en.wikipedia.org/wiki/VESA_BIOS_Extensions
Drawing In Protected Mode - OSDev Wiki
FreeVGA Project Home - Hardware level VGA and SVGA programming info
insomma programmare la VGA era come programmare qualsiasi controller ...
si impostavano i registri mappati nello spazio I/O e si Scrivevano i dati nella memoria video.
ma con l'evoluzione siamo riusciti a complicare anche un sistema banale. :asd:
Insomma work in progress..
faro' altri esperimenti, se non va in crash tutto il sistema :sisi:
basta solo che non vado a scrivere dei dati nel VRM della cpu... :ciaociao:

- - - Updated - - -

comunque al limite senza che sto ad impazzire dietro a delle informazioni tanto banali quanto top secret,
posso utilizzare le routines freeglut che funzionano bene e mi ricavo delle funzioni simili al turbo C
(mi basta solo la finestra grafica in alta risoluzione e il putpixel.)
cosi posso tornare a studiare le mie belle equazioni :veach: senza perdere tempo. :sisi:

- - - Updated - - -

magari provo ad istallare anche il FreeBSD 10.1 che ha la libreria vgl
https://www.freebsd.org/cgi/man.cgi?query=vgl
ma devo imparare ad utilizzare il compilatore.
non dovrebbe essere troppo diverso da linux, ma non si sà mai. :grat:
 
Se SFML non ti dispiace
Codice:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics/Color.hpp>

template <class Callable>
void graph(Callable f, sf::Image &ref)
{
    const int points = 20;
   
    for (int x = 0; x < points; ++x) {
          ref.setPixel( x, f(x), sf::Color::Red);      
    }
    
}


int line(int x)
{
      return 2*x;
}


int parabola(int x)
{
    return  x * x;
}


int main()
{
     sf::RenderWindow mainWindow{ {1280, 720}, "Test"}; // Finestra principale   
     
     sf::Sprite sprite;
     sf::Texture texture;
     sf::Image image;

     image.create(1280, 720, sf::Color::Black); // 1280x720 con sfondo nero

     graph(line, image); // disegno la funzione
     texture.loadFromImage(image); // carico la texture
     sprite.setTexture(texture); // metto la texture in una sprite, che può essere "disegnata" nella finestra


     sf::Event event;
     while ( mainWindow.isOpen() ) {
             while ( mainWindow.pollEvent(event) ) {
                     if ( event.type == sf::Event::Closed) {
                             mainWindow.close();
                     }
             }
             
             mainWindow.draw(sprite);        
             mainWindow.display();
     }

}
"funziona", ma non ho preso in considerazione l'origine del grafico che è in alto a sinistra, non al centro. Inoltre, il numero di punti è arbitrario che quindi non controlla se va fuori dalle dimensioni del grafico ( tipo P(1, 1300) )
 
Ultima modifica:
Se SFML non ti dispiace
Codice:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics/Color.hpp>

template <class Callable>
void graph(Callable f, sf::Image &ref)
{
    const int points = 20;
   
    for (int x = 0; x < points; ++x) {
          ref.setPixel( x, f(x), sf::Color::Red);      
    }
    
}


int line(int x)
{
      return 2*x;
}


int parabola(int x)
{
    return  x * x;
}


int main()
{
     sf::RenderWindow mainWindow{ {1280, 720}, "Test"}; // Finestra principale   
     
     sf::Sprite sprite;
     sf::Texture texture;
     sf::Image image;

     image.create(1280, 720, sf::Color::Black); // 1280x720 con sfondo nero

     graph(line, image); // disegno la funzione
     texture.loadFromImage(image); // carico la texture
     sprite.setTexture(texture); // metto la texture in una sprite, che può essere "disegnata" nella finestra


     sf::Event event;
     while ( mainWindow.isOpen() ) {
             while ( mainWindow.pollEvent(event) ) {
                     if ( event.type == sf::Event::Closed) {
                             mainWindow.close();
                     }
             }
             
             mainWindow.draw(sprite);        
             mainWindow.display();
     }

}
"funziona", ma non ho preso in considerazione l'origine del grafico che è in alto a sinistra, non al centro. Inoltre, il numero di punti è arbitrario che quindi non controlla se va fuori dalle dimensioni del grafico ( tipo P(1, 1300) )
ottimo, complimenti ! :) da considerare anche questo :sisi:
pero' alla fine credo che utilizzero' freeBSD (prima pero' devo trovare un hard disk libero)
che senza aggiungere nulla, ha le librerie vgl e il compilatore cc incluso nella iso.
Per ora sono nella fase degli esperimenti, perche' se il Linux ha i driver aggiornati,
questo gli permette di interagire con la GPU per ottenere delle velocita' davvero elevate,
praticamente impossibili con i modelli standard. :sisi:
mentre invece magari freeBSD utilizza i driver generici molto piu lenti. :look:
 
ma dovrei visualizzare alcuni grafici di equazzioni differenziabili,
senza dover ricorrere a grossi programmi tipo mathemathica, mathlabh e simili.
(che per quanto utili e belli, sono - in alcuni casi - abbastanza lenti.)

Sono curioso, mi puoi fare un esempio in cui MATLAB e simili sono talmente lenti da essere ingestibili? Io personalmente preferisco python con numpy e matplotlib ma questa è un'altra storia
 
Sono curioso, mi puoi fare un esempio in cui MATLAB e simili sono talmente lenti da essere ingestibili? Io personalmente preferisco python con numpy e matplotlib ma questa è un'altra storia
Matlab e il resto sono "linguaggi" iterpretati ad alto livello, un compilato C e' 1000 volte piu' efficente.
ma anche molto piu' flessibile pero' bisogna scriversi le librerie matematiche.
di esempi se ne possono fare centinaia, dalle rotazioni tridimensionali alla variazione dei parametri dell' equazione.
io utilizzerei pure il C del vecchio ms-dos ma il real mode mi limita ad 1MByte che e' davvero troppo poco rispetto ai quasi 4GBye del linux 32bit.
il malloc delle strutture dinamiche della breadth recursion succhiano tanta memoria. :grat:
 
Lo so bene che sono interpretati, ma non è questo il punto. Un conto è eseguire i conti, un altro è generare dei grafici...fossi al posto tuo effettuetei i conti in C, fortran o vattelapesca, salverei i dati in HDF 5 e poi con un più semplice linguaggio interpretato leggerei da hdf5 per generare i grafici senza grandi sbattimenti.

OK che sono più lenti, ma a meno che tu non debba generare numeri spropositati di grafici direi che fai prima così... Tutto il tempo che guadagni a far andare il codice con C sembra che tu lo stia perdendo per disegnare due pixel a schermo.

Ultima cosa, non ho proprio capito in che senso "bisogna scriversi le librerie matematiche": LAPACK c'è, Intel MKL c'è...
 
Lo so bene che sono interpretati, ma non è questo il punto. Un conto è eseguire i conti, un altro è generare dei grafici...fossi al posto tuo effettuetei i conti in C, fortran o vattelapesca, salverei i dati in HDF 5 e poi con un più semplice linguaggio interpretato leggerei da hdf5 per generare i grafici senza grandi sbattimenti.

OK che sono più lenti, ma a meno che tu non debba generare numeri spropositati di grafici direi che fai prima così... Tutto il tempo che guadagni a far andare il codice con C sembra che tu lo stia perdendo per disegnare due pixel a schermo.
Anch'io avevo pensato di risolvere generando un file bitmap da visualizzare successivamente.
Il problema pero' e' che non posso vedere l'evoluzione del sistema, e in caso di necessita' fermare i calcoli.
insomma avrei bisogno di una visualizzazione real-time.
per il resto, in molte condizioni limite i sistemi precompilati (talvolta) tracciano per interpolazione
generando artefatti praticamente inutili.

Ultima cosa, non ho proprio capito in che senso "bisogna scriversi le librerie matematiche": LAPACK c'è, Intel MKL c'è...
e il bello e' proprio questo, la libreria scritta da me' rispecchia le mie esigenze,
e posso aggiungere delle funzioni che non esistono nello standard.
oppure posso eliminare molte parti inutili e caricare solo l'essenziale.

- - - Updated - - -

ecco un bell' esempio che si puo' simulare al PC
 
Ultima modifica da un moderatore:
Pubblicità
Pubblicità
Indietro
Top