2015-10-23 31 views
7

Desidero disegnare pixel sul monitor che cambiano frequentemente dopo determinati parametri. PER ESEMPIO. se un pixel rosso e verde si scontrano, entrambi spariranno, ecc.SDL2: Manipolazione pixel veloce

In ogni frame devo manipolare circa 100 - 1000 pixel. Ho un approccio multi-thread qui, che non mi darà 30 FPS (quello che voglio). Attualmente memorizzo un array Pixel nella RAM che contiene tutti i pixel e ha un SDL_Surface. Quando un pixel nell'array cambia, viene modificato anche in Surface e dopo che tutta la manipolazione è stata eseguita viene visualizzato sullo schermo. Il mio approccio attuale è troppo lento e ho riflettuto su come aumentare la velocità.

I miei pensieri attuali sono:

  • Usa OpenGL per fare la manipolazione dei pixel direttamente sulla GPU, che alcuni forum mi dice che questo è il modo più lento rispetto al mio approccio attuale come "questo non è come funziona un GPU "
  • non conservare una matrice di pixel, memorizzare un BMP nella RAM direttamente, manipolare che e quindi spostarlo a un SDL_Surface o SDL_Texture

ci sono altri approcci su come avrei potuto manipolare pixel in una veloce maniera?

+3

Penso che la manipolazione dei pixel in sé non sia la causa dei bassi FPS. Se cambi casualmente ogni pixel sullo schermo (non solo 1K di essi) dovresti ottenere una velocità superiore a 30 FPS. [Qui] (http://stackoverflow.com/a/24170211/833188) dice che dovresti usare 'SDL_Texture' per le prestazioni. Hai provato? Hai profilato il tuo codice comunque? – Sga

+0

Ho un 'SDL_Texture' con' TEXTURE_STREAMING', quindi Lock the Texture, eseguo la manipolazione sull'array di pixel ottenuto e poi lo sblocco una volta terminato. – Nidhoegger

+0

Solo il profiling potrebbe dire dove è il collo di bottiglia – Sga

risposta

6

SDL_CreateTexture() w/SDL_TEXTUREACCESS_STREAMING + SDL_UpdateTexture() sembra funzionare abbastanza bene con il giusto formato di pixel.

Sul mio sistema utilizzando il renderer di default:

Renderer name: direct3d 
Texture formats: 
SDL_PIXELFORMAT_ARGB8888 
SDL_PIXELFORMAT_YV12 
SDL_PIXELFORMAT_IYUV 

(anche se le informazioni opengl è lo stesso :)

Renderer name: opengl 
Texture formats: 
SDL_PIXELFORMAT_ARGB8888 
SDL_PIXELFORMAT_YV12 
SDL_PIXELFORMAT_IYUV 

SDL_PIXELFORMAT_ARGB8888 mi dà ~ 1 ms/telaio:

#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(); 
} 

Assicurati di non aver attivato vsync (forzato nel driver, eseguendo un co espositore, ecc.) oppure tutti gli i tempi del fotogramma saranno di ~ 16 ms (o qualunque sia l'aggiornamento del display impostato su).

+1

Grazie mille! – Nidhoegger

+0

Posso chiedere quale sistema si utilizza? Qui su un i5 con intel HD 2000 ottengo circa 10ms per frame su un i7 2600k con GTX 560 ottengo 3ms. Entrambi eseguono gentoo linux. Grazie! – Nidhoegger

+0

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