2016-07-22 8 views
2

Schreiben Grafikkarten normalerweise ihre Ausgabe an einen Platz im Speicher, auf den ich zugreifen kann? Muss ich den Fahrer benutzen? Wenn ja, kann ich OpenGL verwenden?Wie kann ich direkt auf den Ausgang einer Grafikkarte zugreifen?

Ich möchte wissen, ob es möglich ist, die Ausgabe einer VM unter Linux zu "erfassen", die direkten Zugriff auf eine GPU hat und Windows ausführt. Im Idealfall könnte ich direkt aus dem Speicher auf die Ausgabe zugreifen, ohne die GPU zu berühren, da dieser Code auf dem Linux-Host ausgeführt werden könnte.

Die andere Möglichkeit ist, vielleicht einen Windows-Treiber zu schreiben, der die Ausgabe der GPU liest und sie an eine Stelle im Speicher schreibt. Auf der Linux-Seite kann ein Programm diesen Speicher lesen. Dies scheint etwas unmöglich, da ich nicht wirklich sicher bin, wie man einen Prozess auf dem Host bekommt, um Speicher mit einem Prozess auf dem Gast zu teilen.

Ist es möglich, Option 1 zu tun und einfach die Ausgabe aus dem Speicher zu lesen?

+0

Was glauben Sie, ist die "Ausgabe" einer Grafikkarte? Was du glaubst, ist wahrscheinlich falsch. – stark

+0

Ein Rahmen. Ein Haufen Pixel. Grundsätzlich möchte ich, dass Windows und seine Treiber das gesamte Rendering verarbeiten, und ich möchte Zugriff auf die Ausgabe haben. – Hassan

+0

Der Ausgang geht über ein Kabel zu einem Monitor. Wer sagt, dass es irgendwo in der Erinnerung existiert? – stark

Antwort

4

ich keinen Code unter Linux aber in Windows- (Sie es in Emulator ohnehin ausgeführt werden) können Sie WinAPI direkt verwenden, um Leinwand von jedem Fenster zu öffnen oder sogar Desktop aus 3. Partei App. Einige GPU Overlays könnte problematisch sein zu fangen (vor allem DirectX basiert), aber ich hatte keine Probleme mit mir GL/GLSL für jetzt.

Wenn Sie Zugriff auf App Quelle bekam können Sie glReadPixels zur Bildextraktion aus GL verwenden direkt (aber das funktioniert nur für aktuelle GL basierte Rendering).

  1. glReadPixels

    Wie Verwenden erwähnt dies in der gezielten App direkt umgesetzt werden müssen, damit Sie es Quellcode haben müssen oder Ihren Code in der richtigen Ort/Zeit zu injizieren. Ich benutze für screenshoting diesen Code:

    void OpenGLscreen::screenshot(Graphics::TBitmap *bmp) 
        { 
        if (bmp==NULL) return; 
        int *dat=new int[xs*ys],x,y,a,*p; 
        if (dat==NULL) return; 
        bmp->HandleType=bmDIB; 
        bmp->PixelFormat=pf32bit; 
        if ((bmp->Width!=xs)||(bmp->Height!=ys)) bmp->SetSize(xs,ys); 
        if ((bmp->Width==xs)&&(bmp->Height==ys)) 
         { 
         glReadPixels(0,0,xs,ys,GL_BGRA,GL_UNSIGNED_BYTE,dat); 
         glFinish(); 
         for (a=0,y=ys-1;y>=0;y--) 
         for (p=(int*)bmp->ScanLine[y],x=0;x<xs;x++,a++) 
          p[x]=dat[a]; 
         } 
        delete[] dat; 
        } 
    

    wo xs,ys ist OpenGL-Fenster Auflösung, können Sie die ganze bmp Sachen ignorieren (es ist VCL Bitmap I zu speichern Screenshot verwenden) und auch die for ignorieren kann es kopieren Sie einfach das Bild von Puffer zu Bitmap. Also die wichtigen Sachen eben diese:

    int *dat=new int[xs*ys]; // each pixel is 32bit int 
    glReadPixels(0,0,xs,ys,GL_BGRA,GL_UNSIGNED_BYTE,dat); 
    glFinish(); 
    

    Sie müssen diesen Code auszuführen, nachdem die Wiedergabe erfolgt sonst werden Sie unvollendet oder leeren Puffer erhalten. Ich benutze es nach Neuzeichnen/Repaint-Ereignisse. Wie bereits erwähnt, erhalten Sie nur die GL gerenderten Dateien. Wenn Ihre App also GDI + OpenGL kombiniert, ist es besser, den nächsten Ansatz zu verwenden.

  2. WinAPI Ansatz

    auf Leinwand-Bild von jedem Fenster Ich schrieb diese Klasse zu erhalten:

    //--------------------------------------------------------------------------- 
    //--- screen capture ver: 1.00 ---------------------------------------------- 
    //--------------------------------------------------------------------------- 
    class scrcap 
        { 
    public: 
        HWND hnd,hnda; 
        TCanvas *scr; 
        Graphics::TBitmap *bmp; 
        int x0,y0,xs,ys; 
        scrcap() 
         { 
         hnd=NULL; 
         hnda=NULL; 
         scr=new TCanvas(); 
         bmp=new Graphics::TBitmap; 
         #ifdef _mmap_h 
         mmap_new('scrc',scr,sizeof(TCanvas()  )); 
         mmap_new('scrc',bmp,sizeof(Graphics::TBitmap)); 
         #endif 
         if (bmp) 
          { 
          bmp->HandleType=bmDIB; 
          bmp->PixelFormat=pf32bit; 
          } 
         x0=0; y0=0; xs=1; ys=1; 
         hnd=GetDesktopWindow(); 
         } 
        ~scrcap() 
         { 
         #ifdef _mmap_h 
         mmap_del('scrc',scr); 
         mmap_del('scrc',bmp); 
         #endif 
         if (scr) delete scr; scr=NULL; 
         if (bmp) delete bmp; bmp=NULL; 
         } 
        void init(HWND _hnd=NULL) 
         { 
         RECT r; 
         if (scr==NULL) return; 
         if (bmp==NULL) return; 
         bmp->SetSize(1,1); 
         if (!IsWindow(_hnd)) _hnd=hnd; 
         scr->Handle=GetDC(_hnd); 
         hnda=_hnd; 
         resize(); 
         } 
        void resize() 
         { 
         if (!IsWindow(hnda)) return; 
         RECT r; 
    //  GetWindowRect(hnda,&r); 
         GetClientRect(hnda,&r); 
         x0=r.left; xs=r.right-x0; 
         y0=r.top; ys=r.bottom-y0; 
         bmp->SetSize(xs,ys); 
         xs=bmp->Width; 
         ys=bmp->Height; 
         } 
        void capture() 
         { 
         if (scr==NULL) return; 
         if (bmp==NULL) return; 
         bmp->Canvas->CopyRect(Rect(0,0,xs,ys),scr,TRect(x0,y0,x0+xs,y0+ys)); 
         } 
        }; 
    //--------------------------------------------------------------------------- 
    //--------------------------------------------------------------------------- 
    //--------------------------------------------------------------------------- 
    

    Wieder nutzt VCL so umschreiben Bitmap bmp und Leinwand scr zu Ihrem programing Umwelt Stil . Auch Igneore die _mmap_h Brocken von Code sind sie nur zum Debuggen/Tracing von Speicherzeigern im Zusammenhang mit einigen fiesen Compiler-Bug Ich konfrontiert war zu der Zeit schrieb ich dies.

    Die Verwendung ist einfach:

    // globals 
    scrcap cap; 
    // init 
    cap.init(); 
    
    // on screenshot 
    cap.capture(); 
    // here use cap.bmp 
    

    Wenn Sie cap.init() nennen es auf dem gesamten Windows-Desktop sperren wird. Wenn Sie cap.init(window_handle) aufrufen, wird stattdessen ein bestimmtes visuelles Fenster/eine bestimmte Komponente gesperrt. Um Fenstergriff vom 3. App Seite siehe zu erhalten:

    Leider ist es auf SE/RE statt hier auf SE/SO, aber meine Antwort hier Abdeckung dieses Themas gelöscht. Ich benutze dies für die Videoaufnahme ... alle animierten GIFs in meinen Antworten wurden mit diesem Code erstellt.

    Wie Sie sich für DirectX Overlay sehen können mit Media Player Classic (auch Windows-Printscreen-Funktion kann nicht tun, es funktioniert auch richtig: Ein weiteres Beispiel könnte auf der Unterseite dieser Antwort von mir zu sehen). Wie ich geschrieben habe, habe ich damit noch keine Probleme.

    Vorsicht visuelle Sachen WinAPI Anrufe von APP Hauptthread (WNDPROC) sonst schwerwiegende Probleme, die zu zufälligen unabhängigen WinAPI fordert Ausnahmen überall in der App auftreten könnte GENANNT WERDEN MÜSSEN.

+0

Vielen Dank!Ich werde dann wahrscheinlich WinAPI verwenden. Ich kann sehen, dass ich damit irgendwie weiterkommen kann. Ich muss herausfinden, wie ich irgendwie von der Linux-Seite darauf zugreifen kann. Das ist ein anderes Thema. Ich schätze Ihre Hilfe. – Hassan

Verwandte Themen