2015-10-23 10 views
7

Ich möchte Pixel auf dem Monitor zeichnen, die sich nach bestimmten Parametern häufig ändern. Z.B. Wenn ein rotes und ein grünes Pixel kollidieren, würden beide verschwinden usw.SDL2: Schnelle Pixel Manipulation

In jedem Frame muss ich etwa 100 - 1000 Pixel manipulieren. Ich habe hier einen Ansatz mit mehreren Threads, der mir 30FPS (was ich will) nicht geben wird. Momentan speichere ich ein Pixel-Array im RAM, das alle Pixel enthält und eine SDL_Surface hat. Wenn sich ein Pixel im Array ändert, wird es auch in der Oberfläche geändert und wird dann, nachdem alle Manipulationen durchgeführt wurden, auf den Bildschirm geblendet. Mein aktueller Ansatz ist zu langsam und ich habe ein wenig darüber nachgedacht, wie ich die Geschwindigkeit erhöhen könnte.

Meine aktuellen Gedanken sind:

  • Verwenden OpenGL die Bearbeitung von Pixeln direkt auf der GPU zu tun, die einige Foren mir sagt, dass dies Art und Weise langsamer als meine derzeitige Ansatz als „dies nicht der Fall, wie eine GPU Werke "
  • sie eine Pixelanordnung nicht speichern, speichern sie eine BMP in RAM direkt, manipulieren, dass es dann zu einem SDL_Surface oder SDL_Texture bewegen

es andere Ansätze, wie ich Pixel in einem schnell manipulieren könnte Weise?

+3

Ich denke, dass Pixel Manipulation selbst ist nicht die Ursache für niedrige FPS. Wenn Sie zufällig jedes Pixel auf dem Bildschirm ändern (nicht nur 1K davon), sollten Sie weit über 30FPS kommen. [Hier] (http://stackoverflow.com/a/24170211/833188) sagt, dass Sie 'SDL_Texture' für die Leistung verwenden sollten. Hast du das probiert? Hast du deinen Code trotzdem profiliert? – Sga

+0

Ich habe eine 'SDL_Texture' mit' TEXTURE_STREAMING', dann die Textur sperren, die Manipulation an dem erhaltenen Pixel-Array vornehmen und sie dann entriegeln, wenn sie fertig ist. – Nidhoegger

+0

Nur Profiling könnte sagen, wo der Flaschenhals ist – Sga

Antwort

6

SDL_CreateTexture() w/SDL_TEXTUREACCESS_STREAMING + SDL_UpdateTexture() scheint mit dem richtigen Pixelformat gut genug zu funktionieren.

Auf meinem System den Standard-Renderer:

Renderer name: direct3d 
Texture formats: 
SDL_PIXELFORMAT_ARGB8888 
SDL_PIXELFORMAT_YV12 
SDL_PIXELFORMAT_IYUV 

(obwohl die opengl info ist die gleiche :)

Renderer name: opengl 
Texture formats: 
SDL_PIXELFORMAT_ARGB8888 
SDL_PIXELFORMAT_YV12 
SDL_PIXELFORMAT_IYUV 

SDL_PIXELFORMAT_ARGB8888 gibt mir ~ 1 ms/Rahmen:

#include <SDL2/SDL.h> 
#include <SDL2/SDL_render.h> 
#include <iostream> 
#include <vector> 

using namespace std; 

int main(int argc, char** argv) 
{ 
    SDL_Init(SDL_INIT_EVERYTHING); 
    atexit(SDL_Quit); 

    SDL_Window* window = SDL_CreateWindow 
     (
     "SDL2", 
     SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
     600, 600, 
     SDL_WINDOW_SHOWN 
     ); 

    SDL_Renderer* renderer = SDL_CreateRenderer 
     (
     window, 
     -1, 
     SDL_RENDERER_ACCELERATED 
     ); 

    SDL_RendererInfo info; 
    SDL_GetRendererInfo(renderer, &info); 
    cout << "Renderer name: " << info.name << endl; 
    cout << "Texture formats: " << endl; 
    for(Uint32 i = 0; i < info.num_texture_formats; i++) 
    { 
     cout << SDL_GetPixelFormatName(info.texture_formats[i]) << endl; 
    } 

    const unsigned int texWidth = 1024; 
    const unsigned int texHeight = 1024; 
    SDL_Texture* texture = SDL_CreateTexture 
     (
     renderer, 
     SDL_PIXELFORMAT_ARGB8888, 
     SDL_TEXTUREACCESS_STREAMING, 
     texWidth, texHeight 
     ); 

    vector< unsigned char > pixels(texWidth * texHeight * 4, 0); 

    SDL_Event event; 
    bool running = true; 
    while(running) 
    { 
     const Uint64 start = SDL_GetPerformanceCounter(); 

     SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); 
     SDL_RenderClear(renderer); 

     while(SDL_PollEvent(&event)) 
     { 
      if((SDL_QUIT == event.type) || 
       (SDL_KEYDOWN == event.type && SDL_SCANCODE_ESCAPE == event.key.keysym.scancode)) 
      { 
       running = false; 
       break; 
      } 
     } 

     // splat down some random pixels 
     for(unsigned int i = 0; i < 1000; i++) 
     { 
      const unsigned int x = rand() % texWidth; 
      const unsigned int y = rand() % texHeight; 

      const unsigned int offset = (texWidth * 4 * y) + x * 4; 
      pixels[ offset + 0 ] = rand() % 256;  // b 
      pixels[ offset + 1 ] = rand() % 256;  // g 
      pixels[ offset + 2 ] = rand() % 256;  // r 
      pixels[ offset + 3 ] = SDL_ALPHA_OPAQUE; // a 
     } 

     //unsigned char* lockedPixels; 
     //int pitch; 
     //SDL_LockTexture 
     // (
     // texture, 
     // NULL, 
     // reinterpret_cast< void** >(&lockedPixels), 
     // &pitch 
     // ); 
     //std::copy(pixels.begin(), pixels.end(), lockedPixels); 
     //SDL_UnlockTexture(texture); 

     SDL_UpdateTexture 
      (
      texture, 
      NULL, 
      &pixels[0], 
      texWidth * 4 
      ); 

     SDL_RenderCopy(renderer, texture, NULL, NULL); 
     SDL_RenderPresent(renderer); 

     const Uint64 end = SDL_GetPerformanceCounter(); 
     const static Uint64 freq = SDL_GetPerformanceFrequency(); 
     const double seconds = (end - start)/static_cast<double>(freq); 
     cout << "Frame time: " << seconds * 1000.0 << "ms" << endl; 
    } 

    SDL_DestroyRenderer(renderer); 
    SDL_DestroyWindow(window); 
    SDL_Quit(); 
} 

Stellen Sie sicher, dass vsync nicht aktiviert ist (im Treiber erzwungen, eine Co ausgeführt wird) mpositor, etc.) oder sonst alle Ihre Rahmen Zeiten werden ~ 16ms (oder was auch immer Ihre Bildschirmaktualisierung eingestellt ist).

+1

Vielen Dank! – Nidhoegger

+0

Darf ich fragen, welches System Sie verwenden? Hier auf einem i5 mit Intel HD 2000 bekomme ich ca. 10ms pro Frame auf einem i7 2600k mit GTX 560 bekomme ich 3ms. Beide laufen Gentoo Linux. Danke! – Nidhoegger

+0

@Nidhoegger: i7 2600 @ 3,4 GHz, Win7 mit einem AMD FirePro V4800. – genpfault